mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-01 18:52:02 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: - a new driver for the Azoteq IQS269A capacitive touch controller - a new driver for the Cypress CY8CTMA140 touchscreen - updates to Elan and ft5x06 touchscreen drivers - assorted driver fixes - msm-vibrator has been removed as we have a more generic solution * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (28 commits) Input: adi - work around module name confict Input: iqs269a - add missing I2C dependency Input: elants - refactor elants_i2c_execute_command() Input: elants - override touchscreen info with DT properties Input: elants - remove unused axes Input: add support for Azoteq IQS269A dt-bindings: input: Add bindings for Azoteq IQS269A Input: imx_sc_key - use devm_add_action_or_reset() to handle all cleanups Input: remove msm-vibrator driver dt-bindings: Input: remove msm-vibrator Input: elants_i2c - provide an attribute to show calibration count Input: introduce input_mt_report_slot_inactive() dt-bindings: input: touchscreen: elants_i2c: convert to YAML Input: add driver for the Cypress CY8CTMA140 touchscreen dt-bindings: touchscreen: Add CY8CTMA140 bindings Input: edt-ft5x06 - prefer asynchronous probe Input: edt-ft5x06 - improve power management operations Input: edt-ft5x06 - move parameter restore into helper Input: edt-ft5x06 - fix get_default register write access Input: atkbd - receive and use physcode->keycode mapping from FW ...
This commit is contained in:
commit
49f13b0921
@ -1,34 +0,0 @@
|
|||||||
Elantech I2C Touchscreen
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: must be "elan,ekth3500".
|
|
||||||
- reg: I2C address of the chip.
|
|
||||||
- interrupts: interrupt to which the chip is connected (see interrupt
|
|
||||||
binding[0]).
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- wakeup-source: touchscreen can be used as a wakeup source.
|
|
||||||
- pinctrl-names: should be "default" (see pinctrl binding [1]).
|
|
||||||
- pinctrl-0: a phandle pointing to the pin settings for the device (see
|
|
||||||
pinctrl binding [1]).
|
|
||||||
- reset-gpios: reset gpio the chip is connected to.
|
|
||||||
- vcc33-supply: a phandle for the regulator supplying 3.3V power.
|
|
||||||
- vccio-supply: a phandle for the regulator supplying IO power.
|
|
||||||
|
|
||||||
[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
|
||||||
[1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
|
|
||||||
|
|
||||||
Example:
|
|
||||||
&i2c1 {
|
|
||||||
/* ... */
|
|
||||||
|
|
||||||
touchscreen@10 {
|
|
||||||
compatible = "elan,ekth3500";
|
|
||||||
reg = <0x10>;
|
|
||||||
interrupt-parent = <&gpio4>;
|
|
||||||
interrupts = <0x0 IRQ_TYPE_EDGE_FALLING>;
|
|
||||||
wakeup-source;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ... */
|
|
||||||
};
|
|
581
Documentation/devicetree/bindings/input/iqs269a.yaml
Normal file
581
Documentation/devicetree/bindings/input/iqs269a.yaml
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/input/iqs269a.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Azoteq IQS269A Capacitive Touch Controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Jeff LaBundy <jeff@labundy.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
The Azoteq IQS269A is an 8-channel capacitive touch controller that features
|
||||||
|
additional Hall-effect and inductive sensing capabilities.
|
||||||
|
|
||||||
|
Link to datasheet: https://www.azoteq.com/
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: azoteq,iqs269a
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#address-cells":
|
||||||
|
const: 1
|
||||||
|
|
||||||
|
"#size-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
azoteq,hall-enable:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Enables Hall-effect sensing on channels 6 and 7. In this case, keycodes
|
||||||
|
assigned to channel 6 are ignored and keycodes assigned to channel 7 are
|
||||||
|
interpreted as switch codes. Refer to the datasheet for requirements im-
|
||||||
|
posed on channels 6 and 7 by Hall-effect sensing.
|
||||||
|
|
||||||
|
azoteq,suspend-mode:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 0
|
||||||
|
description: |
|
||||||
|
Specifies the power mode during suspend as follows:
|
||||||
|
0: Automatic (same as normal runtime, i.e. suspend/resume disabled)
|
||||||
|
1: Low power (all sensing at a reduced reporting rate)
|
||||||
|
2: Ultra-low power (channel 0 proximity sensing)
|
||||||
|
3: Halt (no sensing)
|
||||||
|
|
||||||
|
azoteq,clk-div:
|
||||||
|
type: boolean
|
||||||
|
description: Divides the device's core clock by a factor of 4.
|
||||||
|
|
||||||
|
azoteq,ulp-update:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 7
|
||||||
|
default: 3
|
||||||
|
description: Specifies the ultra-low-power mode update rate.
|
||||||
|
|
||||||
|
azoteq,reseed-offset:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Applies an 8-count offset to all long-term averages upon either ATI or
|
||||||
|
reseed events.
|
||||||
|
|
||||||
|
azoteq,filt-str-lp-lta:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 0
|
||||||
|
description:
|
||||||
|
Specifies the long-term average filter strength during low-power mode.
|
||||||
|
|
||||||
|
azoteq,filt-str-lp-cnt:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 0
|
||||||
|
description:
|
||||||
|
Specifies the raw count filter strength during low-power mode.
|
||||||
|
|
||||||
|
azoteq,filt-str-np-lta:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 0
|
||||||
|
description:
|
||||||
|
Specifies the long-term average filter strength during normal-power mode.
|
||||||
|
|
||||||
|
azoteq,filt-str-np-cnt:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 0
|
||||||
|
description:
|
||||||
|
Specifies the raw count filter strength during normal-power mode.
|
||||||
|
|
||||||
|
azoteq,rate-np-ms:
|
||||||
|
minimum: 0
|
||||||
|
maximum: 255
|
||||||
|
default: 16
|
||||||
|
description: Specifies the report rate (in ms) during normal-power mode.
|
||||||
|
|
||||||
|
azoteq,rate-lp-ms:
|
||||||
|
minimum: 0
|
||||||
|
maximum: 255
|
||||||
|
default: 160
|
||||||
|
description: Specifies the report rate (in ms) during low-power mode.
|
||||||
|
|
||||||
|
azoteq,rate-ulp-ms:
|
||||||
|
multipleOf: 16
|
||||||
|
minimum: 0
|
||||||
|
maximum: 4080
|
||||||
|
default: 160
|
||||||
|
description: Specifies the report rate (in ms) during ultra-low-power mode.
|
||||||
|
|
||||||
|
azoteq,timeout-pwr-ms:
|
||||||
|
multipleOf: 512
|
||||||
|
minimum: 0
|
||||||
|
maximum: 130560
|
||||||
|
default: 2560
|
||||||
|
description:
|
||||||
|
Specifies the length of time (in ms) to wait for an event during normal-
|
||||||
|
power mode before transitioning to low-power mode.
|
||||||
|
|
||||||
|
azoteq,timeout-lta-ms:
|
||||||
|
multipleOf: 512
|
||||||
|
minimum: 0
|
||||||
|
maximum: 130560
|
||||||
|
default: 32768
|
||||||
|
description:
|
||||||
|
Specifies the length of time (in ms) to wait before resetting the long-
|
||||||
|
term average of all channels. Specify the maximum timeout to disable it
|
||||||
|
altogether.
|
||||||
|
|
||||||
|
azoteq,ati-band-disable:
|
||||||
|
type: boolean
|
||||||
|
description: Disables the ATI band check.
|
||||||
|
|
||||||
|
azoteq,ati-lp-only:
|
||||||
|
type: boolean
|
||||||
|
description: Limits automatic ATI to low-power mode.
|
||||||
|
|
||||||
|
azoteq,ati-band-tighten:
|
||||||
|
type: boolean
|
||||||
|
description: Tightens the ATI band from 1/8 to 1/16 of the desired target.
|
||||||
|
|
||||||
|
azoteq,filt-disable:
|
||||||
|
type: boolean
|
||||||
|
description: Disables all raw count filtering.
|
||||||
|
|
||||||
|
azoteq,gpio3-select:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 7
|
||||||
|
default: 0
|
||||||
|
description:
|
||||||
|
Selects the channel for which the GPIO3 pin represents touch state.
|
||||||
|
|
||||||
|
azoteq,dual-direction:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Specifies that long-term averages are to freeze in the presence of either
|
||||||
|
increasing or decreasing counts, thereby permitting events to be reported
|
||||||
|
in either direction.
|
||||||
|
|
||||||
|
azoteq,tx-freq:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 0
|
||||||
|
description: |
|
||||||
|
Specifies the inductive sensing excitation frequency as follows (paren-
|
||||||
|
thesized numbers represent the frequency if 'azoteq,clk-div' is present):
|
||||||
|
0: 16 MHz (4 MHz)
|
||||||
|
1: 8 MHz (2 MHz)
|
||||||
|
2: 4 MHz (1 MHz)
|
||||||
|
3: 2 MHz (500 kHz)
|
||||||
|
|
||||||
|
azoteq,global-cap-increase:
|
||||||
|
type: boolean
|
||||||
|
description: Increases the global capacitance adder from 0.5 pF to 1.5 pF.
|
||||||
|
|
||||||
|
azoteq,reseed-select:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 0
|
||||||
|
description: |
|
||||||
|
Specifies the event(s) that prompt the device to reseed (i.e. reset the
|
||||||
|
long-term average) of an associated channel as follows:
|
||||||
|
0: None
|
||||||
|
1: Proximity
|
||||||
|
2: Proximity or touch
|
||||||
|
3: Proximity, touch or deep touch
|
||||||
|
|
||||||
|
azoteq,tracking-enable:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Enables all associated channels to track their respective reference
|
||||||
|
channels.
|
||||||
|
|
||||||
|
azoteq,filt-str-slider:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 1
|
||||||
|
description: Specifies the slider coordinate filter strength.
|
||||||
|
|
||||||
|
patternProperties:
|
||||||
|
"^channel@[0-7]$":
|
||||||
|
type: object
|
||||||
|
description:
|
||||||
|
Represents a single sensing channel. A channel is active if defined and
|
||||||
|
inactive otherwise.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
reg:
|
||||||
|
minimum: 0
|
||||||
|
maximum: 7
|
||||||
|
description: Index of the channel.
|
||||||
|
|
||||||
|
azoteq,reseed-disable:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Prevents the channel from being reseeded if the long-term average
|
||||||
|
timeout (defined in 'azoteq,timeout-lta') expires.
|
||||||
|
|
||||||
|
azoteq,blocking-enable:
|
||||||
|
type: boolean
|
||||||
|
description: Specifies that the channel is a blocking channel.
|
||||||
|
|
||||||
|
azoteq,slider0-select:
|
||||||
|
type: boolean
|
||||||
|
description: Specifies that the channel participates in slider 0.
|
||||||
|
|
||||||
|
azoteq,slider1-select:
|
||||||
|
type: boolean
|
||||||
|
description: Specifies that the channel participates in slider 1.
|
||||||
|
|
||||||
|
azoteq,rx-enable:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
- minItems: 1
|
||||||
|
maxItems: 8
|
||||||
|
items:
|
||||||
|
minimum: 0
|
||||||
|
maximum: 7
|
||||||
|
description:
|
||||||
|
Specifies the CRX pin(s) associated with the channel. By default, only
|
||||||
|
the CRX pin corresponding to the channel's index is enabled (e.g. CRX0
|
||||||
|
for channel 0).
|
||||||
|
|
||||||
|
azoteq,tx-enable:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
- minItems: 1
|
||||||
|
maxItems: 8
|
||||||
|
items:
|
||||||
|
minimum: 0
|
||||||
|
maximum: 7
|
||||||
|
default: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||||
|
description: Specifies the TX pin(s) associated with the channel.
|
||||||
|
|
||||||
|
azoteq,meas-cap-decrease:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Decreases the internal measurement capacitance from 60 pF to 15 pF.
|
||||||
|
|
||||||
|
azoteq,rx-float-inactive:
|
||||||
|
type: boolean
|
||||||
|
description: Floats any inactive CRX pins instead of grounding them.
|
||||||
|
|
||||||
|
azoteq,local-cap-size:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2]
|
||||||
|
default: 0
|
||||||
|
description: |
|
||||||
|
Specifies the capacitance to be added to the channel as follows:
|
||||||
|
0: None
|
||||||
|
1: Global adder (based on 'azoteq,global-cap-increase')
|
||||||
|
2: Global adder + 0.5 pF
|
||||||
|
|
||||||
|
azoteq,invert-enable:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Inverts the polarity of the states reported for proximity, touch and
|
||||||
|
deep-touch events relative to their respective thresholds.
|
||||||
|
|
||||||
|
azoteq,proj-bias:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 2
|
||||||
|
description: |
|
||||||
|
Specifies the bias current applied during projected-capacitance
|
||||||
|
sensing as follows:
|
||||||
|
0: 2.5 uA
|
||||||
|
1: 5 uA
|
||||||
|
2: 10 uA
|
||||||
|
3: 20 uA
|
||||||
|
|
||||||
|
azoteq,sense-mode:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 9, 14, 15]
|
||||||
|
default: 0
|
||||||
|
description: |
|
||||||
|
Specifies the channel's sensing mode as follows:
|
||||||
|
0: Self capacitance
|
||||||
|
1: Projected capacitance
|
||||||
|
9: Self or mutual inductance
|
||||||
|
14: Hall effect
|
||||||
|
15: Temperature
|
||||||
|
|
||||||
|
azoteq,sense-freq:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 1
|
||||||
|
description: |
|
||||||
|
Specifies the channel's sensing frequency as follows (parenthesized
|
||||||
|
numbers represent the frequency if 'azoteq,clk-div' is present):
|
||||||
|
0: 4 MHz (1 MHz)
|
||||||
|
1: 2 MHz (500 kHz)
|
||||||
|
2: 1 MHz (250 kHz)
|
||||||
|
3: 500 kHz (125 kHz)
|
||||||
|
|
||||||
|
azoteq,static-enable:
|
||||||
|
type: boolean
|
||||||
|
description: Enables the static front-end for the channel.
|
||||||
|
|
||||||
|
azoteq,ati-mode:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [0, 1, 2, 3]
|
||||||
|
default: 3
|
||||||
|
description: |
|
||||||
|
Specifies the channel's ATI mode as follows:
|
||||||
|
0: Disabled
|
||||||
|
1: Semi-partial
|
||||||
|
2: Partial
|
||||||
|
3: Full
|
||||||
|
|
||||||
|
azoteq,ati-base:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- enum: [75, 100, 150, 200]
|
||||||
|
default: 100
|
||||||
|
description: Specifies the channel's ATI base.
|
||||||
|
|
||||||
|
azoteq,ati-target:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- multipleOf: 32
|
||||||
|
minimum: 0
|
||||||
|
maximum: 2016
|
||||||
|
default: 512
|
||||||
|
description: Specifies the channel's ATI target.
|
||||||
|
|
||||||
|
azoteq,assoc-select:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
- minItems: 1
|
||||||
|
maxItems: 8
|
||||||
|
items:
|
||||||
|
minimum: 0
|
||||||
|
maximum: 7
|
||||||
|
description:
|
||||||
|
Specifies the associated channels for which the channel serves as a
|
||||||
|
reference channel. By default, no channels are selected.
|
||||||
|
|
||||||
|
azoteq,assoc-weight:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 255
|
||||||
|
default: 0
|
||||||
|
description:
|
||||||
|
Specifies the channel's impact weight if it acts as an associated
|
||||||
|
channel (0 = 0% impact, 255 = 200% impact).
|
||||||
|
|
||||||
|
patternProperties:
|
||||||
|
"^event-prox(-alt)?$":
|
||||||
|
type: object
|
||||||
|
description:
|
||||||
|
Represents a proximity event reported by the channel in response to
|
||||||
|
a decrease in counts. Node names suffixed with '-alt' instead corre-
|
||||||
|
spond to an increase in counts.
|
||||||
|
|
||||||
|
By default, the long-term average tracks an increase in counts such
|
||||||
|
that only events corresponding to a decrease in counts are reported
|
||||||
|
(refer to the datasheet for more information).
|
||||||
|
|
||||||
|
Specify 'azoteq,dual-direction' to freeze the long-term average when
|
||||||
|
the counts increase or decrease such that events of either direction
|
||||||
|
can be reported. Alternatively, specify 'azoteq,invert-enable' to in-
|
||||||
|
vert the polarity of the states reported by the channel.
|
||||||
|
|
||||||
|
Complementary events (e.g. event-touch and event-touch-alt) can both
|
||||||
|
be present and specify different key or switch codes, but not differ-
|
||||||
|
ent thresholds or hysteresis (if applicable).
|
||||||
|
|
||||||
|
properties:
|
||||||
|
azoteq,thresh:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 255
|
||||||
|
default: 10
|
||||||
|
description: Specifies the threshold for the event.
|
||||||
|
|
||||||
|
linux,code:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: Numeric key or switch code associated with the event.
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
"^event-touch(-alt)?$":
|
||||||
|
type: object
|
||||||
|
description: Represents a touch event reported by the channel.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
azoteq,thresh:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 255
|
||||||
|
default: 8
|
||||||
|
description: Specifies the threshold for the event.
|
||||||
|
|
||||||
|
azoteq,hyst:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 15
|
||||||
|
default: 4
|
||||||
|
description: Specifies the hysteresis for the event.
|
||||||
|
|
||||||
|
linux,code:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: Numeric key or switch code associated with the event.
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
"^event-deep(-alt)?$":
|
||||||
|
type: object
|
||||||
|
description: Represents a deep-touch event reported by the channel.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
azoteq,thresh:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 255
|
||||||
|
default: 26
|
||||||
|
description: Specifies the threshold for the event.
|
||||||
|
|
||||||
|
azoteq,hyst:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 15
|
||||||
|
default: 0
|
||||||
|
description: Specifies the hysteresis for the event.
|
||||||
|
|
||||||
|
linux,code:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: Numeric key or switch code associated with the event.
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- reg
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- "#address-cells"
|
||||||
|
- "#size-cells"
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/input/input.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
iqs269a@44 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
compatible = "azoteq,iqs269a";
|
||||||
|
reg = <0x44>;
|
||||||
|
interrupt-parent = <&gpio>;
|
||||||
|
interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
|
||||||
|
azoteq,hall-enable;
|
||||||
|
azoteq,suspend-mode = <2>;
|
||||||
|
|
||||||
|
channel@0 {
|
||||||
|
reg = <0x0>;
|
||||||
|
|
||||||
|
event-prox {
|
||||||
|
linux,code = <KEY_POWER>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
channel@1 {
|
||||||
|
reg = <0x1>;
|
||||||
|
azoteq,slider0-select;
|
||||||
|
};
|
||||||
|
|
||||||
|
channel@2 {
|
||||||
|
reg = <0x2>;
|
||||||
|
azoteq,slider0-select;
|
||||||
|
};
|
||||||
|
|
||||||
|
channel@3 {
|
||||||
|
reg = <0x3>;
|
||||||
|
azoteq,slider0-select;
|
||||||
|
};
|
||||||
|
|
||||||
|
channel@4 {
|
||||||
|
reg = <0x4>;
|
||||||
|
azoteq,slider0-select;
|
||||||
|
};
|
||||||
|
|
||||||
|
channel@5 {
|
||||||
|
reg = <0x5>;
|
||||||
|
azoteq,slider0-select;
|
||||||
|
};
|
||||||
|
|
||||||
|
channel@6 {
|
||||||
|
reg = <0x6>;
|
||||||
|
azoteq,invert-enable;
|
||||||
|
azoteq,static-enable;
|
||||||
|
azoteq,reseed-disable;
|
||||||
|
azoteq,rx-enable = <0>;
|
||||||
|
azoteq,sense-freq = <0x0>;
|
||||||
|
azoteq,sense-mode = <0xE>;
|
||||||
|
azoteq,ati-mode = <0x0>;
|
||||||
|
azoteq,ati-base = <200>;
|
||||||
|
azoteq,ati-target = <320>;
|
||||||
|
};
|
||||||
|
|
||||||
|
channel@7 {
|
||||||
|
reg = <0x7>;
|
||||||
|
azoteq,invert-enable;
|
||||||
|
azoteq,static-enable;
|
||||||
|
azoteq,reseed-disable;
|
||||||
|
azoteq,rx-enable = <0>, <6>;
|
||||||
|
azoteq,sense-freq = <0x0>;
|
||||||
|
azoteq,sense-mode = <0xE>;
|
||||||
|
azoteq,ati-mode = <0x3>;
|
||||||
|
azoteq,ati-base = <200>;
|
||||||
|
azoteq,ati-target = <320>;
|
||||||
|
|
||||||
|
event-touch {
|
||||||
|
linux,code = <SW_LID>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
@ -1,36 +0,0 @@
|
|||||||
* Device tree bindings for the Qualcomm MSM vibrator
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
|
|
||||||
- compatible: Should be one of
|
|
||||||
"qcom,msm8226-vibrator"
|
|
||||||
"qcom,msm8974-vibrator"
|
|
||||||
- reg: the base address and length of the IO memory for the registers.
|
|
||||||
- pinctrl-names: set to default.
|
|
||||||
- pinctrl-0: phandles pointing to pin configuration nodes. See
|
|
||||||
Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
|
|
||||||
- clock-names: set to pwm
|
|
||||||
- clocks: phandle of the clock. See
|
|
||||||
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
|
||||||
- enable-gpios: GPIO that enables the vibrator.
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
|
|
||||||
- vcc-supply: phandle to the regulator that provides power to the sensor.
|
|
||||||
|
|
||||||
Example from a LG Nexus 5 (hammerhead) phone:
|
|
||||||
|
|
||||||
vibrator@fd8c3450 {
|
|
||||||
reg = <0xfd8c3450 0x400>;
|
|
||||||
compatible = "qcom,msm8974-vibrator";
|
|
||||||
|
|
||||||
vcc-supply = <&pm8941_l19>;
|
|
||||||
|
|
||||||
clocks = <&mmcc CAMSS_GP1_CLK>;
|
|
||||||
clock-names = "pwm";
|
|
||||||
|
|
||||||
enable-gpios = <&msmgpio 60 GPIO_ACTIVE_HIGH>;
|
|
||||||
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&vibrator_pin>;
|
|
||||||
};
|
|
@ -0,0 +1,72 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/input/touchscreen/cypress,cy8ctma140.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Cypress CY8CTMA140 series touchscreen controller bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Linus Walleij <linus.walleij@linaro.org>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: touchscreen.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: cypress,cy8ctma140
|
||||||
|
|
||||||
|
reg:
|
||||||
|
const: 0x20
|
||||||
|
|
||||||
|
clock-frequency:
|
||||||
|
description: I2C client clock frequency, defined for host
|
||||||
|
minimum: 100000
|
||||||
|
maximum: 400000
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
vcpin-supply:
|
||||||
|
description: Analog power supply regulator on VCPIN pin
|
||||||
|
|
||||||
|
vdd-supply:
|
||||||
|
description: Digital power supply regulator on VDD pin
|
||||||
|
|
||||||
|
touchscreen-inverted-x: true
|
||||||
|
touchscreen-inverted-y: true
|
||||||
|
touchscreen-size-x: true
|
||||||
|
touchscreen-size-y: true
|
||||||
|
touchscreen-swapped-x-y: true
|
||||||
|
touchscreen-max-pressure: true
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- touchscreen-size-x
|
||||||
|
- touchscreen-size-y
|
||||||
|
- touchscreen-max-pressure
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
touchscreen@20 {
|
||||||
|
compatible = "cypress,cy8ctma140";
|
||||||
|
reg = <0x20>;
|
||||||
|
touchscreen-size-x = <480>;
|
||||||
|
touchscreen-size-y = <800>;
|
||||||
|
touchscreen-max-pressure = <255>;
|
||||||
|
interrupt-parent = <&gpio6>;
|
||||||
|
interrupts = <26 IRQ_TYPE_EDGE_FALLING>;
|
||||||
|
vdd-supply = <&ab8500_ldo_aux2_reg>;
|
||||||
|
vcpin-supply = <&ab8500_ldo_aux2_reg>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
@ -0,0 +1,69 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: "http://devicetree.org/schemas/input/touchscreen/elan,elants_i2c.yaml#"
|
||||||
|
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||||
|
|
||||||
|
title: Elantech I2C Touchscreen
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- David Heidelberg <david@ixit.cz>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: touchscreen.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- elan,ektf3624
|
||||||
|
- elan,ekth3500
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
wakeup-source:
|
||||||
|
type: boolean
|
||||||
|
description: touchscreen can be used as a wakeup source.
|
||||||
|
|
||||||
|
reset-gpios:
|
||||||
|
description: reset gpio the chip is connected to.
|
||||||
|
|
||||||
|
vcc33-supply:
|
||||||
|
description: a phandle for the regulator supplying 3.3V power.
|
||||||
|
|
||||||
|
vccio-supply:
|
||||||
|
description: a phandle for the regulator supplying IO power.
|
||||||
|
|
||||||
|
touchscreen-inverted-x: true
|
||||||
|
touchscreen-inverted-y: true
|
||||||
|
touchscreen-size-x: true
|
||||||
|
touchscreen-size-y: true
|
||||||
|
touchscreen-swapped-x-y: true
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
touchscreen@10 {
|
||||||
|
compatible = "elan,ekth3500";
|
||||||
|
reg = <0x10>;
|
||||||
|
|
||||||
|
interrupt-parent = <&gpio4>;
|
||||||
|
interrupts = <0x0 IRQ_TYPE_EDGE_FALLING>;
|
||||||
|
wakeup-source;
|
||||||
|
};
|
||||||
|
};
|
@ -1,9 +1,10 @@
|
|||||||
* MELFAS MMS114/MMS152 touchscreen controller
|
* MELFAS MMS114/MMS152/MMS345L touchscreen controller
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: should be one of:
|
- compatible: should be one of:
|
||||||
- "melfas,mms114"
|
- "melfas,mms114"
|
||||||
- "melfas,mms152"
|
- "melfas,mms152"
|
||||||
|
- "melfas,mms345l"
|
||||||
- reg: I2C address of the chip
|
- reg: I2C address of the chip
|
||||||
- interrupts: interrupt to which the chip is connected
|
- interrupts: interrupt to which the chip is connected
|
||||||
- touchscreen-size-x: See [1]
|
- touchscreen-size-x: See [1]
|
||||||
|
@ -4710,6 +4710,12 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/
|
|||||||
T: git git://linuxtv.org/anttip/media_tree.git
|
T: git git://linuxtv.org/anttip/media_tree.git
|
||||||
F: drivers/media/common/cypress_firmware*
|
F: drivers/media/common/cypress_firmware*
|
||||||
|
|
||||||
|
CYPRESS CY8CTMA140 TOUCHSCREEN DRIVER
|
||||||
|
M: Linus Walleij <linus.walleij@linaro.org>
|
||||||
|
L: linux-input@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: drivers/input/touchscreen/cy8ctma140.c
|
||||||
|
|
||||||
CYTTSP TOUCHSCREEN DRIVER
|
CYTTSP TOUCHSCREEN DRIVER
|
||||||
M: Ferruh Yigit <fery@cypress.com>
|
M: Ferruh Yigit <fery@cypress.com>
|
||||||
L: linux-input@vger.kernel.org
|
L: linux-input@vger.kernel.org
|
||||||
|
@ -387,8 +387,7 @@ static int u1_raw_event(struct alps_dev *hdata, u8 *data, int size)
|
|||||||
input_report_abs(hdata->input,
|
input_report_abs(hdata->input,
|
||||||
ABS_MT_PRESSURE, z);
|
ABS_MT_PRESSURE, z);
|
||||||
} else {
|
} else {
|
||||||
input_mt_report_slot_state(hdata->input,
|
input_mt_report_slot_inactive(hdata->input);
|
||||||
MT_TOOL_FINGER, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,7 +899,7 @@ static void mt_release_pending_palms(struct mt_device *td,
|
|||||||
clear_bit(slotnum, app->pending_palm_slots);
|
clear_bit(slotnum, app->pending_palm_slots);
|
||||||
|
|
||||||
input_mt_slot(input, slotnum);
|
input_mt_slot(input, slotnum);
|
||||||
input_mt_report_slot_state(input, MT_TOOL_PALM, false);
|
input_mt_report_slot_inactive(input);
|
||||||
|
|
||||||
need_sync = true;
|
need_sync = true;
|
||||||
}
|
}
|
||||||
@ -1643,9 +1643,7 @@ static void mt_release_contacts(struct hid_device *hid)
|
|||||||
if (mt) {
|
if (mt) {
|
||||||
for (i = 0; i < mt->num_slots; i++) {
|
for (i = 0; i < mt->num_slots; i++) {
|
||||||
input_mt_slot(input_dev, i);
|
input_mt_slot(input_dev, i);
|
||||||
input_mt_report_slot_state(input_dev,
|
input_mt_report_slot_inactive(input_dev);
|
||||||
MT_TOOL_FINGER,
|
|
||||||
false);
|
|
||||||
}
|
}
|
||||||
input_mt_sync_frame(input_dev);
|
input_mt_sync_frame(input_dev);
|
||||||
input_sync(input_dev);
|
input_sync(input_dev);
|
||||||
|
@ -282,7 +282,8 @@ static void evdev_pass_values(struct evdev_client *client,
|
|||||||
spin_unlock(&client->buffer_lock);
|
spin_unlock(&client->buffer_lock);
|
||||||
|
|
||||||
if (wakeup)
|
if (wakeup)
|
||||||
wake_up_interruptible(&evdev->wait);
|
wake_up_interruptible_poll(&evdev->wait,
|
||||||
|
EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -429,7 +430,7 @@ static void evdev_hangup(struct evdev *evdev)
|
|||||||
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
kill_fasync(&client->fasync, SIGIO, POLL_HUP);
|
||||||
spin_unlock(&evdev->client_lock);
|
spin_unlock(&evdev->client_lock);
|
||||||
|
|
||||||
wake_up_interruptible(&evdev->wait);
|
wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int evdev_release(struct inode *inode, struct file *file)
|
static int evdev_release(struct inode *inode, struct file *file)
|
||||||
@ -945,7 +946,7 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
|
|||||||
client->revoked = true;
|
client->revoked = true;
|
||||||
evdev_ungrab(evdev, client);
|
evdev_ungrab(evdev, client);
|
||||||
input_flush_device(&evdev->handle, file);
|
input_flush_device(&evdev->handle, file);
|
||||||
wake_up_interruptible(&evdev->wait);
|
wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ config JOYSTICK_A3D
|
|||||||
config JOYSTICK_ADI
|
config JOYSTICK_ADI
|
||||||
tristate "Logitech ADI digital joysticks and gamepads"
|
tristate "Logitech ADI digital joysticks and gamepads"
|
||||||
select GAMEPORT
|
select GAMEPORT
|
||||||
|
depends on ADI!=m # avoid module name conflict
|
||||||
help
|
help
|
||||||
Say Y here if you have a Logitech controller using the ADI
|
Say Y here if you have a Logitech controller using the ADI
|
||||||
protocol over the PC gameport.
|
protocol over the PC gameport.
|
||||||
|
@ -701,7 +701,7 @@ config KEYBOARD_SPEAR
|
|||||||
Say Y here if you want to use the SPEAR keyboard.
|
Say Y here if you want to use the SPEAR keyboard.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called spear-keboard.
|
module will be called spear-keyboard.
|
||||||
|
|
||||||
config KEYBOARD_TC3589X
|
config KEYBOARD_TC3589X
|
||||||
tristate "TC3589X Keypad support"
|
tristate "TC3589X Keypad support"
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#include <linux/libps2.h>
|
#include <linux/libps2.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
|
#include <linux/property.h>
|
||||||
|
|
||||||
#define DRIVER_DESC "AT and PS/2 keyboard driver"
|
#define DRIVER_DESC "AT and PS/2 keyboard driver"
|
||||||
|
|
||||||
@ -63,6 +64,11 @@ static bool atkbd_terminal;
|
|||||||
module_param_named(terminal, atkbd_terminal, bool, 0);
|
module_param_named(terminal, atkbd_terminal, bool, 0);
|
||||||
MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
|
MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
|
||||||
|
|
||||||
|
#define MAX_FUNCTION_ROW_KEYS 24
|
||||||
|
|
||||||
|
#define SCANCODE(keymap) ((keymap >> 16) & 0xFFFF)
|
||||||
|
#define KEYCODE(keymap) (keymap & 0xFFFF)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scancode to keycode tables. These are just the default setting, and
|
* Scancode to keycode tables. These are just the default setting, and
|
||||||
* are loadable via a userland utility.
|
* are loadable via a userland utility.
|
||||||
@ -230,6 +236,9 @@ struct atkbd {
|
|||||||
|
|
||||||
/* Serializes reconnect(), attr->set() and event work */
|
/* Serializes reconnect(), attr->set() and event work */
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
|
|
||||||
|
u32 function_row_physmap[MAX_FUNCTION_ROW_KEYS];
|
||||||
|
int num_function_row_keys;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -283,6 +292,7 @@ static struct device_attribute atkbd_attr_##_name = \
|
|||||||
__ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL);
|
__ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL);
|
||||||
|
|
||||||
ATKBD_DEFINE_RO_ATTR(err_count);
|
ATKBD_DEFINE_RO_ATTR(err_count);
|
||||||
|
ATKBD_DEFINE_RO_ATTR(function_row_physmap);
|
||||||
|
|
||||||
static struct attribute *atkbd_attributes[] = {
|
static struct attribute *atkbd_attributes[] = {
|
||||||
&atkbd_attr_extra.attr,
|
&atkbd_attr_extra.attr,
|
||||||
@ -292,11 +302,42 @@ static struct attribute *atkbd_attributes[] = {
|
|||||||
&atkbd_attr_softrepeat.attr,
|
&atkbd_attr_softrepeat.attr,
|
||||||
&atkbd_attr_softraw.attr,
|
&atkbd_attr_softraw.attr,
|
||||||
&atkbd_attr_err_count.attr,
|
&atkbd_attr_err_count.attr,
|
||||||
|
&atkbd_attr_function_row_physmap.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf)
|
||||||
|
{
|
||||||
|
ssize_t size = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!atkbd->num_function_row_keys)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < atkbd->num_function_row_keys; i++)
|
||||||
|
size += scnprintf(buf + size, PAGE_SIZE - size, "%02X ",
|
||||||
|
atkbd->function_row_physmap[i]);
|
||||||
|
size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static umode_t atkbd_attr_is_visible(struct kobject *kobj,
|
||||||
|
struct attribute *attr, int i)
|
||||||
|
{
|
||||||
|
struct device *dev = container_of(kobj, struct device, kobj);
|
||||||
|
struct serio *serio = to_serio_port(dev);
|
||||||
|
struct atkbd *atkbd = serio_get_drvdata(serio);
|
||||||
|
|
||||||
|
if (attr == &atkbd_attr_function_row_physmap.attr &&
|
||||||
|
!atkbd->num_function_row_keys)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return attr->mode;
|
||||||
|
}
|
||||||
|
|
||||||
static struct attribute_group atkbd_attribute_group = {
|
static struct attribute_group atkbd_attribute_group = {
|
||||||
.attrs = atkbd_attributes,
|
.attrs = atkbd_attributes,
|
||||||
|
.is_visible = atkbd_attr_is_visible,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int xl_table[] = {
|
static const unsigned int xl_table[] = {
|
||||||
@ -994,6 +1035,39 @@ static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
|
||||||
|
{
|
||||||
|
struct device *dev = &atkbd->ps2dev.serio->dev;
|
||||||
|
int i, n;
|
||||||
|
u32 *ptr;
|
||||||
|
u16 scancode, keycode;
|
||||||
|
|
||||||
|
/* Parse "linux,keymap" property */
|
||||||
|
n = device_property_count_u32(dev, "linux,keymap");
|
||||||
|
if (n <= 0 || n > ATKBD_KEYMAP_SIZE)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
ptr = kcalloc(n, sizeof(u32), GFP_KERNEL);
|
||||||
|
if (!ptr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) {
|
||||||
|
dev_err(dev, "problem parsing FW keymap property\n");
|
||||||
|
kfree(ptr);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
scancode = SCANCODE(ptr[i]);
|
||||||
|
keycode = KEYCODE(ptr[i]);
|
||||||
|
atkbd->keycode[scancode] = keycode;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(ptr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* atkbd_set_keycode_table() initializes keyboard's keycode table
|
* atkbd_set_keycode_table() initializes keyboard's keycode table
|
||||||
* according to the selected scancode set
|
* according to the selected scancode set
|
||||||
@ -1001,13 +1075,16 @@ static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd,
|
|||||||
|
|
||||||
static void atkbd_set_keycode_table(struct atkbd *atkbd)
|
static void atkbd_set_keycode_table(struct atkbd *atkbd)
|
||||||
{
|
{
|
||||||
|
struct device *dev = &atkbd->ps2dev.serio->dev;
|
||||||
unsigned int scancode;
|
unsigned int scancode;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
|
memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
|
||||||
bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
|
bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
|
||||||
|
|
||||||
if (atkbd->translated) {
|
if (!atkbd_get_keymap_from_fwnode(atkbd)) {
|
||||||
|
dev_dbg(dev, "Using FW keymap\n");
|
||||||
|
} else if (atkbd->translated) {
|
||||||
for (i = 0; i < 128; i++) {
|
for (i = 0; i < 128; i++) {
|
||||||
scancode = atkbd_unxlate_table[i];
|
scancode = atkbd_unxlate_table[i];
|
||||||
atkbd->keycode[i] = atkbd_set2_keycode[scancode];
|
atkbd->keycode[i] = atkbd_set2_keycode[scancode];
|
||||||
@ -1121,6 +1198,22 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void atkbd_parse_fwnode_data(struct serio *serio)
|
||||||
|
{
|
||||||
|
struct atkbd *atkbd = serio_get_drvdata(serio);
|
||||||
|
struct device *dev = &serio->dev;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* Parse "function-row-physmap" property */
|
||||||
|
n = device_property_count_u32(dev, "function-row-physmap");
|
||||||
|
if (n > 0 && n <= MAX_FUNCTION_ROW_KEYS &&
|
||||||
|
!device_property_read_u32_array(dev, "function-row-physmap",
|
||||||
|
atkbd->function_row_physmap, n)) {
|
||||||
|
atkbd->num_function_row_keys = n;
|
||||||
|
dev_dbg(dev, "FW reported %d function-row key locations\n", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* atkbd_connect() is called when the serio module finds an interface
|
* atkbd_connect() is called when the serio module finds an interface
|
||||||
* that isn't handled yet by an appropriate device driver. We check if
|
* that isn't handled yet by an appropriate device driver. We check if
|
||||||
@ -1184,6 +1277,8 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
|
|||||||
atkbd->id = 0xab00;
|
atkbd->id = 0xab00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atkbd_parse_fwnode_data(serio);
|
||||||
|
|
||||||
atkbd_set_keycode_table(atkbd);
|
atkbd_set_keycode_table(atkbd);
|
||||||
atkbd_set_device_attrs(atkbd);
|
atkbd_set_device_attrs(atkbd);
|
||||||
|
|
||||||
|
@ -99,6 +99,15 @@ static void imx_sc_check_for_events(struct work_struct *work)
|
|||||||
msecs_to_jiffies(REPEAT_INTERVAL));
|
msecs_to_jiffies(REPEAT_INTERVAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void imx_sc_key_action(void *data)
|
||||||
|
{
|
||||||
|
struct imx_key_drv_data *priv = data;
|
||||||
|
|
||||||
|
imx_scu_irq_group_enable(SC_IRQ_GROUP_WAKE, SC_IRQ_BUTTON, false);
|
||||||
|
imx_scu_irq_unregister_notifier(&priv->key_notifier);
|
||||||
|
cancel_delayed_work_sync(&priv->check_work);
|
||||||
|
}
|
||||||
|
|
||||||
static int imx_sc_key_probe(struct platform_device *pdev)
|
static int imx_sc_key_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct imx_key_drv_data *priv;
|
struct imx_key_drv_data *priv;
|
||||||
@ -149,27 +158,16 @@ static int imx_sc_key_probe(struct platform_device *pdev)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error = devm_add_action_or_reset(&pdev->dev, imx_sc_key_action, &priv);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
priv->key_notifier.notifier_call = imx_sc_key_notify;
|
priv->key_notifier.notifier_call = imx_sc_key_notify;
|
||||||
error = imx_scu_irq_register_notifier(&priv->key_notifier);
|
error = imx_scu_irq_register_notifier(&priv->key_notifier);
|
||||||
if (error) {
|
if (error)
|
||||||
imx_scu_irq_group_enable(SC_IRQ_GROUP_WAKE, SC_IRQ_BUTTON,
|
|
||||||
false);
|
|
||||||
dev_err(&pdev->dev, "failed to register scu notifier\n");
|
dev_err(&pdev->dev, "failed to register scu notifier\n");
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return error;
|
||||||
}
|
|
||||||
|
|
||||||
static int imx_sc_key_remove(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct imx_key_drv_data *priv = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
imx_scu_irq_group_enable(SC_IRQ_GROUP_WAKE, SC_IRQ_BUTTON, false);
|
|
||||||
imx_scu_irq_unregister_notifier(&priv->key_notifier);
|
|
||||||
cancel_delayed_work_sync(&priv->check_work);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id imx_sc_key_ids[] = {
|
static const struct of_device_id imx_sc_key_ids[] = {
|
||||||
@ -184,7 +182,6 @@ static struct platform_driver imx_sc_key_driver = {
|
|||||||
.of_match_table = imx_sc_key_ids,
|
.of_match_table = imx_sc_key_ids,
|
||||||
},
|
},
|
||||||
.probe = imx_sc_key_probe,
|
.probe = imx_sc_key_probe,
|
||||||
.remove = imx_sc_key_remove,
|
|
||||||
};
|
};
|
||||||
module_platform_driver(imx_sc_key_driver);
|
module_platform_driver(imx_sc_key_driver);
|
||||||
|
|
||||||
|
@ -374,5 +374,5 @@ static void __exit tca6416_keypad_exit(void)
|
|||||||
module_exit(tca6416_keypad_exit);
|
module_exit(tca6416_keypad_exit);
|
||||||
|
|
||||||
MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>");
|
MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>");
|
||||||
MODULE_DESCRIPTION("Keypad driver over tca6146 IO expander");
|
MODULE_DESCRIPTION("Keypad driver over tca6416 IO expander");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@ -117,16 +117,6 @@ config INPUT_E3X0_BUTTON
|
|||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called e3x0_button.
|
module will be called e3x0_button.
|
||||||
|
|
||||||
config INPUT_MSM_VIBRATOR
|
|
||||||
tristate "Qualcomm MSM vibrator driver"
|
|
||||||
select INPUT_FF_MEMLESS
|
|
||||||
help
|
|
||||||
Support for the vibrator that is found on various Qualcomm MSM
|
|
||||||
SOCs.
|
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the module
|
|
||||||
will be called msm_vibrator.
|
|
||||||
|
|
||||||
config INPUT_PCSPKR
|
config INPUT_PCSPKR
|
||||||
tristate "PC Speaker support"
|
tristate "PC Speaker support"
|
||||||
depends on PCSPKR_PLATFORM
|
depends on PCSPKR_PLATFORM
|
||||||
@ -265,17 +255,6 @@ config INPUT_APANEL
|
|||||||
To compile this driver as a module, choose M here: the module will
|
To compile this driver as a module, choose M here: the module will
|
||||||
be called apanel.
|
be called apanel.
|
||||||
|
|
||||||
config INPUT_GP2A
|
|
||||||
tristate "Sharp GP2AP002A00F I2C Proximity/Opto sensor driver"
|
|
||||||
depends on I2C
|
|
||||||
depends on GPIOLIB || COMPILE_TEST
|
|
||||||
help
|
|
||||||
Say Y here if you have a Sharp GP2AP002A00F proximity/als combo-chip
|
|
||||||
hooked to an I2C bus.
|
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
|
||||||
module will be called gp2ap002a00f.
|
|
||||||
|
|
||||||
config INPUT_GPIO_BEEPER
|
config INPUT_GPIO_BEEPER
|
||||||
tristate "Generic GPIO Beeper support"
|
tristate "Generic GPIO Beeper support"
|
||||||
depends on GPIOLIB || COMPILE_TEST
|
depends on GPIOLIB || COMPILE_TEST
|
||||||
@ -739,6 +718,17 @@ config INPUT_IMS_PCU
|
|||||||
To compile this driver as a module, choose M here: the module will be
|
To compile this driver as a module, choose M here: the module will be
|
||||||
called ims_pcu.
|
called ims_pcu.
|
||||||
|
|
||||||
|
config INPUT_IQS269A
|
||||||
|
tristate "Azoteq IQS269A capacitive touch controller"
|
||||||
|
depends on I2C
|
||||||
|
select REGMAP_I2C
|
||||||
|
help
|
||||||
|
Say Y to enable support for the Azoteq IQS269A capacitive
|
||||||
|
touch controller.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called iqs269a.
|
||||||
|
|
||||||
config INPUT_CMA3000
|
config INPUT_CMA3000
|
||||||
tristate "VTI CMA3000 Tri-axis accelerometer"
|
tristate "VTI CMA3000 Tri-axis accelerometer"
|
||||||
help
|
help
|
||||||
|
@ -33,13 +33,13 @@ obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o
|
|||||||
obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o
|
obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o
|
||||||
obj-$(CONFIG_INPUT_DRV2665_HAPTICS) += drv2665.o
|
obj-$(CONFIG_INPUT_DRV2665_HAPTICS) += drv2665.o
|
||||||
obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
|
obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
|
||||||
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
|
|
||||||
obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o
|
obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o
|
||||||
obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o
|
obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o
|
||||||
obj-$(CONFIG_INPUT_GPIO_VIBRA) += gpio-vibra.o
|
obj-$(CONFIG_INPUT_GPIO_VIBRA) += gpio-vibra.o
|
||||||
obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o
|
obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o
|
||||||
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
|
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
|
||||||
obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
|
obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
|
||||||
|
obj-$(CONFIG_INPUT_IQS269A) += iqs269a.o
|
||||||
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
|
obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
|
||||||
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
|
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
|
||||||
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
|
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
|
||||||
@ -50,7 +50,6 @@ obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
|
|||||||
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
|
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
|
||||||
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
|
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
|
||||||
obj-$(CONFIG_INPUT_MMA8450) += mma8450.o
|
obj-$(CONFIG_INPUT_MMA8450) += mma8450.o
|
||||||
obj-$(CONFIG_INPUT_MSM_VIBRATOR) += msm-vibrator.o
|
|
||||||
obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o
|
obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o
|
||||||
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
|
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
|
||||||
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
|
obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
|
||||||
|
@ -1,281 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2011 Sony Ericsson Mobile Communications Inc.
|
|
||||||
*
|
|
||||||
* Author: Courtney Cavin <courtney.cavin@sonyericsson.com>
|
|
||||||
* Prepared for up-stream by: Oskar Andero <oskar.andero@sonyericsson.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/i2c.h>
|
|
||||||
#include <linux/irq.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/input/gp2ap002a00f.h>
|
|
||||||
|
|
||||||
struct gp2a_data {
|
|
||||||
struct input_dev *input;
|
|
||||||
const struct gp2a_platform_data *pdata;
|
|
||||||
struct i2c_client *i2c_client;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum gp2a_addr {
|
|
||||||
GP2A_ADDR_PROX = 0x0,
|
|
||||||
GP2A_ADDR_GAIN = 0x1,
|
|
||||||
GP2A_ADDR_HYS = 0x2,
|
|
||||||
GP2A_ADDR_CYCLE = 0x3,
|
|
||||||
GP2A_ADDR_OPMOD = 0x4,
|
|
||||||
GP2A_ADDR_CON = 0x6
|
|
||||||
};
|
|
||||||
|
|
||||||
enum gp2a_controls {
|
|
||||||
/* Software Shutdown control: 0 = shutdown, 1 = normal operation */
|
|
||||||
GP2A_CTRL_SSD = 0x01
|
|
||||||
};
|
|
||||||
|
|
||||||
static int gp2a_report(struct gp2a_data *dt)
|
|
||||||
{
|
|
||||||
int vo = gpio_get_value(dt->pdata->vout_gpio);
|
|
||||||
|
|
||||||
input_report_switch(dt->input, SW_FRONT_PROXIMITY, !vo);
|
|
||||||
input_sync(dt->input);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t gp2a_irq(int irq, void *handle)
|
|
||||||
{
|
|
||||||
struct gp2a_data *dt = handle;
|
|
||||||
|
|
||||||
gp2a_report(dt);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gp2a_enable(struct gp2a_data *dt)
|
|
||||||
{
|
|
||||||
return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD,
|
|
||||||
GP2A_CTRL_SSD);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gp2a_disable(struct gp2a_data *dt)
|
|
||||||
{
|
|
||||||
return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD,
|
|
||||||
0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gp2a_device_open(struct input_dev *dev)
|
|
||||||
{
|
|
||||||
struct gp2a_data *dt = input_get_drvdata(dev);
|
|
||||||
int error;
|
|
||||||
|
|
||||||
error = gp2a_enable(dt);
|
|
||||||
if (error < 0) {
|
|
||||||
dev_err(&dt->i2c_client->dev,
|
|
||||||
"unable to activate, err %d\n", error);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
gp2a_report(dt);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gp2a_device_close(struct input_dev *dev)
|
|
||||||
{
|
|
||||||
struct gp2a_data *dt = input_get_drvdata(dev);
|
|
||||||
int error;
|
|
||||||
|
|
||||||
error = gp2a_disable(dt);
|
|
||||||
if (error < 0)
|
|
||||||
dev_err(&dt->i2c_client->dev,
|
|
||||||
"unable to deactivate, err %d\n", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gp2a_initialize(struct gp2a_data *dt)
|
|
||||||
{
|
|
||||||
int error;
|
|
||||||
|
|
||||||
error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_GAIN,
|
|
||||||
0x08);
|
|
||||||
if (error < 0)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_HYS,
|
|
||||||
0xc2);
|
|
||||||
if (error < 0)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_CYCLE,
|
|
||||||
0x04);
|
|
||||||
if (error < 0)
|
|
||||||
return error;
|
|
||||||
|
|
||||||
error = gp2a_disable(dt);
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gp2a_probe(struct i2c_client *client,
|
|
||||||
const struct i2c_device_id *id)
|
|
||||||
{
|
|
||||||
const struct gp2a_platform_data *pdata = dev_get_platdata(&client->dev);
|
|
||||||
struct gp2a_data *dt;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
if (!pdata)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (pdata->hw_setup) {
|
|
||||||
error = pdata->hw_setup(client);
|
|
||||||
if (error < 0)
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = gpio_request_one(pdata->vout_gpio, GPIOF_IN, GP2A_I2C_NAME);
|
|
||||||
if (error)
|
|
||||||
goto err_hw_shutdown;
|
|
||||||
|
|
||||||
dt = kzalloc(sizeof(struct gp2a_data), GFP_KERNEL);
|
|
||||||
if (!dt) {
|
|
||||||
error = -ENOMEM;
|
|
||||||
goto err_free_gpio;
|
|
||||||
}
|
|
||||||
|
|
||||||
dt->pdata = pdata;
|
|
||||||
dt->i2c_client = client;
|
|
||||||
|
|
||||||
error = gp2a_initialize(dt);
|
|
||||||
if (error < 0)
|
|
||||||
goto err_free_mem;
|
|
||||||
|
|
||||||
dt->input = input_allocate_device();
|
|
||||||
if (!dt->input) {
|
|
||||||
error = -ENOMEM;
|
|
||||||
goto err_free_mem;
|
|
||||||
}
|
|
||||||
|
|
||||||
input_set_drvdata(dt->input, dt);
|
|
||||||
|
|
||||||
dt->input->open = gp2a_device_open;
|
|
||||||
dt->input->close = gp2a_device_close;
|
|
||||||
dt->input->name = GP2A_I2C_NAME;
|
|
||||||
dt->input->id.bustype = BUS_I2C;
|
|
||||||
dt->input->dev.parent = &client->dev;
|
|
||||||
|
|
||||||
input_set_capability(dt->input, EV_SW, SW_FRONT_PROXIMITY);
|
|
||||||
|
|
||||||
error = request_threaded_irq(client->irq, NULL, gp2a_irq,
|
|
||||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
|
|
||||||
IRQF_ONESHOT,
|
|
||||||
GP2A_I2C_NAME, dt);
|
|
||||||
if (error) {
|
|
||||||
dev_err(&client->dev, "irq request failed\n");
|
|
||||||
goto err_free_input_dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = input_register_device(dt->input);
|
|
||||||
if (error) {
|
|
||||||
dev_err(&client->dev, "device registration failed\n");
|
|
||||||
goto err_free_irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
device_init_wakeup(&client->dev, pdata->wakeup);
|
|
||||||
i2c_set_clientdata(client, dt);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_free_irq:
|
|
||||||
free_irq(client->irq, dt);
|
|
||||||
err_free_input_dev:
|
|
||||||
input_free_device(dt->input);
|
|
||||||
err_free_mem:
|
|
||||||
kfree(dt);
|
|
||||||
err_free_gpio:
|
|
||||||
gpio_free(pdata->vout_gpio);
|
|
||||||
err_hw_shutdown:
|
|
||||||
if (pdata->hw_shutdown)
|
|
||||||
pdata->hw_shutdown(client);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gp2a_remove(struct i2c_client *client)
|
|
||||||
{
|
|
||||||
struct gp2a_data *dt = i2c_get_clientdata(client);
|
|
||||||
const struct gp2a_platform_data *pdata = dt->pdata;
|
|
||||||
|
|
||||||
free_irq(client->irq, dt);
|
|
||||||
|
|
||||||
input_unregister_device(dt->input);
|
|
||||||
kfree(dt);
|
|
||||||
|
|
||||||
gpio_free(pdata->vout_gpio);
|
|
||||||
|
|
||||||
if (pdata->hw_shutdown)
|
|
||||||
pdata->hw_shutdown(client);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __maybe_unused gp2a_suspend(struct device *dev)
|
|
||||||
{
|
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
|
||||||
struct gp2a_data *dt = i2c_get_clientdata(client);
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
if (device_may_wakeup(&client->dev)) {
|
|
||||||
enable_irq_wake(client->irq);
|
|
||||||
} else {
|
|
||||||
mutex_lock(&dt->input->mutex);
|
|
||||||
if (dt->input->users)
|
|
||||||
retval = gp2a_disable(dt);
|
|
||||||
mutex_unlock(&dt->input->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __maybe_unused gp2a_resume(struct device *dev)
|
|
||||||
{
|
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
|
||||||
struct gp2a_data *dt = i2c_get_clientdata(client);
|
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
if (device_may_wakeup(&client->dev)) {
|
|
||||||
disable_irq_wake(client->irq);
|
|
||||||
} else {
|
|
||||||
mutex_lock(&dt->input->mutex);
|
|
||||||
if (dt->input->users)
|
|
||||||
retval = gp2a_enable(dt);
|
|
||||||
mutex_unlock(&dt->input->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(gp2a_pm, gp2a_suspend, gp2a_resume);
|
|
||||||
|
|
||||||
static const struct i2c_device_id gp2a_i2c_id[] = {
|
|
||||||
{ GP2A_I2C_NAME, 0 },
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(i2c, gp2a_i2c_id);
|
|
||||||
|
|
||||||
static struct i2c_driver gp2a_i2c_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = GP2A_I2C_NAME,
|
|
||||||
.pm = &gp2a_pm,
|
|
||||||
},
|
|
||||||
.probe = gp2a_probe,
|
|
||||||
.remove = gp2a_remove,
|
|
||||||
.id_table = gp2a_i2c_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
module_i2c_driver(gp2a_i2c_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Courtney Cavin <courtney.cavin@sonyericsson.com>");
|
|
||||||
MODULE_DESCRIPTION("Sharp GP2AP002A00F I2C Proximity/Opto sensor driver");
|
|
||||||
MODULE_LICENSE("GPL v2");
|
|
1833
drivers/input/misc/iqs269a.c
Normal file
1833
drivers/input/misc/iqs269a.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,281 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0+
|
|
||||||
/*
|
|
||||||
* Qualcomm MSM vibrator driver
|
|
||||||
*
|
|
||||||
* Copyright (c) 2018 Brian Masney <masneyb@onstation.org>
|
|
||||||
*
|
|
||||||
* Based on qcom,pwm-vibrator.c from:
|
|
||||||
* Copyright (c) 2018 Jonathan Marek <jonathan@marek.ca>
|
|
||||||
*
|
|
||||||
* Based on msm_pwm_vibrator.c from downstream Android sources:
|
|
||||||
* Copyright (C) 2009-2014 LGE, Inc.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/clk.h>
|
|
||||||
#include <linux/err.h>
|
|
||||||
#include <linux/gpio/consumer.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/regulator/consumer.h>
|
|
||||||
|
|
||||||
#define REG_CMD_RCGR 0x00
|
|
||||||
#define REG_CFG_RCGR 0x04
|
|
||||||
#define REG_M 0x08
|
|
||||||
#define REG_N 0x0C
|
|
||||||
#define REG_D 0x10
|
|
||||||
#define REG_CBCR 0x24
|
|
||||||
#define MMSS_CC_M_DEFAULT 1
|
|
||||||
|
|
||||||
struct msm_vibrator {
|
|
||||||
struct input_dev *input;
|
|
||||||
struct mutex mutex;
|
|
||||||
struct work_struct worker;
|
|
||||||
void __iomem *base;
|
|
||||||
struct regulator *vcc;
|
|
||||||
struct clk *clk;
|
|
||||||
struct gpio_desc *enable_gpio;
|
|
||||||
u16 magnitude;
|
|
||||||
bool enabled;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void msm_vibrator_write(struct msm_vibrator *vibrator, int offset,
|
|
||||||
u32 value)
|
|
||||||
{
|
|
||||||
writel(value, vibrator->base + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int msm_vibrator_start(struct msm_vibrator *vibrator)
|
|
||||||
{
|
|
||||||
int d_reg_val, ret = 0;
|
|
||||||
|
|
||||||
mutex_lock(&vibrator->mutex);
|
|
||||||
|
|
||||||
if (!vibrator->enabled) {
|
|
||||||
ret = clk_set_rate(vibrator->clk, 24000);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&vibrator->input->dev,
|
|
||||||
"Failed to set clock rate: %d\n", ret);
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(vibrator->clk);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&vibrator->input->dev,
|
|
||||||
"Failed to enable clock: %d\n", ret);
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = regulator_enable(vibrator->vcc);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&vibrator->input->dev,
|
|
||||||
"Failed to enable regulator: %d\n", ret);
|
|
||||||
clk_disable(vibrator->clk);
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpiod_set_value_cansleep(vibrator->enable_gpio, 1);
|
|
||||||
|
|
||||||
vibrator->enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
d_reg_val = 127 - ((126 * vibrator->magnitude) / 0xffff);
|
|
||||||
msm_vibrator_write(vibrator, REG_CFG_RCGR,
|
|
||||||
(2 << 12) | /* dual edge mode */
|
|
||||||
(0 << 8) | /* cxo */
|
|
||||||
(7 << 0));
|
|
||||||
msm_vibrator_write(vibrator, REG_M, 1);
|
|
||||||
msm_vibrator_write(vibrator, REG_N, 128);
|
|
||||||
msm_vibrator_write(vibrator, REG_D, d_reg_val);
|
|
||||||
msm_vibrator_write(vibrator, REG_CMD_RCGR, 1);
|
|
||||||
msm_vibrator_write(vibrator, REG_CBCR, 1);
|
|
||||||
|
|
||||||
unlock:
|
|
||||||
mutex_unlock(&vibrator->mutex);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void msm_vibrator_stop(struct msm_vibrator *vibrator)
|
|
||||||
{
|
|
||||||
mutex_lock(&vibrator->mutex);
|
|
||||||
|
|
||||||
if (vibrator->enabled) {
|
|
||||||
gpiod_set_value_cansleep(vibrator->enable_gpio, 0);
|
|
||||||
regulator_disable(vibrator->vcc);
|
|
||||||
clk_disable(vibrator->clk);
|
|
||||||
vibrator->enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&vibrator->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void msm_vibrator_worker(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct msm_vibrator *vibrator = container_of(work,
|
|
||||||
struct msm_vibrator,
|
|
||||||
worker);
|
|
||||||
|
|
||||||
if (vibrator->magnitude)
|
|
||||||
msm_vibrator_start(vibrator);
|
|
||||||
else
|
|
||||||
msm_vibrator_stop(vibrator);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int msm_vibrator_play_effect(struct input_dev *dev, void *data,
|
|
||||||
struct ff_effect *effect)
|
|
||||||
{
|
|
||||||
struct msm_vibrator *vibrator = input_get_drvdata(dev);
|
|
||||||
|
|
||||||
mutex_lock(&vibrator->mutex);
|
|
||||||
|
|
||||||
if (effect->u.rumble.strong_magnitude > 0)
|
|
||||||
vibrator->magnitude = effect->u.rumble.strong_magnitude;
|
|
||||||
else
|
|
||||||
vibrator->magnitude = effect->u.rumble.weak_magnitude;
|
|
||||||
|
|
||||||
mutex_unlock(&vibrator->mutex);
|
|
||||||
|
|
||||||
schedule_work(&vibrator->worker);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void msm_vibrator_close(struct input_dev *input)
|
|
||||||
{
|
|
||||||
struct msm_vibrator *vibrator = input_get_drvdata(input);
|
|
||||||
|
|
||||||
cancel_work_sync(&vibrator->worker);
|
|
||||||
msm_vibrator_stop(vibrator);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int msm_vibrator_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
struct msm_vibrator *vibrator;
|
|
||||||
struct resource *res;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL);
|
|
||||||
if (!vibrator)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
vibrator->input = devm_input_allocate_device(&pdev->dev);
|
|
||||||
if (!vibrator->input)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
|
|
||||||
if (IS_ERR(vibrator->vcc)) {
|
|
||||||
if (PTR_ERR(vibrator->vcc) != -EPROBE_DEFER)
|
|
||||||
dev_err(&pdev->dev, "Failed to get regulator: %ld\n",
|
|
||||||
PTR_ERR(vibrator->vcc));
|
|
||||||
return PTR_ERR(vibrator->vcc);
|
|
||||||
}
|
|
||||||
|
|
||||||
vibrator->enable_gpio = devm_gpiod_get(&pdev->dev, "enable",
|
|
||||||
GPIOD_OUT_LOW);
|
|
||||||
if (IS_ERR(vibrator->enable_gpio)) {
|
|
||||||
if (PTR_ERR(vibrator->enable_gpio) != -EPROBE_DEFER)
|
|
||||||
dev_err(&pdev->dev, "Failed to get enable gpio: %ld\n",
|
|
||||||
PTR_ERR(vibrator->enable_gpio));
|
|
||||||
return PTR_ERR(vibrator->enable_gpio);
|
|
||||||
}
|
|
||||||
|
|
||||||
vibrator->clk = devm_clk_get(&pdev->dev, "pwm");
|
|
||||||
if (IS_ERR(vibrator->clk)) {
|
|
||||||
if (PTR_ERR(vibrator->clk) != -EPROBE_DEFER)
|
|
||||||
dev_err(&pdev->dev, "Failed to lookup pwm clock: %ld\n",
|
|
||||||
PTR_ERR(vibrator->clk));
|
|
||||||
return PTR_ERR(vibrator->clk);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
if (!res) {
|
|
||||||
dev_err(&pdev->dev, "Failed to get platform resource\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
vibrator->base = devm_ioremap(&pdev->dev, res->start,
|
|
||||||
resource_size(res));
|
|
||||||
if (!vibrator->base) {
|
|
||||||
dev_err(&pdev->dev, "Failed to iomap resource.\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
vibrator->enabled = false;
|
|
||||||
mutex_init(&vibrator->mutex);
|
|
||||||
INIT_WORK(&vibrator->worker, msm_vibrator_worker);
|
|
||||||
|
|
||||||
vibrator->input->name = "msm-vibrator";
|
|
||||||
vibrator->input->id.bustype = BUS_HOST;
|
|
||||||
vibrator->input->close = msm_vibrator_close;
|
|
||||||
|
|
||||||
input_set_drvdata(vibrator->input, vibrator);
|
|
||||||
input_set_capability(vibrator->input, EV_FF, FF_RUMBLE);
|
|
||||||
|
|
||||||
ret = input_ff_create_memless(vibrator->input, NULL,
|
|
||||||
msm_vibrator_play_effect);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "Failed to create ff memless: %d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = input_register_device(vibrator->input);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&pdev->dev, "Failed to register input device: %d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, vibrator);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __maybe_unused msm_vibrator_suspend(struct device *dev)
|
|
||||||
{
|
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
|
||||||
struct msm_vibrator *vibrator = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
cancel_work_sync(&vibrator->worker);
|
|
||||||
|
|
||||||
if (vibrator->enabled)
|
|
||||||
msm_vibrator_stop(vibrator);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __maybe_unused msm_vibrator_resume(struct device *dev)
|
|
||||||
{
|
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
|
||||||
struct msm_vibrator *vibrator = platform_get_drvdata(pdev);
|
|
||||||
|
|
||||||
if (vibrator->enabled)
|
|
||||||
msm_vibrator_start(vibrator);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(msm_vibrator_pm_ops, msm_vibrator_suspend,
|
|
||||||
msm_vibrator_resume);
|
|
||||||
|
|
||||||
static const struct of_device_id msm_vibrator_of_match[] = {
|
|
||||||
{ .compatible = "qcom,msm8226-vibrator" },
|
|
||||||
{ .compatible = "qcom,msm8974-vibrator" },
|
|
||||||
{},
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, msm_vibrator_of_match);
|
|
||||||
|
|
||||||
static struct platform_driver msm_vibrator_driver = {
|
|
||||||
.probe = msm_vibrator_probe,
|
|
||||||
.driver = {
|
|
||||||
.name = "msm-vibrator",
|
|
||||||
.pm = &msm_vibrator_pm_ops,
|
|
||||||
.of_match_table = of_match_ptr(msm_vibrator_of_match),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
module_platform_driver(msm_vibrator_driver);
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Brian Masney <masneyb@onstation.org>");
|
|
||||||
MODULE_DESCRIPTION("Qualcomm MSM vibrator driver");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
@ -146,7 +146,7 @@ static void xenkbd_handle_mt_event(struct xenkbd_info *info,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case XENKBD_MT_EV_UP:
|
case XENKBD_MT_EV_UP:
|
||||||
input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, false);
|
input_mt_report_slot_inactive(info->mtouch);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XENKBD_MT_EV_SYN:
|
case XENKBD_MT_EV_SYN:
|
||||||
|
@ -938,7 +938,7 @@ static void elan_report_contact(struct elan_tp_data *data,
|
|||||||
input_report_abs(input, ABS_MT_TOUCH_MINOR, minor);
|
input_report_abs(input, ABS_MT_TOUCH_MINOR, minor);
|
||||||
} else {
|
} else {
|
||||||
input_mt_slot(input, contact_num);
|
input_mt_slot(input, contact_num);
|
||||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
|
input_mt_report_slot_inactive(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -945,6 +945,7 @@ static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id *
|
|||||||
}
|
}
|
||||||
i8042_pnp_id_to_string(dev->id, i8042_kbd_firmware_id,
|
i8042_pnp_id_to_string(dev->id, i8042_kbd_firmware_id,
|
||||||
sizeof(i8042_kbd_firmware_id));
|
sizeof(i8042_kbd_firmware_id));
|
||||||
|
i8042_kbd_fwnode = dev_fwnode(&dev->dev);
|
||||||
|
|
||||||
/* Keyboard ports are always supposed to be wakeup-enabled */
|
/* Keyboard ports are always supposed to be wakeup-enabled */
|
||||||
device_set_wakeup_enable(&dev->dev, true);
|
device_set_wakeup_enable(&dev->dev, true);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <linux/i8042.h>
|
#include <linux/i8042.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
|
#include <linux/property.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
@ -124,6 +125,7 @@ MODULE_PARM_DESC(unmask_kbd_data, "Unconditional enable (may reveal sensitive da
|
|||||||
static bool i8042_bypass_aux_irq_test;
|
static bool i8042_bypass_aux_irq_test;
|
||||||
static char i8042_kbd_firmware_id[128];
|
static char i8042_kbd_firmware_id[128];
|
||||||
static char i8042_aux_firmware_id[128];
|
static char i8042_aux_firmware_id[128];
|
||||||
|
static struct fwnode_handle *i8042_kbd_fwnode;
|
||||||
|
|
||||||
#include "i8042.h"
|
#include "i8042.h"
|
||||||
|
|
||||||
@ -1335,6 +1337,7 @@ static int __init i8042_create_kbd_port(void)
|
|||||||
strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
|
strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
|
||||||
strlcpy(serio->firmware_id, i8042_kbd_firmware_id,
|
strlcpy(serio->firmware_id, i8042_kbd_firmware_id,
|
||||||
sizeof(serio->firmware_id));
|
sizeof(serio->firmware_id));
|
||||||
|
set_primary_fwnode(&serio->dev, i8042_kbd_fwnode);
|
||||||
|
|
||||||
port->serio = serio;
|
port->serio = serio;
|
||||||
port->irq = I8042_KBD_IRQ;
|
port->irq = I8042_KBD_IRQ;
|
||||||
|
@ -201,6 +201,18 @@ config TOUCHSCREEN_CHIPONE_ICN8505
|
|||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called chipone_icn8505.
|
module will be called chipone_icn8505.
|
||||||
|
|
||||||
|
config TOUCHSCREEN_CY8CTMA140
|
||||||
|
tristate "cy8ctma140 touchscreen"
|
||||||
|
depends on I2C
|
||||||
|
help
|
||||||
|
Say Y here if you have a Cypress CY8CTMA140 capacitive
|
||||||
|
touchscreen also just known as "TMA140"
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called cy8ctma140.
|
||||||
|
|
||||||
config TOUCHSCREEN_CY8CTMG110
|
config TOUCHSCREEN_CY8CTMG110
|
||||||
tristate "cy8ctmg110 touchscreen"
|
tristate "cy8ctmg110 touchscreen"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
|
@ -22,6 +22,7 @@ obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
|
|||||||
obj-$(CONFIG_TOUCHSCREEN_BU21029) += bu21029_ts.o
|
obj-$(CONFIG_TOUCHSCREEN_BU21029) += bu21029_ts.o
|
||||||
obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8318) += chipone_icn8318.o
|
obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8318) += chipone_icn8318.o
|
||||||
obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8505) += chipone_icn8505.o
|
obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8505) += chipone_icn8505.o
|
||||||
|
obj-$(CONFIG_TOUCHSCREEN_CY8CTMA140) += cy8ctma140.o
|
||||||
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
|
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
|
||||||
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
|
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
|
||||||
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o
|
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o
|
||||||
|
@ -822,8 +822,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
|
|||||||
* have happened.
|
* have happened.
|
||||||
*/
|
*/
|
||||||
if (status & MXT_T9_RELEASE) {
|
if (status & MXT_T9_RELEASE) {
|
||||||
input_mt_report_slot_state(input_dev,
|
input_mt_report_slot_inactive(input_dev);
|
||||||
MT_TOOL_FINGER, 0);
|
|
||||||
mxt_input_sync(data);
|
mxt_input_sync(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,7 +838,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
|
|||||||
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
|
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
|
||||||
} else {
|
} else {
|
||||||
/* Touch no longer active, close out slot */
|
/* Touch no longer active, close out slot */
|
||||||
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 0);
|
input_mt_report_slot_inactive(input_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
data->update_input = true;
|
data->update_input = true;
|
||||||
@ -947,7 +946,7 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
|
|||||||
dev_dbg(dev, "[%u] release\n", id);
|
dev_dbg(dev, "[%u] release\n", id);
|
||||||
|
|
||||||
/* close out slot */
|
/* close out slot */
|
||||||
input_mt_report_slot_state(input_dev, 0, 0);
|
input_mt_report_slot_inactive(input_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
data->update_input = true;
|
data->update_input = true;
|
||||||
|
353
drivers/input/touchscreen/cy8ctma140.c
Normal file
353
drivers/input/touchscreen/cy8ctma140.c
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Driver for Cypress CY8CTMA140 (TMA140) touchscreen
|
||||||
|
* (C) 2020 Linus Walleij <linus.walleij@linaro.org>
|
||||||
|
* (C) 2007 Cypress
|
||||||
|
* (C) 2007 Google, Inc.
|
||||||
|
*
|
||||||
|
* Inspired by the tma140_skomer.c driver in the Samsung GT-S7710 code
|
||||||
|
* drop. The GT-S7710 is codenamed "Skomer", the code also indicates
|
||||||
|
* that the same touchscreen was used in a product called "Lucas".
|
||||||
|
*
|
||||||
|
* The code drop for GT-S7710 also contains a firmware downloader and
|
||||||
|
* 15 (!) versions of the firmware drop from Cypress. But here we assume
|
||||||
|
* the firmware got downloaded to the touchscreen flash successfully and
|
||||||
|
* just use it to read the fingers. The shipped vendor driver does the
|
||||||
|
* same.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/input/touchscreen.h>
|
||||||
|
#include <linux/input/mt.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
#define CY8CTMA140_NAME "cy8ctma140"
|
||||||
|
|
||||||
|
#define CY8CTMA140_MAX_FINGERS 4
|
||||||
|
|
||||||
|
#define CY8CTMA140_GET_FINGERS 0x00
|
||||||
|
#define CY8CTMA140_GET_FW_INFO 0x19
|
||||||
|
|
||||||
|
/* This message also fits some bytes for touchkeys, if used */
|
||||||
|
#define CY8CTMA140_PACKET_SIZE 31
|
||||||
|
|
||||||
|
#define CY8CTMA140_INVALID_BUFFER_BIT 5
|
||||||
|
|
||||||
|
struct cy8ctma140 {
|
||||||
|
struct input_dev *input;
|
||||||
|
struct touchscreen_properties props;
|
||||||
|
struct device *dev;
|
||||||
|
struct i2c_client *client;
|
||||||
|
struct regulator_bulk_data regulators[2];
|
||||||
|
u8 prev_fingers;
|
||||||
|
u8 prev_f1id;
|
||||||
|
u8 prev_f2id;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void cy8ctma140_report(struct cy8ctma140 *ts, u8 *data, int n_fingers)
|
||||||
|
{
|
||||||
|
static const u8 contact_offsets[] = { 0x03, 0x09, 0x10, 0x16 };
|
||||||
|
u8 *buf;
|
||||||
|
u16 x, y;
|
||||||
|
u8 w;
|
||||||
|
u8 id;
|
||||||
|
int slot;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < n_fingers; i++) {
|
||||||
|
buf = &data[contact_offsets[i]];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Odd contacts have contact ID in the lower nibble of
|
||||||
|
* the preceding byte, whereas even contacts have it in
|
||||||
|
* the upper nibble of the following byte.
|
||||||
|
*/
|
||||||
|
id = i % 2 ? buf[-1] & 0x0f : buf[5] >> 4;
|
||||||
|
slot = input_mt_get_slot_by_key(ts->input, id);
|
||||||
|
if (slot < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
x = get_unaligned_be16(buf);
|
||||||
|
y = get_unaligned_be16(buf + 2);
|
||||||
|
w = buf[4];
|
||||||
|
|
||||||
|
dev_dbg(ts->dev, "finger %d: ID %02x (%d, %d) w: %d\n",
|
||||||
|
slot, id, x, y, w);
|
||||||
|
|
||||||
|
input_mt_slot(ts->input, slot);
|
||||||
|
input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true);
|
||||||
|
touchscreen_report_pos(ts->input, &ts->props, x, y, true);
|
||||||
|
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
input_mt_sync_frame(ts->input);
|
||||||
|
input_sync(ts->input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t cy8ctma140_irq_thread(int irq, void *d)
|
||||||
|
{
|
||||||
|
struct cy8ctma140 *ts = d;
|
||||||
|
u8 cmdbuf[] = { CY8CTMA140_GET_FINGERS };
|
||||||
|
u8 buf[CY8CTMA140_PACKET_SIZE];
|
||||||
|
struct i2c_msg msg[] = {
|
||||||
|
{
|
||||||
|
.addr = ts->client->addr,
|
||||||
|
.flags = 0,
|
||||||
|
.len = sizeof(cmdbuf),
|
||||||
|
.buf = cmdbuf,
|
||||||
|
}, {
|
||||||
|
.addr = ts->client->addr,
|
||||||
|
.flags = I2C_M_RD,
|
||||||
|
.len = sizeof(buf),
|
||||||
|
.buf = buf,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
u8 n_fingers;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = i2c_transfer(ts->client->adapter, msg, ARRAY_SIZE(msg));
|
||||||
|
if (ret != ARRAY_SIZE(msg)) {
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(ts->dev, "error reading message: %d\n", ret);
|
||||||
|
else
|
||||||
|
dev_err(ts->dev, "wrong number of messages\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf[1] & BIT(CY8CTMA140_INVALID_BUFFER_BIT)) {
|
||||||
|
dev_dbg(ts->dev, "invalid event\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
n_fingers = buf[2] & 0x0f;
|
||||||
|
if (n_fingers > CY8CTMA140_MAX_FINGERS) {
|
||||||
|
dev_err(ts->dev, "unexpected number of fingers: %d\n",
|
||||||
|
n_fingers);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cy8ctma140_report(ts, buf, n_fingers);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cy8ctma140_init(struct cy8ctma140 *ts)
|
||||||
|
{
|
||||||
|
u8 addr[1];
|
||||||
|
u8 buf[5];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
addr[0] = CY8CTMA140_GET_FW_INFO;
|
||||||
|
ret = i2c_master_send(ts->client, addr, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(ts->dev, "error sending FW info message\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = i2c_master_recv(ts->client, buf, 5);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(ts->dev, "error receiving FW info message\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (ret != 5) {
|
||||||
|
dev_err(ts->dev, "got only %d bytes\n", ret);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(ts->dev, "vendor %c%c, HW ID %.2d, FW ver %.4d\n",
|
||||||
|
buf[0], buf[1], buf[3], buf[4]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cy8ctma140_power_up(struct cy8ctma140 *ts)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = regulator_bulk_enable(ARRAY_SIZE(ts->regulators),
|
||||||
|
ts->regulators);
|
||||||
|
if (error) {
|
||||||
|
dev_err(ts->dev, "failed to enable regulators\n");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
msleep(250);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cy8ctma140_power_down(struct cy8ctma140 *ts)
|
||||||
|
{
|
||||||
|
regulator_bulk_disable(ARRAY_SIZE(ts->regulators),
|
||||||
|
ts->regulators);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called from the registered devm action */
|
||||||
|
static void cy8ctma140_power_off_action(void *d)
|
||||||
|
{
|
||||||
|
struct cy8ctma140 *ts = d;
|
||||||
|
|
||||||
|
cy8ctma140_power_down(ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cy8ctma140_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct cy8ctma140 *ts;
|
||||||
|
struct input_dev *input;
|
||||||
|
struct device *dev = &client->dev;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
|
||||||
|
if (!ts)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
input = devm_input_allocate_device(dev);
|
||||||
|
if (!input)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ts->dev = dev;
|
||||||
|
ts->client = client;
|
||||||
|
ts->input = input;
|
||||||
|
|
||||||
|
input_set_capability(input, EV_ABS, ABS_MT_POSITION_X);
|
||||||
|
input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y);
|
||||||
|
/* One byte for width 0..255 so this is the limit */
|
||||||
|
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
|
||||||
|
/*
|
||||||
|
* This sets up event max/min capabilities and fuzz.
|
||||||
|
* Some DT properties are compulsory so we do not need
|
||||||
|
* to provide defaults for X/Y max or pressure max.
|
||||||
|
*
|
||||||
|
* We just initialize a very simple MT touchscreen here,
|
||||||
|
* some devices use the capability of this touchscreen to
|
||||||
|
* provide touchkeys, and in that case this needs to be
|
||||||
|
* extended to handle touchkey input.
|
||||||
|
*
|
||||||
|
* The firmware takes care of finger tracking and dropping
|
||||||
|
* invalid ranges.
|
||||||
|
*/
|
||||||
|
touchscreen_parse_properties(input, true, &ts->props);
|
||||||
|
input_abs_set_fuzz(input, ABS_MT_POSITION_X, 0);
|
||||||
|
input_abs_set_fuzz(input, ABS_MT_POSITION_Y, 0);
|
||||||
|
|
||||||
|
error = input_mt_init_slots(input, CY8CTMA140_MAX_FINGERS,
|
||||||
|
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
input->name = CY8CTMA140_NAME;
|
||||||
|
input->id.bustype = BUS_I2C;
|
||||||
|
input_set_drvdata(input, ts);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VCPIN is the analog voltage supply
|
||||||
|
* VDD is the digital voltage supply
|
||||||
|
* since the voltage range of VDD overlaps that of VCPIN,
|
||||||
|
* many designs to just supply both with a single voltage
|
||||||
|
* source of ~3.3 V.
|
||||||
|
*/
|
||||||
|
ts->regulators[0].supply = "vcpin";
|
||||||
|
ts->regulators[1].supply = "vdd";
|
||||||
|
error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators),
|
||||||
|
ts->regulators);
|
||||||
|
if (error) {
|
||||||
|
if (error != -EPROBE_DEFER)
|
||||||
|
dev_err(dev, "Failed to get regulators %d\n",
|
||||||
|
error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = cy8ctma140_power_up(ts);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
error = devm_add_action_or_reset(dev, cy8ctma140_power_off_action, ts);
|
||||||
|
if (error) {
|
||||||
|
dev_err(dev, "failed to install power off handler\n");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = devm_request_threaded_irq(dev, client->irq,
|
||||||
|
NULL, cy8ctma140_irq_thread,
|
||||||
|
IRQF_ONESHOT, CY8CTMA140_NAME, ts);
|
||||||
|
if (error) {
|
||||||
|
dev_err(dev, "irq %d busy? error %d\n", client->irq, error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = cy8ctma140_init(ts);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
error = input_register_device(input);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, ts);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused cy8ctma140_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct cy8ctma140 *ts = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
if (!device_may_wakeup(&client->dev))
|
||||||
|
cy8ctma140_power_down(ts);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused cy8ctma140_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct cy8ctma140 *ts = i2c_get_clientdata(client);
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (!device_may_wakeup(&client->dev)) {
|
||||||
|
error = cy8ctma140_power_up(ts);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(cy8ctma140_pm, cy8ctma140_suspend, cy8ctma140_resume);
|
||||||
|
|
||||||
|
static const struct i2c_device_id cy8ctma140_idtable[] = {
|
||||||
|
{ CY8CTMA140_NAME, 0 },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, cy8ctma140_idtable);
|
||||||
|
|
||||||
|
static const struct of_device_id cy8ctma140_of_match[] = {
|
||||||
|
{ .compatible = "cypress,cy8ctma140", },
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, cy8ctma140_of_match);
|
||||||
|
|
||||||
|
static struct i2c_driver cy8ctma140_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = CY8CTMA140_NAME,
|
||||||
|
.pm = &cy8ctma140_pm,
|
||||||
|
.of_match_table = cy8ctma140_of_match,
|
||||||
|
},
|
||||||
|
.id_table = cy8ctma140_idtable,
|
||||||
|
.probe = cy8ctma140_probe,
|
||||||
|
};
|
||||||
|
module_i2c_driver(cy8ctma140_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
|
||||||
|
MODULE_DESCRIPTION("CY8CTMA140 TouchScreen Driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -744,8 +744,7 @@ static void cyttsp4_report_slot_liftoff(struct cyttsp4_mt_data *md,
|
|||||||
|
|
||||||
for (t = 0; t < max_slots; t++) {
|
for (t = 0; t < max_slots; t++) {
|
||||||
input_mt_slot(md->input, t);
|
input_mt_slot(md->input, t);
|
||||||
input_mt_report_slot_state(md->input,
|
input_mt_report_slot_inactive(md->input);
|
||||||
MT_TOOL_FINGER, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -845,7 +844,7 @@ static void cyttsp4_final_sync(struct input_dev *input, int max_slots, int *ids)
|
|||||||
if (ids[t])
|
if (ids[t])
|
||||||
continue;
|
continue;
|
||||||
input_mt_slot(input, t);
|
input_mt_slot(input, t);
|
||||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
|
input_mt_report_slot_inactive(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_sync(input);
|
input_sync(input);
|
||||||
|
@ -340,7 +340,7 @@ static void cyttsp_report_tchdata(struct cyttsp *ts)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
input_mt_slot(input, i);
|
input_mt_slot(input, i);
|
||||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
|
input_mt_report_slot_inactive(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_sync(input);
|
input_sync(input);
|
||||||
|
@ -38,6 +38,9 @@
|
|||||||
#define WORK_REGISTER_NUM_X 0x33
|
#define WORK_REGISTER_NUM_X 0x33
|
||||||
#define WORK_REGISTER_NUM_Y 0x34
|
#define WORK_REGISTER_NUM_Y 0x34
|
||||||
|
|
||||||
|
#define PMOD_REGISTER_ACTIVE 0x00
|
||||||
|
#define PMOD_REGISTER_HIBERNATE 0x03
|
||||||
|
|
||||||
#define M09_REGISTER_THRESHOLD 0x80
|
#define M09_REGISTER_THRESHOLD 0x80
|
||||||
#define M09_REGISTER_GAIN 0x92
|
#define M09_REGISTER_GAIN 0x92
|
||||||
#define M09_REGISTER_OFFSET 0x93
|
#define M09_REGISTER_OFFSET 0x93
|
||||||
@ -53,6 +56,7 @@
|
|||||||
|
|
||||||
#define WORK_REGISTER_OPMODE 0x3c
|
#define WORK_REGISTER_OPMODE 0x3c
|
||||||
#define FACTORY_REGISTER_OPMODE 0x01
|
#define FACTORY_REGISTER_OPMODE 0x01
|
||||||
|
#define PMOD_REGISTER_OPMODE 0xa5
|
||||||
|
|
||||||
#define TOUCH_EVENT_DOWN 0x00
|
#define TOUCH_EVENT_DOWN 0x00
|
||||||
#define TOUCH_EVENT_UP 0x01
|
#define TOUCH_EVENT_UP 0x01
|
||||||
@ -65,6 +69,12 @@
|
|||||||
#define EDT_RAW_DATA_RETRIES 100
|
#define EDT_RAW_DATA_RETRIES 100
|
||||||
#define EDT_RAW_DATA_DELAY 1000 /* usec */
|
#define EDT_RAW_DATA_DELAY 1000 /* usec */
|
||||||
|
|
||||||
|
enum edt_pmode {
|
||||||
|
EDT_PMODE_NOT_SUPPORTED,
|
||||||
|
EDT_PMODE_HIBERNATE,
|
||||||
|
EDT_PMODE_POWEROFF,
|
||||||
|
};
|
||||||
|
|
||||||
enum edt_ver {
|
enum edt_ver {
|
||||||
EDT_M06,
|
EDT_M06,
|
||||||
EDT_M09,
|
EDT_M09,
|
||||||
@ -103,6 +113,7 @@ struct edt_ft5x06_ts_data {
|
|||||||
|
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
bool factory_mode;
|
bool factory_mode;
|
||||||
|
enum edt_pmode suspend_mode;
|
||||||
int threshold;
|
int threshold;
|
||||||
int gain;
|
int gain;
|
||||||
int offset;
|
int offset;
|
||||||
@ -527,6 +538,29 @@ static const struct attribute_group edt_ft5x06_attr_group = {
|
|||||||
.attrs = edt_ft5x06_attrs,
|
.attrs = edt_ft5x06_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata)
|
||||||
|
{
|
||||||
|
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
|
||||||
|
|
||||||
|
edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold,
|
||||||
|
tsdata->threshold);
|
||||||
|
edt_ft5x06_register_write(tsdata, reg_addr->reg_gain,
|
||||||
|
tsdata->gain);
|
||||||
|
if (reg_addr->reg_offset != NO_REGISTER)
|
||||||
|
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,
|
||||||
|
tsdata->offset);
|
||||||
|
if (reg_addr->reg_offset_x != NO_REGISTER)
|
||||||
|
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x,
|
||||||
|
tsdata->offset_x);
|
||||||
|
if (reg_addr->reg_offset_y != NO_REGISTER)
|
||||||
|
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y,
|
||||||
|
tsdata->offset_y);
|
||||||
|
if (reg_addr->reg_report_rate != NO_REGISTER)
|
||||||
|
edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate,
|
||||||
|
tsdata->report_rate);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
|
static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
|
||||||
{
|
{
|
||||||
@ -592,7 +626,6 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
|
|||||||
{
|
{
|
||||||
struct i2c_client *client = tsdata->client;
|
struct i2c_client *client = tsdata->client;
|
||||||
int retries = EDT_SWITCH_MODE_RETRIES;
|
int retries = EDT_SWITCH_MODE_RETRIES;
|
||||||
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
|
|
||||||
int ret;
|
int ret;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -624,24 +657,7 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
|
|||||||
kfree(tsdata->raw_buffer);
|
kfree(tsdata->raw_buffer);
|
||||||
tsdata->raw_buffer = NULL;
|
tsdata->raw_buffer = NULL;
|
||||||
|
|
||||||
/* restore parameters */
|
edt_ft5x06_restore_reg_parameters(tsdata);
|
||||||
edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold,
|
|
||||||
tsdata->threshold);
|
|
||||||
edt_ft5x06_register_write(tsdata, reg_addr->reg_gain,
|
|
||||||
tsdata->gain);
|
|
||||||
if (reg_addr->reg_offset != NO_REGISTER)
|
|
||||||
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,
|
|
||||||
tsdata->offset);
|
|
||||||
if (reg_addr->reg_offset_x != NO_REGISTER)
|
|
||||||
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x,
|
|
||||||
tsdata->offset_x);
|
|
||||||
if (reg_addr->reg_offset_y != NO_REGISTER)
|
|
||||||
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y,
|
|
||||||
tsdata->offset_y);
|
|
||||||
if (reg_addr->reg_report_rate != NO_REGISTER)
|
|
||||||
edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate,
|
|
||||||
tsdata->report_rate);
|
|
||||||
|
|
||||||
enable_irq(client->irq);
|
enable_irq(client->irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -762,9 +778,8 @@ static const struct file_operations debugfs_raw_data_fops = {
|
|||||||
.read = edt_ft5x06_debugfs_raw_data_read,
|
.read = edt_ft5x06_debugfs_raw_data_read,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
|
||||||
edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
|
const char *debugfs_name)
|
||||||
const char *debugfs_name)
|
|
||||||
{
|
{
|
||||||
tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
|
tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
|
||||||
|
|
||||||
@ -777,8 +792,7 @@ edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
|
|||||||
tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
|
tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
|
||||||
edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
|
|
||||||
{
|
{
|
||||||
debugfs_remove_recursive(tsdata->debug_dir);
|
debugfs_remove_recursive(tsdata->debug_dir);
|
||||||
kfree(tsdata->raw_buffer);
|
kfree(tsdata->raw_buffer);
|
||||||
@ -786,14 +800,17 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline void
|
static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
|
||||||
edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
|
{
|
||||||
const char *debugfs_name)
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
|
||||||
|
const char *debugfs_name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
|
||||||
edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,19 +955,25 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev,
|
|||||||
|
|
||||||
error = device_property_read_u32(dev, "offset", &val);
|
error = device_property_read_u32(dev, "offset", &val);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, val);
|
if (reg_addr->reg_offset != NO_REGISTER)
|
||||||
|
edt_ft5x06_register_write(tsdata,
|
||||||
|
reg_addr->reg_offset, val);
|
||||||
tsdata->offset = val;
|
tsdata->offset = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = device_property_read_u32(dev, "offset-x", &val);
|
error = device_property_read_u32(dev, "offset-x", &val);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, val);
|
if (reg_addr->reg_offset_x != NO_REGISTER)
|
||||||
|
edt_ft5x06_register_write(tsdata,
|
||||||
|
reg_addr->reg_offset_x, val);
|
||||||
tsdata->offset_x = val;
|
tsdata->offset_x = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = device_property_read_u32(dev, "offset-y", &val);
|
error = device_property_read_u32(dev, "offset-y", &val);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, val);
|
if (reg_addr->reg_offset_y != NO_REGISTER)
|
||||||
|
edt_ft5x06_register_write(tsdata,
|
||||||
|
reg_addr->reg_offset_y, val);
|
||||||
tsdata->offset_y = val;
|
tsdata->offset_y = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1114,6 +1137,19 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check which sleep modes we can support. Power-off requieres the
|
||||||
|
* reset-pin to ensure correct power-down/power-up behaviour. Start with
|
||||||
|
* the EDT_PMODE_POWEROFF test since this is the deepest possible sleep
|
||||||
|
* mode.
|
||||||
|
*/
|
||||||
|
if (tsdata->reset_gpio)
|
||||||
|
tsdata->suspend_mode = EDT_PMODE_POWEROFF;
|
||||||
|
else if (tsdata->wake_gpio)
|
||||||
|
tsdata->suspend_mode = EDT_PMODE_HIBERNATE;
|
||||||
|
else
|
||||||
|
tsdata->suspend_mode = EDT_PMODE_NOT_SUPPORTED;
|
||||||
|
|
||||||
if (tsdata->wake_gpio) {
|
if (tsdata->wake_gpio) {
|
||||||
usleep_range(5000, 6000);
|
usleep_range(5000, 6000);
|
||||||
gpiod_set_value_cansleep(tsdata->wake_gpio, 1);
|
gpiod_set_value_cansleep(tsdata->wake_gpio, 1);
|
||||||
@ -1227,6 +1263,102 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
|
||||||
|
struct gpio_desc *reset_gpio = tsdata->reset_gpio;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (device_may_wakeup(dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (tsdata->suspend_mode == EDT_PMODE_NOT_SUPPORTED)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Enter hibernate mode. */
|
||||||
|
ret = edt_ft5x06_register_write(tsdata, PMOD_REGISTER_OPMODE,
|
||||||
|
PMOD_REGISTER_HIBERNATE);
|
||||||
|
if (ret)
|
||||||
|
dev_warn(dev, "Failed to set hibernate mode\n");
|
||||||
|
|
||||||
|
if (tsdata->suspend_mode == EDT_PMODE_HIBERNATE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Power-off according the datasheet. Cut the power may leaf the irq
|
||||||
|
* line in an undefined state depending on the host pull resistor
|
||||||
|
* settings. Disable the irq to avoid adjusting each host till the
|
||||||
|
* device is back in a full functional state.
|
||||||
|
*/
|
||||||
|
disable_irq(tsdata->client->irq);
|
||||||
|
|
||||||
|
gpiod_set_value_cansleep(reset_gpio, 1);
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
|
||||||
|
ret = regulator_disable(tsdata->vcc);
|
||||||
|
if (ret)
|
||||||
|
dev_warn(dev, "Failed to disable vcc\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (device_may_wakeup(dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (tsdata->suspend_mode == EDT_PMODE_NOT_SUPPORTED)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (tsdata->suspend_mode == EDT_PMODE_POWEROFF) {
|
||||||
|
struct gpio_desc *reset_gpio = tsdata->reset_gpio;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can't check if the regulator is a dummy or a real
|
||||||
|
* regulator. So we need to specify the 5ms reset time (T_rst)
|
||||||
|
* here instead of the 100us T_rtp time. We also need to wait
|
||||||
|
* 300ms in case it was a real supply and the power was cutted
|
||||||
|
* of. Toggle the reset pin is also a way to exit the hibernate
|
||||||
|
* mode.
|
||||||
|
*/
|
||||||
|
gpiod_set_value_cansleep(reset_gpio, 1);
|
||||||
|
usleep_range(5000, 6000);
|
||||||
|
|
||||||
|
ret = regulator_enable(tsdata->vcc);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to enable vcc\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep_range(1000, 2000);
|
||||||
|
gpiod_set_value_cansleep(reset_gpio, 0);
|
||||||
|
msleep(300);
|
||||||
|
|
||||||
|
edt_ft5x06_restore_reg_parameters(tsdata);
|
||||||
|
enable_irq(tsdata->client->irq);
|
||||||
|
|
||||||
|
if (tsdata->factory_mode)
|
||||||
|
ret = edt_ft5x06_factory_mode(tsdata);
|
||||||
|
} else {
|
||||||
|
struct gpio_desc *wake_gpio = tsdata->wake_gpio;
|
||||||
|
|
||||||
|
gpiod_set_value_cansleep(wake_gpio, 0);
|
||||||
|
usleep_range(5000, 6000);
|
||||||
|
gpiod_set_value_cansleep(wake_gpio, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
|
||||||
|
edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
|
||||||
|
|
||||||
static const struct edt_i2c_chip_data edt_ft5x06_data = {
|
static const struct edt_i2c_chip_data edt_ft5x06_data = {
|
||||||
.max_support_points = 5,
|
.max_support_points = 5,
|
||||||
};
|
};
|
||||||
@ -1265,6 +1397,8 @@ static struct i2c_driver edt_ft5x06_ts_driver = {
|
|||||||
.driver = {
|
.driver = {
|
||||||
.name = "edt_ft5x06",
|
.name = "edt_ft5x06",
|
||||||
.of_match_table = edt_ft5x06_of_match,
|
.of_match_table = edt_ft5x06_of_match,
|
||||||
|
.pm = &edt_ft5x06_ts_pm_ops,
|
||||||
|
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||||
},
|
},
|
||||||
.id_table = edt_ft5x06_ts_id,
|
.id_table = edt_ft5x06_ts_id,
|
||||||
.probe = edt_ft5x06_ts_probe,
|
.probe = edt_ft5x06_ts_probe,
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
#include <linux/input/mt.h>
|
#include <linux/input/mt.h>
|
||||||
|
#include <linux/input/touchscreen.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
@ -89,6 +90,7 @@
|
|||||||
/* FW read command, 0x53 0x?? 0x0, 0x01 */
|
/* FW read command, 0x53 0x?? 0x0, 0x01 */
|
||||||
#define E_ELAN_INFO_FW_VER 0x00
|
#define E_ELAN_INFO_FW_VER 0x00
|
||||||
#define E_ELAN_INFO_BC_VER 0x10
|
#define E_ELAN_INFO_BC_VER 0x10
|
||||||
|
#define E_ELAN_INFO_REK 0xE0
|
||||||
#define E_ELAN_INFO_TEST_VER 0xE0
|
#define E_ELAN_INFO_TEST_VER 0xE0
|
||||||
#define E_ELAN_INFO_FW_ID 0xF0
|
#define E_ELAN_INFO_FW_ID 0xF0
|
||||||
#define E_INFO_OSR 0xD6
|
#define E_INFO_OSR 0xD6
|
||||||
@ -136,6 +138,7 @@ struct elants_data {
|
|||||||
unsigned int y_res;
|
unsigned int y_res;
|
||||||
unsigned int x_max;
|
unsigned int x_max;
|
||||||
unsigned int y_max;
|
unsigned int y_max;
|
||||||
|
struct touchscreen_properties prop;
|
||||||
|
|
||||||
enum elants_state state;
|
enum elants_state state;
|
||||||
enum elants_iap_mode iap_mode;
|
enum elants_iap_mode iap_mode;
|
||||||
@ -189,7 +192,8 @@ static int elants_i2c_read(struct i2c_client *client, void *data, size_t size)
|
|||||||
|
|
||||||
static int elants_i2c_execute_command(struct i2c_client *client,
|
static int elants_i2c_execute_command(struct i2c_client *client,
|
||||||
const u8 *cmd, size_t cmd_size,
|
const u8 *cmd, size_t cmd_size,
|
||||||
u8 *resp, size_t resp_size)
|
u8 *resp, size_t resp_size,
|
||||||
|
int retries, const char *cmd_name)
|
||||||
{
|
{
|
||||||
struct i2c_msg msgs[2];
|
struct i2c_msg msgs[2];
|
||||||
int ret;
|
int ret;
|
||||||
@ -209,30 +213,55 @@ static int elants_i2c_execute_command(struct i2c_client *client,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dev_err(&client->dev, "%s: invalid command %*ph\n",
|
dev_err(&client->dev, "(%s): invalid command: %*ph\n",
|
||||||
__func__, (int)cmd_size, cmd);
|
cmd_name, (int)cmd_size, cmd);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
msgs[0].addr = client->addr;
|
for (;;) {
|
||||||
msgs[0].flags = client->flags & I2C_M_TEN;
|
msgs[0].addr = client->addr;
|
||||||
msgs[0].len = cmd_size;
|
msgs[0].flags = client->flags & I2C_M_TEN;
|
||||||
msgs[0].buf = (u8 *)cmd;
|
msgs[0].len = cmd_size;
|
||||||
|
msgs[0].buf = (u8 *)cmd;
|
||||||
|
|
||||||
msgs[1].addr = client->addr;
|
msgs[1].addr = client->addr;
|
||||||
msgs[1].flags = client->flags & I2C_M_TEN;
|
msgs[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
|
||||||
msgs[1].flags |= I2C_M_RD;
|
msgs[1].flags |= I2C_M_RD;
|
||||||
msgs[1].len = resp_size;
|
msgs[1].len = resp_size;
|
||||||
msgs[1].buf = resp;
|
msgs[1].buf = resp;
|
||||||
|
|
||||||
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
return ret;
|
if (--retries > 0) {
|
||||||
|
dev_dbg(&client->dev,
|
||||||
|
"(%s) I2C transfer failed: %pe (retrying)\n",
|
||||||
|
cmd_name, ERR_PTR(ret));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret != ARRAY_SIZE(msgs) || resp[FW_HDR_TYPE] != expected_response)
|
dev_err(&client->dev,
|
||||||
return -EIO;
|
"(%s) I2C transfer failed: %pe\n",
|
||||||
|
cmd_name, ERR_PTR(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
if (ret != ARRAY_SIZE(msgs) ||
|
||||||
|
resp[FW_HDR_TYPE] != expected_response) {
|
||||||
|
if (--retries > 0) {
|
||||||
|
dev_dbg(&client->dev,
|
||||||
|
"(%s) unexpected response: %*ph (retrying)\n",
|
||||||
|
cmd_name, ret, resp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"(%s) unexpected response: %*ph\n",
|
||||||
|
cmd_name, ret, resp);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int elants_i2c_calibrate(struct elants_data *ts)
|
static int elants_i2c_calibrate(struct elants_data *ts)
|
||||||
@ -305,27 +334,21 @@ static u16 elants_i2c_parse_version(u8 *buf)
|
|||||||
static int elants_i2c_query_hw_version(struct elants_data *ts)
|
static int elants_i2c_query_hw_version(struct elants_data *ts)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = ts->client;
|
struct i2c_client *client = ts->client;
|
||||||
int error, retry_cnt;
|
int retry_cnt = MAX_RETRIES;
|
||||||
const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_ID, 0x00, 0x01 };
|
const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_ID, 0x00, 0x01 };
|
||||||
u8 resp[HEADER_SIZE];
|
u8 resp[HEADER_SIZE];
|
||||||
|
int error;
|
||||||
|
|
||||||
for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) {
|
while (retry_cnt--) {
|
||||||
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
||||||
resp, sizeof(resp));
|
resp, sizeof(resp), 1,
|
||||||
if (!error) {
|
"read fw id");
|
||||||
ts->hw_version = elants_i2c_parse_version(resp);
|
if (error)
|
||||||
if (ts->hw_version != 0xffff)
|
return error;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(&client->dev, "read fw id error=%d, buf=%*phC\n",
|
ts->hw_version = elants_i2c_parse_version(resp);
|
||||||
error, (int)sizeof(resp), resp);
|
if (ts->hw_version != 0xffff)
|
||||||
}
|
return 0;
|
||||||
|
|
||||||
if (error) {
|
|
||||||
dev_err(&client->dev,
|
|
||||||
"Failed to read fw id: %d\n", error);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_err(&client->dev, "Invalid fw id: %#04x\n", ts->hw_version);
|
dev_err(&client->dev, "Invalid fw id: %#04x\n", ts->hw_version);
|
||||||
@ -336,26 +359,27 @@ static int elants_i2c_query_hw_version(struct elants_data *ts)
|
|||||||
static int elants_i2c_query_fw_version(struct elants_data *ts)
|
static int elants_i2c_query_fw_version(struct elants_data *ts)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = ts->client;
|
struct i2c_client *client = ts->client;
|
||||||
int error, retry_cnt;
|
int retry_cnt = MAX_RETRIES;
|
||||||
const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_VER, 0x00, 0x01 };
|
const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_VER, 0x00, 0x01 };
|
||||||
u8 resp[HEADER_SIZE];
|
u8 resp[HEADER_SIZE];
|
||||||
|
int error;
|
||||||
|
|
||||||
for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) {
|
while (retry_cnt--) {
|
||||||
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
||||||
resp, sizeof(resp));
|
resp, sizeof(resp), 1,
|
||||||
if (!error) {
|
"read fw version");
|
||||||
ts->fw_version = elants_i2c_parse_version(resp);
|
if (error)
|
||||||
if (ts->fw_version != 0x0000 &&
|
return error;
|
||||||
ts->fw_version != 0xffff)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(&client->dev, "read fw version error=%d, buf=%*phC\n",
|
ts->fw_version = elants_i2c_parse_version(resp);
|
||||||
error, (int)sizeof(resp), resp);
|
if (ts->fw_version != 0x0000 && ts->fw_version != 0xffff)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dev_dbg(&client->dev, "(read fw version) resp %*phC\n",
|
||||||
|
(int)sizeof(resp), resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_err(&client->dev,
|
dev_err(&client->dev, "Invalid fw ver: %#04x\n", ts->fw_version);
|
||||||
"Failed to read fw version or fw version is invalid\n");
|
|
||||||
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -363,30 +387,24 @@ static int elants_i2c_query_fw_version(struct elants_data *ts)
|
|||||||
static int elants_i2c_query_test_version(struct elants_data *ts)
|
static int elants_i2c_query_test_version(struct elants_data *ts)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = ts->client;
|
struct i2c_client *client = ts->client;
|
||||||
int error, retry_cnt;
|
int error;
|
||||||
u16 version;
|
u16 version;
|
||||||
const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_TEST_VER, 0x00, 0x01 };
|
const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_TEST_VER, 0x00, 0x01 };
|
||||||
u8 resp[HEADER_SIZE];
|
u8 resp[HEADER_SIZE];
|
||||||
|
|
||||||
for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) {
|
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
||||||
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
resp, sizeof(resp), MAX_RETRIES,
|
||||||
resp, sizeof(resp));
|
"read test version");
|
||||||
if (!error) {
|
if (error) {
|
||||||
version = elants_i2c_parse_version(resp);
|
dev_err(&client->dev, "Failed to read test version\n");
|
||||||
ts->test_version = version >> 8;
|
return error;
|
||||||
ts->solution_version = version & 0xff;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(&client->dev,
|
|
||||||
"read test version error rc=%d, buf=%*phC\n",
|
|
||||||
error, (int)sizeof(resp), resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_err(&client->dev, "Failed to read test version\n");
|
version = elants_i2c_parse_version(resp);
|
||||||
|
ts->test_version = version >> 8;
|
||||||
|
ts->solution_version = version & 0xff;
|
||||||
|
|
||||||
return -EINVAL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int elants_i2c_query_bc_version(struct elants_data *ts)
|
static int elants_i2c_query_bc_version(struct elants_data *ts)
|
||||||
@ -398,13 +416,10 @@ static int elants_i2c_query_bc_version(struct elants_data *ts)
|
|||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
||||||
resp, sizeof(resp));
|
resp, sizeof(resp), 1,
|
||||||
if (error) {
|
"read BC version");
|
||||||
dev_err(&client->dev,
|
if (error)
|
||||||
"read BC version error=%d, buf=%*phC\n",
|
|
||||||
error, (int)sizeof(resp), resp);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
|
|
||||||
version = elants_i2c_parse_version(resp);
|
version = elants_i2c_parse_version(resp);
|
||||||
ts->bc_version = version >> 8;
|
ts->bc_version = version >> 8;
|
||||||
@ -436,12 +451,10 @@ static int elants_i2c_query_ts_info(struct elants_data *ts)
|
|||||||
error = elants_i2c_execute_command(client,
|
error = elants_i2c_execute_command(client,
|
||||||
get_resolution_cmd,
|
get_resolution_cmd,
|
||||||
sizeof(get_resolution_cmd),
|
sizeof(get_resolution_cmd),
|
||||||
resp, sizeof(resp));
|
resp, sizeof(resp), 1,
|
||||||
if (error) {
|
"get resolution");
|
||||||
dev_err(&client->dev, "get resolution command failed: %d\n",
|
if (error)
|
||||||
error);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
|
|
||||||
rows = resp[2] + resp[6] + resp[10];
|
rows = resp[2] + resp[6] + resp[10];
|
||||||
cols = resp[3] + resp[7] + resp[11];
|
cols = resp[3] + resp[7] + resp[11];
|
||||||
@ -449,36 +462,29 @@ static int elants_i2c_query_ts_info(struct elants_data *ts)
|
|||||||
/* Process mm_to_pixel information */
|
/* Process mm_to_pixel information */
|
||||||
error = elants_i2c_execute_command(client,
|
error = elants_i2c_execute_command(client,
|
||||||
get_osr_cmd, sizeof(get_osr_cmd),
|
get_osr_cmd, sizeof(get_osr_cmd),
|
||||||
resp, sizeof(resp));
|
resp, sizeof(resp), 1, "get osr");
|
||||||
if (error) {
|
if (error)
|
||||||
dev_err(&client->dev, "get osr command failed: %d\n",
|
|
||||||
error);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
|
|
||||||
osr = resp[3];
|
osr = resp[3];
|
||||||
|
|
||||||
error = elants_i2c_execute_command(client,
|
error = elants_i2c_execute_command(client,
|
||||||
get_physical_scan_cmd,
|
get_physical_scan_cmd,
|
||||||
sizeof(get_physical_scan_cmd),
|
sizeof(get_physical_scan_cmd),
|
||||||
resp, sizeof(resp));
|
resp, sizeof(resp), 1,
|
||||||
if (error) {
|
"get physical scan");
|
||||||
dev_err(&client->dev, "get physical scan command failed: %d\n",
|
if (error)
|
||||||
error);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
|
|
||||||
phy_x = get_unaligned_be16(&resp[2]);
|
phy_x = get_unaligned_be16(&resp[2]);
|
||||||
|
|
||||||
error = elants_i2c_execute_command(client,
|
error = elants_i2c_execute_command(client,
|
||||||
get_physical_drive_cmd,
|
get_physical_drive_cmd,
|
||||||
sizeof(get_physical_drive_cmd),
|
sizeof(get_physical_drive_cmd),
|
||||||
resp, sizeof(resp));
|
resp, sizeof(resp), 1,
|
||||||
if (error) {
|
"get physical drive");
|
||||||
dev_err(&client->dev, "get physical drive command failed: %d\n",
|
if (error)
|
||||||
error);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
|
|
||||||
phy_y = get_unaligned_be16(&resp[2]);
|
phy_y = get_unaligned_be16(&resp[2]);
|
||||||
|
|
||||||
@ -633,11 +639,10 @@ static int elants_i2c_validate_remark_id(struct elants_data *ts,
|
|||||||
|
|
||||||
/* Compare TS Remark ID and FW Remark ID */
|
/* Compare TS Remark ID and FW Remark ID */
|
||||||
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
||||||
resp, sizeof(resp));
|
resp, sizeof(resp),
|
||||||
if (error) {
|
1, "read Remark ID");
|
||||||
dev_err(&client->dev, "failed to query Remark ID: %d\n", error);
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
|
|
||||||
ts_remark_id = get_unaligned_be16(&resp[3]);
|
ts_remark_id = get_unaligned_be16(&resp[3]);
|
||||||
|
|
||||||
@ -875,8 +880,7 @@ static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf)
|
|||||||
|
|
||||||
input_mt_slot(input, i);
|
input_mt_slot(input, i);
|
||||||
input_mt_report_slot_state(input, tool_type, true);
|
input_mt_report_slot_state(input, tool_type, true);
|
||||||
input_event(input, EV_ABS, ABS_MT_POSITION_X, x);
|
touchscreen_report_pos(input, &ts->prop, x, y, true);
|
||||||
input_event(input, EV_ABS, ABS_MT_POSITION_Y, y);
|
|
||||||
input_event(input, EV_ABS, ABS_MT_PRESSURE, p);
|
input_event(input, EV_ABS, ABS_MT_PRESSURE, p);
|
||||||
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, w);
|
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, w);
|
||||||
|
|
||||||
@ -1017,7 +1021,7 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
|
|||||||
*/
|
*/
|
||||||
static ssize_t calibrate_store(struct device *dev,
|
static ssize_t calibrate_store(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct elants_data *ts = i2c_get_clientdata(client);
|
struct elants_data *ts = i2c_get_clientdata(client);
|
||||||
@ -1063,8 +1067,28 @@ static ssize_t show_iap_mode(struct device *dev,
|
|||||||
"Normal" : "Recovery");
|
"Normal" : "Recovery");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t show_calibration_count(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_REK, 0x00, 0x01 };
|
||||||
|
u8 resp[HEADER_SIZE];
|
||||||
|
u16 rek_count;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
||||||
|
resp, sizeof(resp), 1,
|
||||||
|
"read ReK status");
|
||||||
|
if (error)
|
||||||
|
return sprintf(buf, "%d\n", error);
|
||||||
|
|
||||||
|
rek_count = get_unaligned_be16(&resp[2]);
|
||||||
|
return sprintf(buf, "0x%04x\n", rek_count);
|
||||||
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR_WO(calibrate);
|
static DEVICE_ATTR_WO(calibrate);
|
||||||
static DEVICE_ATTR(iap_mode, S_IRUGO, show_iap_mode, NULL);
|
static DEVICE_ATTR(iap_mode, S_IRUGO, show_iap_mode, NULL);
|
||||||
|
static DEVICE_ATTR(calibration_count, S_IRUGO, show_calibration_count, NULL);
|
||||||
static DEVICE_ATTR(update_fw, S_IWUSR, NULL, write_update_fw);
|
static DEVICE_ATTR(update_fw, S_IWUSR, NULL, write_update_fw);
|
||||||
|
|
||||||
struct elants_version_attribute {
|
struct elants_version_attribute {
|
||||||
@ -1120,6 +1144,7 @@ static struct attribute *elants_attributes[] = {
|
|||||||
&dev_attr_calibrate.attr,
|
&dev_attr_calibrate.attr,
|
||||||
&dev_attr_update_fw.attr,
|
&dev_attr_update_fw.attr,
|
||||||
&dev_attr_iap_mode.attr,
|
&dev_attr_iap_mode.attr,
|
||||||
|
&dev_attr_calibration_count.attr,
|
||||||
|
|
||||||
&elants_ver_attr_fw_version.dattr.attr,
|
&elants_ver_attr_fw_version.dattr.attr,
|
||||||
&elants_ver_attr_hw_version.dattr.attr,
|
&elants_ver_attr_hw_version.dattr.attr,
|
||||||
@ -1290,25 +1315,7 @@ static int elants_i2c_probe(struct i2c_client *client,
|
|||||||
ts->input->name = "Elan Touchscreen";
|
ts->input->name = "Elan Touchscreen";
|
||||||
ts->input->id.bustype = BUS_I2C;
|
ts->input->id.bustype = BUS_I2C;
|
||||||
|
|
||||||
__set_bit(BTN_TOUCH, ts->input->keybit);
|
|
||||||
__set_bit(EV_ABS, ts->input->evbit);
|
|
||||||
__set_bit(EV_KEY, ts->input->evbit);
|
|
||||||
|
|
||||||
/* Single touch input params setup */
|
|
||||||
input_set_abs_params(ts->input, ABS_X, 0, ts->x_max, 0, 0);
|
|
||||||
input_set_abs_params(ts->input, ABS_Y, 0, ts->y_max, 0, 0);
|
|
||||||
input_set_abs_params(ts->input, ABS_PRESSURE, 0, 255, 0, 0);
|
|
||||||
input_abs_set_res(ts->input, ABS_X, ts->x_res);
|
|
||||||
input_abs_set_res(ts->input, ABS_Y, ts->y_res);
|
|
||||||
|
|
||||||
/* Multitouch input params setup */
|
/* Multitouch input params setup */
|
||||||
error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM,
|
|
||||||
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
|
|
||||||
if (error) {
|
|
||||||
dev_err(&client->dev,
|
|
||||||
"failed to initialize MT slots: %d\n", error);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0);
|
input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0);
|
||||||
input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0);
|
input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0);
|
||||||
@ -1320,6 +1327,16 @@ static int elants_i2c_probe(struct i2c_client *client,
|
|||||||
input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res);
|
input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res);
|
||||||
input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, 1);
|
input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, 1);
|
||||||
|
|
||||||
|
touchscreen_parse_properties(ts->input, true, &ts->prop);
|
||||||
|
|
||||||
|
error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM,
|
||||||
|
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"failed to initialize MT slots: %d\n", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
error = input_register_device(ts->input);
|
error = input_register_device(ts->input);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(&client->dev,
|
dev_err(&client->dev,
|
||||||
|
@ -391,7 +391,7 @@ static void mip4_clear_input(struct mip4_ts *ts)
|
|||||||
/* Screen */
|
/* Screen */
|
||||||
for (i = 0; i < MIP4_MAX_FINGERS; i++) {
|
for (i = 0; i < MIP4_MAX_FINGERS; i++) {
|
||||||
input_mt_slot(ts->input, i);
|
input_mt_slot(ts->input, i);
|
||||||
input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, 0);
|
input_mt_report_slot_inactive(ts->input);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keys */
|
/* Keys */
|
||||||
@ -534,7 +534,7 @@ static void mip4_report_touch(struct mip4_ts *ts, u8 *packet)
|
|||||||
} else {
|
} else {
|
||||||
/* Release event */
|
/* Release event */
|
||||||
input_mt_slot(ts->input, id);
|
input_mt_slot(ts->input, id);
|
||||||
input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, 0);
|
input_mt_report_slot_inactive(ts->input);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_mt_sync_frame(ts->input);
|
input_mt_sync_frame(ts->input);
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
enum mms_type {
|
enum mms_type {
|
||||||
TYPE_MMS114 = 114,
|
TYPE_MMS114 = 114,
|
||||||
TYPE_MMS152 = 152,
|
TYPE_MMS152 = 152,
|
||||||
|
TYPE_MMS345L = 345,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mms114_data {
|
struct mms114_data {
|
||||||
@ -250,6 +251,15 @@ static int mms114_get_version(struct mms114_data *data)
|
|||||||
int error;
|
int error;
|
||||||
|
|
||||||
switch (data->type) {
|
switch (data->type) {
|
||||||
|
case TYPE_MMS345L:
|
||||||
|
error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
dev_info(dev, "TSP FW Rev: bootloader 0x%x / core 0x%x / config 0x%x\n",
|
||||||
|
buf[0], buf[1], buf[2]);
|
||||||
|
break;
|
||||||
|
|
||||||
case TYPE_MMS152:
|
case TYPE_MMS152:
|
||||||
error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf);
|
error = __mms114_read_reg(data, MMS152_FW_REV, 3, buf);
|
||||||
if (error)
|
if (error)
|
||||||
@ -287,8 +297,8 @@ static int mms114_setup_regs(struct mms114_data *data)
|
|||||||
if (error < 0)
|
if (error < 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
/* MMS152 has no configuration or power on registers */
|
/* Only MMS114 has configuration and power on registers */
|
||||||
if (data->type == TYPE_MMS152)
|
if (data->type != TYPE_MMS114)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error = mms114_set_active(data, true);
|
error = mms114_set_active(data, true);
|
||||||
@ -547,7 +557,7 @@ static int __maybe_unused mms114_suspend(struct device *dev)
|
|||||||
/* Release all touch */
|
/* Release all touch */
|
||||||
for (id = 0; id < MMS114_MAX_TOUCH; id++) {
|
for (id = 0; id < MMS114_MAX_TOUCH; id++) {
|
||||||
input_mt_slot(input_dev, id);
|
input_mt_slot(input_dev, id);
|
||||||
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
|
input_mt_report_slot_inactive(input_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_mt_report_pointer_emulation(input_dev, true);
|
input_mt_report_pointer_emulation(input_dev, true);
|
||||||
@ -597,6 +607,9 @@ static const struct of_device_id mms114_dt_match[] = {
|
|||||||
}, {
|
}, {
|
||||||
.compatible = "melfas,mms152",
|
.compatible = "melfas,mms152",
|
||||||
.data = (void *)TYPE_MMS152,
|
.data = (void *)TYPE_MMS152,
|
||||||
|
}, {
|
||||||
|
.compatible = "melfas,mms345l",
|
||||||
|
.data = (void *)TYPE_MMS345L,
|
||||||
},
|
},
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
@ -100,7 +100,7 @@ static void rpi_ts_poll(struct input_dev *input)
|
|||||||
released_ids = ts->known_ids & ~modified_ids;
|
released_ids = ts->known_ids & ~modified_ids;
|
||||||
for_each_set_bit(i, &released_ids, RPI_TS_MAX_SUPPORTED_POINTS) {
|
for_each_set_bit(i, &released_ids, RPI_TS_MAX_SUPPORTED_POINTS) {
|
||||||
input_mt_slot(input, i);
|
input_mt_slot(input, i);
|
||||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, 0);
|
input_mt_report_slot_inactive(input);
|
||||||
modified_ids &= ~(BIT(i));
|
modified_ids &= ~(BIT(i));
|
||||||
}
|
}
|
||||||
ts->known_ids = modified_ids;
|
ts->known_ids = modified_ids;
|
||||||
|
@ -198,7 +198,7 @@ static void stmfts_report_contact_release(struct stmfts_data *sdata,
|
|||||||
u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
|
u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
|
||||||
|
|
||||||
input_mt_slot(sdata->input, slot_id);
|
input_mt_slot(sdata->input, slot_id);
|
||||||
input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, false);
|
input_mt_report_slot_inactive(sdata->input);
|
||||||
|
|
||||||
input_sync(sdata->input);
|
input_sync(sdata->input);
|
||||||
}
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
|
||||||
#ifndef _GP2AP002A00F_H_
|
|
||||||
#define _GP2AP002A00F_H_
|
|
||||||
|
|
||||||
#include <linux/i2c.h>
|
|
||||||
|
|
||||||
#define GP2A_I2C_NAME "gp2ap002a00f"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct gp2a_platform_data - Sharp gp2ap002a00f proximity platform data
|
|
||||||
* @vout_gpio: The gpio connected to the object detected pin (VOUT)
|
|
||||||
* @wakeup: Set to true if the proximity can wake the device from suspend
|
|
||||||
* @hw_setup: Callback for setting up hardware such as gpios and vregs
|
|
||||||
* @hw_shutdown: Callback for properly shutting down hardware
|
|
||||||
*/
|
|
||||||
struct gp2a_platform_data {
|
|
||||||
int vout_gpio;
|
|
||||||
bool wakeup;
|
|
||||||
int (*hw_setup)(struct i2c_client *client);
|
|
||||||
int (*hw_shutdown)(struct i2c_client *client);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -100,6 +100,11 @@ static inline bool input_is_mt_axis(int axis)
|
|||||||
bool input_mt_report_slot_state(struct input_dev *dev,
|
bool input_mt_report_slot_state(struct input_dev *dev,
|
||||||
unsigned int tool_type, bool active);
|
unsigned int tool_type, bool active);
|
||||||
|
|
||||||
|
static inline void input_mt_report_slot_inactive(struct input_dev *dev)
|
||||||
|
{
|
||||||
|
input_mt_report_slot_state(dev, 0, false);
|
||||||
|
}
|
||||||
|
|
||||||
void input_mt_report_finger_count(struct input_dev *dev, int count);
|
void input_mt_report_finger_count(struct input_dev *dev, int count);
|
||||||
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);
|
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);
|
||||||
void input_mt_drop_unused(struct input_dev *dev);
|
void input_mt_drop_unused(struct input_dev *dev);
|
||||||
|
Loading…
Reference in New Issue
Block a user