mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 13:53:33 +00:00
Input updates for 6.8 merge window:
- a new driver for Adafruit Seesaw gamepad device - Zforce touchscreen will handle standard device properties for axis swap/inversion - handling of advanced sensitivity settings in Microchip CAP11xx capacitive sensor driver - more drivers have been converted to use newer gpiod API - support for dedicated wakeup IRQs in gpio-keys dirver - support for slider gestures and OTP variants in iqs269a driver - atkbd will report keyboard version as 0xab83 in cases when GET ID command was skipped (to deal with problematic firmware on newer laptops), restoring the previous behavior - other assorted cleanups and changes -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQST2eWILY88ieB2DOtAj56VGEWXnAUCZalqoQAKCRBAj56VGEWX nOqHAP4u4b/r4w2aeULy3kpESgbUQ1vXpFUus/6AHTw1FAtbsgD/XxV3ZWKZ0H8J VfZ81yXvT3WstJM7p7YNP0GGXJ/HRQg= =l0Z8 -----END PGP SIGNATURE----- Merge tag 'input-for-v6.8-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input Pull input updates from Dmitry Torokhov: - a new driver for Adafruit Seesaw gamepad device - Zforce touchscreen will handle standard device properties for axis swap/inversion - handling of advanced sensitivity settings in Microchip CAP11xx capacitive sensor driver - more drivers have been converted to use newer gpiod API - support for dedicated wakeup IRQs in gpio-keys dirver - support for slider gestures and OTP variants in iqs269a driver - atkbd will report keyboard version as 0xab83 in cases when GET ID command was skipped (to deal with problematic firmware on newer laptops), restoring the previous behavior - other assorted cleanups and changes * tag 'input-for-v6.8-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (44 commits) Input: atkbd - use ab83 as id when skipping the getid command Input: driver for Adafruit Seesaw Gamepad dt-bindings: input: bindings for Adafruit Seesaw Gamepad Input: da9063_onkey - avoid explicitly setting input's parent Input: da9063_onkey - avoid using OF-specific APIs Input: iqs269a - add support for OTP variants dt-bindings: input: iqs269a: Add bindings for OTP variants Input: iqs269a - add support for slider gestures dt-bindings: input: iqs269a: Add bindings for slider gestures Input: gpio-keys - filter gpio_keys -EPROBE_DEFER error messages Input: zforce_ts - accept standard touchscreen properties dt-bindings: touchscreen: neonode,zforce: Use standard properties dt-bindings: touchscreen: convert neonode,zforce to json-schema dt-bindings: input: convert drv266x to json-schema Input: da9063 - use dev_err_probe() Input: da9063 - drop redundant prints in probe() Input: da9063 - simplify obtaining OF match data Input: as5011 - convert to GPIO descriptor Input: omap-keypad - drop optional GPIO support Input: tca6416-keypad - drop unused include ...
This commit is contained in:
commit
0f289bdd41
57 changed files with 1634 additions and 551 deletions
|
@ -0,0 +1,63 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/input/adafruit,seesaw-gamepad.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Adafruit Mini I2C Gamepad with seesaw
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Anshul Dalal <anshulusr@gmail.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Adafruit Mini I2C Gamepad
|
||||||
|
|
||||||
|
+-----------------------------+
|
||||||
|
| ___ |
|
||||||
|
| / \ (X) |
|
||||||
|
| | S | __ __ (Y) (A) |
|
||||||
|
| \___/ |ST| |SE| (B) |
|
||||||
|
| |
|
||||||
|
+-----------------------------+
|
||||||
|
|
||||||
|
S -> 10-bit precision bidirectional analog joystick
|
||||||
|
ST -> Start
|
||||||
|
SE -> Select
|
||||||
|
X, A, B, Y -> Digital action buttons
|
||||||
|
|
||||||
|
Datasheet: https://cdn-learn.adafruit.com/downloads/pdf/gamepad-qt.pdf
|
||||||
|
Product page: https://www.adafruit.com/product/5743
|
||||||
|
Arduino Driver: https://github.com/adafruit/Adafruit_Seesaw
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: adafruit,seesaw-gamepad
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
description:
|
||||||
|
The gamepad's IRQ pin triggers a rising edge if interrupts are enabled.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
joystick@50 {
|
||||||
|
compatible = "adafruit,seesaw-gamepad";
|
||||||
|
interrupts = <18 IRQ_TYPE_EDGE_RISING>;
|
||||||
|
reg = <0x50>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -31,7 +31,23 @@ patternProperties:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
interrupts:
|
interrupts:
|
||||||
maxItems: 1
|
oneOf:
|
||||||
|
- items:
|
||||||
|
- description: Optional key interrupt or wakeup interrupt
|
||||||
|
- items:
|
||||||
|
- description: Key interrupt
|
||||||
|
- description: Wakeup interrupt
|
||||||
|
|
||||||
|
interrupt-names:
|
||||||
|
description:
|
||||||
|
Optional interrupt names, can be used to specify a separate dedicated
|
||||||
|
wake-up interrupt in addition to the gpio irq
|
||||||
|
oneOf:
|
||||||
|
- items:
|
||||||
|
- enum: [ irq, wakeup ]
|
||||||
|
- items:
|
||||||
|
- const: irq
|
||||||
|
- const: wakeup
|
||||||
|
|
||||||
label:
|
label:
|
||||||
description: Descriptive name of the key.
|
description: Descriptive name of the key.
|
||||||
|
@ -97,6 +113,20 @@ patternProperties:
|
||||||
- required:
|
- required:
|
||||||
- gpios
|
- gpios
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
interrupts:
|
||||||
|
minItems: 2
|
||||||
|
required:
|
||||||
|
- interrupts
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
interrupt-names:
|
||||||
|
minItems: 2
|
||||||
|
required:
|
||||||
|
- interrupt-names
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
wakeup-event-action: [ wakeup-source ]
|
wakeup-event-action: [ wakeup-source ]
|
||||||
linux,input-value: [ gpios ]
|
linux,input-value: [ gpios ]
|
||||||
|
@ -137,6 +167,15 @@ examples:
|
||||||
linux,code = <108>;
|
linux,code = <108>;
|
||||||
interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
|
interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
key-wakeup {
|
||||||
|
label = "GPIO Key WAKEUP";
|
||||||
|
linux,code = <143>;
|
||||||
|
interrupts-extended = <&intc 2 IRQ_TYPE_EDGE_FALLING>,
|
||||||
|
<&intc_wakeup 0 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
interrupt-names = "irq", "wakeup";
|
||||||
|
wakeup-source;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
Device-Tree bindings for GPIO attached mice
|
|
||||||
|
|
||||||
This simply uses standard GPIO handles to define a simple mouse connected
|
|
||||||
to 5-7 GPIO lines.
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: must be "gpio-mouse"
|
|
||||||
- scan-interval-ms: The scanning interval in milliseconds
|
|
||||||
- up-gpios: GPIO line phandle to the line indicating "up"
|
|
||||||
- down-gpios: GPIO line phandle to the line indicating "down"
|
|
||||||
- left-gpios: GPIO line phandle to the line indicating "left"
|
|
||||||
- right-gpios: GPIO line phandle to the line indicating "right"
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- button-left-gpios: GPIO line handle to the left mouse button
|
|
||||||
- button-middle-gpios: GPIO line handle to the middle mouse button
|
|
||||||
- button-right-gpios: GPIO line handle to the right mouse button
|
|
||||||
Example:
|
|
||||||
|
|
||||||
#include <dt-bindings/gpio/gpio.h>
|
|
||||||
|
|
||||||
gpio-mouse {
|
|
||||||
compatible = "gpio-mouse";
|
|
||||||
scan-interval-ms = <50>;
|
|
||||||
up-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
|
|
||||||
down-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
|
|
||||||
left-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
|
|
||||||
right-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
|
|
||||||
button-left-gpios = <&gpio0 4 GPIO_ACTIVE_LOW>;
|
|
||||||
button-middle-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
|
|
||||||
button-right-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
|
|
||||||
};
|
|
68
Documentation/devicetree/bindings/input/gpio-mouse.yaml
Normal file
68
Documentation/devicetree/bindings/input/gpio-mouse.yaml
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/input/gpio-mouse.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: GPIO attached mouse
|
||||||
|
|
||||||
|
description: |
|
||||||
|
This simply uses standard GPIO handles to define a simple mouse connected
|
||||||
|
to 5-7 GPIO lines.
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Anshul Dalal <anshulusr@gmail.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: gpio-mouse
|
||||||
|
|
||||||
|
scan-interval-ms:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
up-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
down-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
left-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
right-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
button-left-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
button-middle-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
button-right-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- scan-interval-ms
|
||||||
|
- up-gpios
|
||||||
|
- down-gpios
|
||||||
|
- left-gpios
|
||||||
|
- right-gpios
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
|
||||||
|
gpio-mouse {
|
||||||
|
compatible = "gpio-mouse";
|
||||||
|
scan-interval-ms = <50>;
|
||||||
|
up-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
|
||||||
|
down-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
|
||||||
|
left-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
|
||||||
|
right-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
|
||||||
|
button-left-gpios = <&gpio0 4 GPIO_ACTIVE_LOW>;
|
||||||
|
button-middle-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
|
||||||
|
button-right-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
|
||||||
|
};
|
|
@ -9,6 +9,9 @@ title: Azoteq IQS269A Capacitive Touch Controller
|
||||||
maintainers:
|
maintainers:
|
||||||
- Jeff LaBundy <jeff@labundy.com>
|
- Jeff LaBundy <jeff@labundy.com>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: input.yaml#
|
||||||
|
|
||||||
description: |
|
description: |
|
||||||
The Azoteq IQS269A is an 8-channel capacitive touch controller that features
|
The Azoteq IQS269A is an 8-channel capacitive touch controller that features
|
||||||
additional Hall-effect and inductive sensing capabilities.
|
additional Hall-effect and inductive sensing capabilities.
|
||||||
|
@ -17,7 +20,10 @@ description: |
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
const: azoteq,iqs269a
|
enum:
|
||||||
|
- azoteq,iqs269a
|
||||||
|
- azoteq,iqs269a-00
|
||||||
|
- azoteq,iqs269a-d0
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
@ -204,6 +210,73 @@ properties:
|
||||||
default: 1
|
default: 1
|
||||||
description: Specifies the slider coordinate filter strength.
|
description: Specifies the slider coordinate filter strength.
|
||||||
|
|
||||||
|
azoteq,touch-hold-ms:
|
||||||
|
multipleOf: 256
|
||||||
|
minimum: 256
|
||||||
|
maximum: 65280
|
||||||
|
default: 5120
|
||||||
|
description:
|
||||||
|
Specifies the length of time (in ms) for which the channel selected by
|
||||||
|
'azoteq,gpio3-select' must be held in a state of touch in order for an
|
||||||
|
approximately 60-ms pulse to be asserted on the GPIO4 pin.
|
||||||
|
|
||||||
|
linux,keycodes:
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 8
|
||||||
|
description: |
|
||||||
|
Specifies the numeric keycodes associated with each available gesture in
|
||||||
|
the following order (enter 0 for unused gestures):
|
||||||
|
0: Slider 0 tap
|
||||||
|
1: Slider 0 hold
|
||||||
|
2: Slider 0 positive flick or swipe
|
||||||
|
3: Slider 0 negative flick or swipe
|
||||||
|
4: Slider 1 tap
|
||||||
|
5: Slider 1 hold
|
||||||
|
6: Slider 1 positive flick or swipe
|
||||||
|
7: Slider 1 negative flick or swipe
|
||||||
|
|
||||||
|
azoteq,gesture-swipe:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
Directs the device to interpret axial gestures as a swipe (finger remains
|
||||||
|
on slider) instead of a flick (finger leaves slider).
|
||||||
|
|
||||||
|
azoteq,timeout-tap-ms:
|
||||||
|
multipleOf: 16
|
||||||
|
minimum: 0
|
||||||
|
maximum: 4080
|
||||||
|
default: 400
|
||||||
|
description:
|
||||||
|
Specifies the length of time (in ms) within which a slider touch must be
|
||||||
|
released in order to be interpreted as a tap. Default and maximum values
|
||||||
|
as well as step size are reduced by a factor of 4 with device version 2.
|
||||||
|
|
||||||
|
azoteq,timeout-swipe-ms:
|
||||||
|
multipleOf: 16
|
||||||
|
minimum: 0
|
||||||
|
maximum: 4080
|
||||||
|
default: 2000
|
||||||
|
description:
|
||||||
|
Specifies the length of time (in ms) within which an axial gesture must be
|
||||||
|
completed in order to be interpreted as a flick or swipe. Default and max-
|
||||||
|
imum values as well as step size are reduced by a factor of 4 with device
|
||||||
|
version 2.
|
||||||
|
|
||||||
|
azoteq,thresh-swipe:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
minimum: 0
|
||||||
|
maximum: 255
|
||||||
|
default: 128
|
||||||
|
description:
|
||||||
|
Specifies the number of points across which an axial gesture must travel
|
||||||
|
in order to be interpreted as a flick or swipe.
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
azoteq,gesture-swipe: ["linux,keycodes"]
|
||||||
|
azoteq,timeout-tap-ms: ["linux,keycodes"]
|
||||||
|
azoteq,timeout-swipe-ms: ["linux,keycodes"]
|
||||||
|
azoteq,thresh-swipe: ["linux,keycodes"]
|
||||||
|
|
||||||
patternProperties:
|
patternProperties:
|
||||||
"^channel@[0-7]$":
|
"^channel@[0-7]$":
|
||||||
type: object
|
type: object
|
||||||
|
@ -454,6 +527,21 @@ patternProperties:
|
||||||
|
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
|
||||||
|
if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- azoteq,iqs269a-d0
|
||||||
|
then:
|
||||||
|
patternProperties:
|
||||||
|
"^channel@[0-7]$":
|
||||||
|
properties:
|
||||||
|
azoteq,slider1-select: false
|
||||||
|
else:
|
||||||
|
properties:
|
||||||
|
azoteq,touch-hold-ms: false
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
|
@ -484,6 +572,14 @@ examples:
|
||||||
azoteq,hall-enable;
|
azoteq,hall-enable;
|
||||||
azoteq,suspend-mode = <2>;
|
azoteq,suspend-mode = <2>;
|
||||||
|
|
||||||
|
linux,keycodes = <KEY_PLAYPAUSE>,
|
||||||
|
<KEY_STOPCD>,
|
||||||
|
<KEY_NEXTSONG>,
|
||||||
|
<KEY_PREVIOUSSONG>;
|
||||||
|
|
||||||
|
azoteq,timeout-tap-ms = <400>;
|
||||||
|
azoteq,timeout-swipe-ms = <800>;
|
||||||
|
|
||||||
channel@0 {
|
channel@0 {
|
||||||
reg = <0x0>;
|
reg = <0x0>;
|
||||||
|
|
||||||
|
|
|
@ -90,26 +90,4 @@ required:
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
examples:
|
...
|
||||||
- |
|
|
||||||
#include <dt-bindings/input/input.h>
|
|
||||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
|
||||||
|
|
||||||
pmic {
|
|
||||||
compatible = "mediatek,mt6397";
|
|
||||||
|
|
||||||
keys {
|
|
||||||
compatible = "mediatek,mt6397-keys";
|
|
||||||
mediatek,long-press-mode = <1>;
|
|
||||||
power-off-time-sec = <0>;
|
|
||||||
|
|
||||||
key-power {
|
|
||||||
linux,keycodes = <KEY_POWER>;
|
|
||||||
wakeup-source;
|
|
||||||
};
|
|
||||||
|
|
||||||
key-home {
|
|
||||||
linux,keycodes = <KEY_VOLUMEDOWN>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
|
@ -45,13 +45,13 @@ properties:
|
||||||
Enables the Linux input system's autorepeat feature on the input device.
|
Enables the Linux input system's autorepeat feature on the input device.
|
||||||
|
|
||||||
linux,keycodes:
|
linux,keycodes:
|
||||||
minItems: 6
|
minItems: 3
|
||||||
maxItems: 6
|
maxItems: 8
|
||||||
description: |
|
description: |
|
||||||
Specifies an array of numeric keycode values to
|
Specifies an array of numeric keycode values to
|
||||||
be used for the channels. If this property is
|
be used for the channels. If this property is
|
||||||
omitted, KEY_A, KEY_B, etc are used as defaults.
|
omitted, KEY_A, KEY_B, etc are used as defaults.
|
||||||
The array must have exactly six entries.
|
The number of entries must correspond to the number of channels.
|
||||||
|
|
||||||
microchip,sensor-gain:
|
microchip,sensor-gain:
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
@ -70,6 +70,59 @@ properties:
|
||||||
open drain. This property allows using the active
|
open drain. This property allows using the active
|
||||||
high push-pull output.
|
high push-pull output.
|
||||||
|
|
||||||
|
microchip,sensitivity-delta-sense:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
default: 32
|
||||||
|
enum: [1, 2, 4, 8, 16, 32, 64, 128]
|
||||||
|
description:
|
||||||
|
Controls the sensitivity multiplier of a touch detection.
|
||||||
|
Higher value means more sensitive settings.
|
||||||
|
At the more sensitive settings, touches are detected for a smaller delta
|
||||||
|
capacitance corresponding to a "lighter" touch.
|
||||||
|
|
||||||
|
microchip,signal-guard:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
minItems: 3
|
||||||
|
maxItems: 8
|
||||||
|
items:
|
||||||
|
enum: [0, 1]
|
||||||
|
description: |
|
||||||
|
0 - off
|
||||||
|
1 - on
|
||||||
|
The signal guard isolates the signal from virtual grounds.
|
||||||
|
If enabled then the behavior of the channel is changed to signal guard.
|
||||||
|
The number of entries must correspond to the number of channels.
|
||||||
|
|
||||||
|
microchip,input-threshold:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
minItems: 3
|
||||||
|
maxItems: 8
|
||||||
|
items:
|
||||||
|
minimum: 0
|
||||||
|
maximum: 127
|
||||||
|
description:
|
||||||
|
Specifies the delta threshold that is used to determine if a touch has
|
||||||
|
been detected. A higher value means a larger difference in capacitance
|
||||||
|
is required for a touch to be registered, making the touch sensor less
|
||||||
|
sensitive.
|
||||||
|
The number of entries must correspond to the number of channels.
|
||||||
|
|
||||||
|
microchip,calib-sensitivity:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
minItems: 3
|
||||||
|
maxItems: 8
|
||||||
|
items:
|
||||||
|
enum: [1, 2, 4]
|
||||||
|
description: |
|
||||||
|
Specifies an array of numeric values that controls the gain
|
||||||
|
used by the calibration routine to enable sensor inputs
|
||||||
|
to be more sensitive for proximity detection.
|
||||||
|
Gain is based on touch pad capacitance range
|
||||||
|
1 - 5-50pF
|
||||||
|
2 - 0-25pF
|
||||||
|
4 - 0-12.5pF
|
||||||
|
The number of entries must correspond to the number of channels.
|
||||||
|
|
||||||
patternProperties:
|
patternProperties:
|
||||||
"^led@[0-7]$":
|
"^led@[0-7]$":
|
||||||
type: object
|
type: object
|
||||||
|
@ -99,10 +152,29 @@ allOf:
|
||||||
contains:
|
contains:
|
||||||
enum:
|
enum:
|
||||||
- microchip,cap1106
|
- microchip,cap1106
|
||||||
|
- microchip,cap1203
|
||||||
|
- microchip,cap1206
|
||||||
|
- microchip,cap1293
|
||||||
|
- microchip,cap1298
|
||||||
then:
|
then:
|
||||||
patternProperties:
|
patternProperties:
|
||||||
"^led@[0-7]$": false
|
"^led@[0-7]$": false
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- microchip,cap1106
|
||||||
|
- microchip,cap1126
|
||||||
|
- microchip,cap1188
|
||||||
|
- microchip,cap1203
|
||||||
|
- microchip,cap1206
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
microchip,signal-guard: false
|
||||||
|
microchip,calib-sensitivity: false
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- interrupts
|
- interrupts
|
||||||
|
@ -122,6 +194,8 @@ examples:
|
||||||
reg = <0x28>;
|
reg = <0x28>;
|
||||||
autorepeat;
|
autorepeat;
|
||||||
microchip,sensor-gain = <2>;
|
microchip,sensor-gain = <2>;
|
||||||
|
microchip,sensitivity-delta-sense = <16>;
|
||||||
|
microchip,input-threshold = <21>, <18>, <46>, <46>, <46>, <21>;
|
||||||
|
|
||||||
linux,keycodes = <103>, /* KEY_UP */
|
linux,keycodes = <103>, /* KEY_UP */
|
||||||
<106>, /* KEY_RIGHT */
|
<106>, /* KEY_RIGHT */
|
||||||
|
|
|
@ -28,21 +28,4 @@ required:
|
||||||
|
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
|
||||||
examples:
|
...
|
||||||
- |
|
|
||||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
|
||||||
sc2731_pmic: pmic@0 {
|
|
||||||
compatible = "sprd,sc2731";
|
|
||||||
reg = <0 0>;
|
|
||||||
spi-max-frequency = <26000000>;
|
|
||||||
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
|
||||||
interrupt-controller;
|
|
||||||
#interrupt-cells = <2>;
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
|
|
||||||
vibrator@eb4 {
|
|
||||||
compatible = "sprd,sc2731-vibrator";
|
|
||||||
reg = <0xeb4>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
* Texas Instruments - drv2665 Haptics driver
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible - "ti,drv2665" - DRV2665
|
|
||||||
- reg - I2C slave address
|
|
||||||
- vbat-supply - Required supply regulator
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
haptics: haptics@59 {
|
|
||||||
compatible = "ti,drv2665";
|
|
||||||
reg = <0x59>;
|
|
||||||
vbat-supply = <&vbat>;
|
|
||||||
};
|
|
||||||
|
|
||||||
For more product information please see the link below:
|
|
||||||
http://www.ti.com/product/drv2665
|
|
|
@ -1,17 +0,0 @@
|
||||||
* Texas Instruments - drv2667 Haptics driver
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible - "ti,drv2667" - DRV2667
|
|
||||||
- reg - I2C slave address
|
|
||||||
- vbat-supply - Required supply regulator
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
haptics: haptics@59 {
|
|
||||||
compatible = "ti,drv2667";
|
|
||||||
reg = <0x59>;
|
|
||||||
vbat-supply = <&vbat>;
|
|
||||||
};
|
|
||||||
|
|
||||||
For more product information please see the link below:
|
|
||||||
http://www.ti.com/product/drv2667
|
|
50
Documentation/devicetree/bindings/input/ti,drv266x.yaml
Normal file
50
Documentation/devicetree/bindings/input/ti,drv266x.yaml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/input/ti,drv266x.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Texas Instruments - drv266x Haptics driver
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Product Page:
|
||||||
|
http://www.ti.com/product/drv2665
|
||||||
|
http://www.ti.com/product/drv2667
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Anshul Dalal <anshulusr@gmail.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- ti,drv2665
|
||||||
|
- ti,drv2667
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
vbat-supply:
|
||||||
|
description: Required supply regulator
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- vbat-supply
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/gpio/gpio.h>
|
||||||
|
|
||||||
|
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
haptics@59 {
|
||||||
|
compatible = "ti,drv2667";
|
||||||
|
reg = <0x59>;
|
||||||
|
vbat-supply = <&vbat>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -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/neonode,zforce.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Neonode infrared touchscreen controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Heiko Stuebner <heiko@sntech.de>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: touchscreen.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: neonode,zforce
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
reset-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
irq-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
x-size:
|
||||||
|
deprecated: true
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
y-size:
|
||||||
|
deprecated: true
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
vdd-supply: true
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- reset-gpios
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
touchscreen@50 {
|
||||||
|
compatible = "neonode,zforce";
|
||||||
|
reg = <0x50>;
|
||||||
|
interrupts = <2 0>;
|
||||||
|
vdd-supply = <®_zforce_vdd>;
|
||||||
|
|
||||||
|
reset-gpios = <&gpio5 9 0>; /* RST */
|
||||||
|
irq-gpios = <&gpio5 6 0>; /* IRQ, optional */
|
||||||
|
|
||||||
|
touchscreen-min-x = <0>;
|
||||||
|
touchscreen-size-x = <800>;
|
||||||
|
touchscreen-min-y = <0>;
|
||||||
|
touchscreen-size-y = <600>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
...
|
|
@ -1,32 +0,0 @@
|
||||||
* Samsung S6SY761 touchscreen controller
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible : must be "samsung,s6sy761"
|
|
||||||
- reg : I2C slave address, (e.g. 0x48)
|
|
||||||
- interrupts : interrupt specification
|
|
||||||
- avdd-supply : analogic power supply
|
|
||||||
- vdd-supply : power supply
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- touchscreen-size-x : see touchscreen.txt. This property is embedded in the
|
|
||||||
device. If defined it forces a different x resolution.
|
|
||||||
- touchscreen-size-y : see touchscreen.txt. This property is embedded in the
|
|
||||||
device. If defined it forces a different y resolution.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
i2c@00000000 {
|
|
||||||
|
|
||||||
/* ... */
|
|
||||||
|
|
||||||
touchscreen@48 {
|
|
||||||
compatible = "samsung,s6sy761";
|
|
||||||
reg = <0x48>;
|
|
||||||
interrupt-parent = <&gpa1>;
|
|
||||||
interrupts = <1 IRQ_TYPE_NONE>;
|
|
||||||
avdd-supply = <&ldo30_reg>;
|
|
||||||
vdd-supply = <&ldo31_reg>;
|
|
||||||
touchscreen-size-x = <4096>;
|
|
||||||
touchscreen-size-y = <4096>;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/input/touchscreen/samsung,s6sy761.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Samsung S6SY761 touchscreen controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Andi Shyti <andi.shyti@kernel.org>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: touchscreen.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: samsung,s6sy761
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
avdd-supply: true
|
||||||
|
vdd-supply: true
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- avdd-supply
|
||||||
|
- vdd-supply
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
touchscreen@48 {
|
||||||
|
compatible = "samsung,s6sy761";
|
||||||
|
reg = <0x48>;
|
||||||
|
interrupt-parent = <&gpa1>;
|
||||||
|
interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
avdd-supply = <&ldo30_reg>;
|
||||||
|
vdd-supply = <&ldo31_reg>;
|
||||||
|
touchscreen-size-x = <4096>;
|
||||||
|
touchscreen-size-y = <4096>;
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,34 +0,0 @@
|
||||||
* Neonode infrared touchscreen controller
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: must be "neonode,zforce"
|
|
||||||
- reg: I2C address of the chip
|
|
||||||
- interrupts: interrupt to which the chip is connected
|
|
||||||
- reset-gpios: reset gpio the chip is connected to
|
|
||||||
- x-size: horizontal resolution of touchscreen
|
|
||||||
- y-size: vertical resolution of touchscreen
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- irq-gpios : interrupt gpio the chip is connected to
|
|
||||||
- vdd-supply: Regulator controlling the controller supply
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
i2c@00000000 {
|
|
||||||
/* ... */
|
|
||||||
|
|
||||||
zforce_ts@50 {
|
|
||||||
compatible = "neonode,zforce";
|
|
||||||
reg = <0x50>;
|
|
||||||
interrupts = <2 0>;
|
|
||||||
vdd-supply = <®_zforce_vdd>;
|
|
||||||
|
|
||||||
reset-gpios = <&gpio5 9 0>; /* RST */
|
|
||||||
irq-gpios = <&gpio5 6 0>; /* IRQ, optional */
|
|
||||||
|
|
||||||
x-size = <800>;
|
|
||||||
y-size = <600>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ... */
|
|
||||||
};
|
|
|
@ -441,6 +441,13 @@ W: http://wiki.analog.com/AD7879
|
||||||
W: https://ez.analog.com/linux-software-drivers
|
W: https://ez.analog.com/linux-software-drivers
|
||||||
F: drivers/input/touchscreen/ad7879.c
|
F: drivers/input/touchscreen/ad7879.c
|
||||||
|
|
||||||
|
ADAFRUIT MINI I2C GAMEPAD
|
||||||
|
M: Anshul Dalal <anshulusr@gmail.com>
|
||||||
|
L: linux-input@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: Documentation/devicetree/bindings/input/adafruit,seesaw-gamepad.yaml
|
||||||
|
F: drivers/input/joystick/adafruit-seesaw.c
|
||||||
|
|
||||||
ADDRESS SPACE LAYOUT RANDOMIZATION (ASLR)
|
ADDRESS SPACE LAYOUT RANDOMIZATION (ASLR)
|
||||||
M: Jiri Kosina <jikos@kernel.org>
|
M: Jiri Kosina <jikos@kernel.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
|
@ -1365,7 +1365,7 @@ static ssize_t input_dev_show_##name(struct device *dev, \
|
||||||
{ \
|
{ \
|
||||||
struct input_dev *input_dev = to_input_dev(dev); \
|
struct input_dev *input_dev = to_input_dev(dev); \
|
||||||
\
|
\
|
||||||
return scnprintf(buf, PAGE_SIZE, "%s\n", \
|
return sysfs_emit(buf, "%s\n", \
|
||||||
input_dev->name ? input_dev->name : ""); \
|
input_dev->name ? input_dev->name : ""); \
|
||||||
} \
|
} \
|
||||||
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)
|
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL)
|
||||||
|
@ -1458,7 +1458,7 @@ static ssize_t inhibited_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct input_dev *input_dev = to_input_dev(dev);
|
struct input_dev *input_dev = to_input_dev(dev);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%d\n", input_dev->inhibited);
|
return sysfs_emit(buf, "%d\n", input_dev->inhibited);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t inhibited_store(struct device *dev,
|
static ssize_t inhibited_store(struct device *dev,
|
||||||
|
@ -1505,7 +1505,7 @@ static ssize_t input_dev_show_id_##name(struct device *dev, \
|
||||||
char *buf) \
|
char *buf) \
|
||||||
{ \
|
{ \
|
||||||
struct input_dev *input_dev = to_input_dev(dev); \
|
struct input_dev *input_dev = to_input_dev(dev); \
|
||||||
return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name); \
|
return sysfs_emit(buf, "%04x\n", input_dev->id.name); \
|
||||||
} \
|
} \
|
||||||
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)
|
static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL)
|
||||||
|
|
||||||
|
|
|
@ -412,4 +412,14 @@ config JOYSTICK_SENSEHAT
|
||||||
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 sensehat_joystick.
|
module will be called sensehat_joystick.
|
||||||
|
|
||||||
|
config JOYSTICK_SEESAW
|
||||||
|
tristate "Adafruit Mini I2C Gamepad with Seesaw"
|
||||||
|
depends on I2C
|
||||||
|
select INPUT_SPARSEKMAP
|
||||||
|
help
|
||||||
|
Say Y here if you want to use the Adafruit Mini I2C Gamepad.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module will be
|
||||||
|
called adafruit-seesaw.
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -28,6 +28,7 @@ obj-$(CONFIG_JOYSTICK_N64) += n64joy.o
|
||||||
obj-$(CONFIG_JOYSTICK_PSXPAD_SPI) += psxpad-spi.o
|
obj-$(CONFIG_JOYSTICK_PSXPAD_SPI) += psxpad-spi.o
|
||||||
obj-$(CONFIG_JOYSTICK_PXRC) += pxrc.o
|
obj-$(CONFIG_JOYSTICK_PXRC) += pxrc.o
|
||||||
obj-$(CONFIG_JOYSTICK_QWIIC) += qwiic-joystick.o
|
obj-$(CONFIG_JOYSTICK_QWIIC) += qwiic-joystick.o
|
||||||
|
obj-$(CONFIG_JOYSTICK_SEESAW) += adafruit-seesaw.o
|
||||||
obj-$(CONFIG_JOYSTICK_SENSEHAT) += sensehat-joystick.o
|
obj-$(CONFIG_JOYSTICK_SENSEHAT) += sensehat-joystick.o
|
||||||
obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o
|
obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o
|
||||||
obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o
|
obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o
|
||||||
|
|
315
drivers/input/joystick/adafruit-seesaw.c
Normal file
315
drivers/input/joystick/adafruit-seesaw.c
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Anshul Dalal <anshulusr@gmail.com>
|
||||||
|
*
|
||||||
|
* Driver for Adafruit Mini I2C Gamepad
|
||||||
|
*
|
||||||
|
* Based on the work of:
|
||||||
|
* Oleh Kravchenko (Sparkfun Qwiic Joystick driver)
|
||||||
|
*
|
||||||
|
* Datasheet: https://cdn-learn.adafruit.com/downloads/pdf/gamepad-qt.pdf
|
||||||
|
* Product page: https://www.adafruit.com/product/5743
|
||||||
|
* Firmware and hardware sources: https://github.com/adafruit/Adafruit_Seesaw
|
||||||
|
*
|
||||||
|
* TODO:
|
||||||
|
* - Add interrupt support
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
#include <linux/bits.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/input/sparse-keymap.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
#define SEESAW_DEVICE_NAME "seesaw-gamepad"
|
||||||
|
|
||||||
|
#define SEESAW_ADC_BASE 0x0900
|
||||||
|
|
||||||
|
#define SEESAW_GPIO_DIRCLR_BULK 0x0103
|
||||||
|
#define SEESAW_GPIO_BULK 0x0104
|
||||||
|
#define SEESAW_GPIO_BULK_SET 0x0105
|
||||||
|
#define SEESAW_GPIO_PULLENSET 0x010b
|
||||||
|
|
||||||
|
#define SEESAW_STATUS_HW_ID 0x0001
|
||||||
|
#define SEESAW_STATUS_SWRST 0x007f
|
||||||
|
|
||||||
|
#define SEESAW_ADC_OFFSET 0x07
|
||||||
|
|
||||||
|
#define SEESAW_BUTTON_A 0x05
|
||||||
|
#define SEESAW_BUTTON_B 0x01
|
||||||
|
#define SEESAW_BUTTON_X 0x06
|
||||||
|
#define SEESAW_BUTTON_Y 0x02
|
||||||
|
#define SEESAW_BUTTON_START 0x10
|
||||||
|
#define SEESAW_BUTTON_SELECT 0x00
|
||||||
|
|
||||||
|
#define SEESAW_ANALOG_X 0x0e
|
||||||
|
#define SEESAW_ANALOG_Y 0x0f
|
||||||
|
|
||||||
|
#define SEESAW_JOYSTICK_MAX_AXIS 1023
|
||||||
|
#define SEESAW_JOYSTICK_FUZZ 2
|
||||||
|
#define SEESAW_JOYSTICK_FLAT 4
|
||||||
|
|
||||||
|
#define SEESAW_GAMEPAD_POLL_INTERVAL_MS 16
|
||||||
|
#define SEESAW_GAMEPAD_POLL_MIN 8
|
||||||
|
#define SEESAW_GAMEPAD_POLL_MAX 32
|
||||||
|
|
||||||
|
static const unsigned long SEESAW_BUTTON_MASK =
|
||||||
|
BIT(SEESAW_BUTTON_A) | BIT(SEESAW_BUTTON_B) | BIT(SEESAW_BUTTON_X) |
|
||||||
|
BIT(SEESAW_BUTTON_Y) | BIT(SEESAW_BUTTON_START) |
|
||||||
|
BIT(SEESAW_BUTTON_SELECT);
|
||||||
|
|
||||||
|
struct seesaw_gamepad {
|
||||||
|
struct input_dev *input_dev;
|
||||||
|
struct i2c_client *i2c_client;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct seesaw_data {
|
||||||
|
u16 x;
|
||||||
|
u16 y;
|
||||||
|
u32 button_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct key_entry seesaw_buttons_new[] = {
|
||||||
|
{ KE_KEY, SEESAW_BUTTON_A, .keycode = BTN_SOUTH },
|
||||||
|
{ KE_KEY, SEESAW_BUTTON_B, .keycode = BTN_EAST },
|
||||||
|
{ KE_KEY, SEESAW_BUTTON_X, .keycode = BTN_NORTH },
|
||||||
|
{ KE_KEY, SEESAW_BUTTON_Y, .keycode = BTN_WEST },
|
||||||
|
{ KE_KEY, SEESAW_BUTTON_START, .keycode = BTN_START },
|
||||||
|
{ KE_KEY, SEESAW_BUTTON_SELECT, .keycode = BTN_SELECT },
|
||||||
|
{ KE_END, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int seesaw_register_read(struct i2c_client *client, u16 reg, void *buf,
|
||||||
|
int count)
|
||||||
|
{
|
||||||
|
__be16 register_buf = cpu_to_be16(reg);
|
||||||
|
struct i2c_msg message_buf[2] = {
|
||||||
|
{
|
||||||
|
.addr = client->addr,
|
||||||
|
.flags = client->flags,
|
||||||
|
.len = sizeof(register_buf),
|
||||||
|
.buf = (u8 *)®ister_buf,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.addr = client->addr,
|
||||||
|
.flags = client->flags | I2C_M_RD,
|
||||||
|
.len = count,
|
||||||
|
.buf = (u8 *)buf,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = i2c_transfer(client->adapter, message_buf,
|
||||||
|
ARRAY_SIZE(message_buf));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seesaw_register_write_u8(struct i2c_client *client, u16 reg,
|
||||||
|
u8 value)
|
||||||
|
{
|
||||||
|
u8 write_buf[sizeof(reg) + sizeof(value)];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
put_unaligned_be16(reg, write_buf);
|
||||||
|
write_buf[sizeof(reg)] = value;
|
||||||
|
|
||||||
|
ret = i2c_master_send(client, write_buf, sizeof(write_buf));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seesaw_register_write_u32(struct i2c_client *client, u16 reg,
|
||||||
|
u32 value)
|
||||||
|
{
|
||||||
|
u8 write_buf[sizeof(reg) + sizeof(value)];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
put_unaligned_be16(reg, write_buf);
|
||||||
|
put_unaligned_be32(value, write_buf + sizeof(reg));
|
||||||
|
ret = i2c_master_send(client, write_buf, sizeof(write_buf));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seesaw_read_data(struct i2c_client *client, struct seesaw_data *data)
|
||||||
|
{
|
||||||
|
__be16 adc_data;
|
||||||
|
__be32 read_buf;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = seesaw_register_read(client, SEESAW_GPIO_BULK,
|
||||||
|
&read_buf, sizeof(read_buf));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
data->button_state = ~be32_to_cpu(read_buf);
|
||||||
|
|
||||||
|
err = seesaw_register_read(client,
|
||||||
|
SEESAW_ADC_BASE |
|
||||||
|
(SEESAW_ADC_OFFSET + SEESAW_ANALOG_X),
|
||||||
|
&adc_data, sizeof(adc_data));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
/*
|
||||||
|
* ADC reads left as max and right as 0, must be reversed since kernel
|
||||||
|
* expects reports in opposite order.
|
||||||
|
*/
|
||||||
|
data->x = SEESAW_JOYSTICK_MAX_AXIS - be16_to_cpu(adc_data);
|
||||||
|
|
||||||
|
err = seesaw_register_read(client,
|
||||||
|
SEESAW_ADC_BASE |
|
||||||
|
(SEESAW_ADC_OFFSET + SEESAW_ANALOG_Y),
|
||||||
|
&adc_data, sizeof(adc_data));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
data->y = be16_to_cpu(adc_data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void seesaw_poll(struct input_dev *input)
|
||||||
|
{
|
||||||
|
struct seesaw_gamepad *private = input_get_drvdata(input);
|
||||||
|
struct seesaw_data data;
|
||||||
|
int err, i;
|
||||||
|
|
||||||
|
err = seesaw_read_data(private->i2c_client, &data);
|
||||||
|
if (err) {
|
||||||
|
dev_err_ratelimited(&input->dev,
|
||||||
|
"failed to read joystick state: %d\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_report_abs(input, ABS_X, data.x);
|
||||||
|
input_report_abs(input, ABS_Y, data.y);
|
||||||
|
|
||||||
|
for_each_set_bit(i, &SEESAW_BUTTON_MASK,
|
||||||
|
BITS_PER_TYPE(SEESAW_BUTTON_MASK)) {
|
||||||
|
if (!sparse_keymap_report_event(input, i,
|
||||||
|
data.button_state & BIT(i),
|
||||||
|
false))
|
||||||
|
dev_err_ratelimited(&input->dev,
|
||||||
|
"failed to report keymap event");
|
||||||
|
}
|
||||||
|
|
||||||
|
input_sync(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int seesaw_probe(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct seesaw_gamepad *seesaw;
|
||||||
|
u8 hardware_id;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = seesaw_register_write_u8(client, SEESAW_STATUS_SWRST, 0xFF);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Wait for the registers to reset before proceeding */
|
||||||
|
usleep_range(10000, 15000);
|
||||||
|
|
||||||
|
seesaw = devm_kzalloc(&client->dev, sizeof(*seesaw), GFP_KERNEL);
|
||||||
|
if (!seesaw)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
err = seesaw_register_read(client, SEESAW_STATUS_HW_ID,
|
||||||
|
&hardware_id, sizeof(hardware_id));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
dev_dbg(&client->dev, "Adafruit Seesaw Gamepad, Hardware ID: %02x\n",
|
||||||
|
hardware_id);
|
||||||
|
|
||||||
|
/* Set Pin Mode to input and enable pull-up resistors */
|
||||||
|
err = seesaw_register_write_u32(client, SEESAW_GPIO_DIRCLR_BULK,
|
||||||
|
SEESAW_BUTTON_MASK);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
err = seesaw_register_write_u32(client, SEESAW_GPIO_PULLENSET,
|
||||||
|
SEESAW_BUTTON_MASK);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
err = seesaw_register_write_u32(client, SEESAW_GPIO_BULK_SET,
|
||||||
|
SEESAW_BUTTON_MASK);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
seesaw->i2c_client = client;
|
||||||
|
seesaw->input_dev = devm_input_allocate_device(&client->dev);
|
||||||
|
if (!seesaw->input_dev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
seesaw->input_dev->id.bustype = BUS_I2C;
|
||||||
|
seesaw->input_dev->name = "Adafruit Seesaw Gamepad";
|
||||||
|
seesaw->input_dev->phys = "i2c/" SEESAW_DEVICE_NAME;
|
||||||
|
input_set_drvdata(seesaw->input_dev, seesaw);
|
||||||
|
input_set_abs_params(seesaw->input_dev, ABS_X,
|
||||||
|
0, SEESAW_JOYSTICK_MAX_AXIS,
|
||||||
|
SEESAW_JOYSTICK_FUZZ, SEESAW_JOYSTICK_FLAT);
|
||||||
|
input_set_abs_params(seesaw->input_dev, ABS_Y,
|
||||||
|
0, SEESAW_JOYSTICK_MAX_AXIS,
|
||||||
|
SEESAW_JOYSTICK_FUZZ, SEESAW_JOYSTICK_FLAT);
|
||||||
|
|
||||||
|
err = sparse_keymap_setup(seesaw->input_dev, seesaw_buttons_new, NULL);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"failed to set up input device keymap: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = input_setup_polling(seesaw->input_dev, seesaw_poll);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&client->dev, "failed to set up polling: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_set_poll_interval(seesaw->input_dev,
|
||||||
|
SEESAW_GAMEPAD_POLL_INTERVAL_MS);
|
||||||
|
input_set_max_poll_interval(seesaw->input_dev, SEESAW_GAMEPAD_POLL_MAX);
|
||||||
|
input_set_min_poll_interval(seesaw->input_dev, SEESAW_GAMEPAD_POLL_MIN);
|
||||||
|
|
||||||
|
err = input_register_device(seesaw->input_dev);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&client->dev, "failed to register joystick: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id seesaw_id_table[] = {
|
||||||
|
{ SEESAW_DEVICE_NAME },
|
||||||
|
{ /* Sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, seesaw_id_table);
|
||||||
|
|
||||||
|
static const struct of_device_id seesaw_of_table[] = {
|
||||||
|
{ .compatible = "adafruit,seesaw-gamepad"},
|
||||||
|
{ /* Sentinel */ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, seesaw_of_table);
|
||||||
|
|
||||||
|
static struct i2c_driver seesaw_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = SEESAW_DEVICE_NAME,
|
||||||
|
.of_match_table = seesaw_of_table,
|
||||||
|
},
|
||||||
|
.id_table = seesaw_id_table,
|
||||||
|
.probe = seesaw_probe,
|
||||||
|
};
|
||||||
|
module_i2c_driver(seesaw_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Anshul Dalal <anshulusr@gmail.com>");
|
||||||
|
MODULE_DESCRIPTION("Adafruit Mini I2C Gamepad driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -13,7 +13,7 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/input/as5011.h>
|
#include <linux/input/as5011.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
@ -61,7 +61,7 @@ MODULE_LICENSE("GPL");
|
||||||
struct as5011_device {
|
struct as5011_device {
|
||||||
struct input_dev *input_dev;
|
struct input_dev *input_dev;
|
||||||
struct i2c_client *i2c_client;
|
struct i2c_client *i2c_client;
|
||||||
unsigned int button_gpio;
|
struct gpio_desc *button_gpiod;
|
||||||
unsigned int button_irq;
|
unsigned int button_irq;
|
||||||
unsigned int axis_irq;
|
unsigned int axis_irq;
|
||||||
};
|
};
|
||||||
|
@ -114,7 +114,7 @@ static int as5011_i2c_read(struct i2c_client *client,
|
||||||
static irqreturn_t as5011_button_interrupt(int irq, void *dev_id)
|
static irqreturn_t as5011_button_interrupt(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct as5011_device *as5011 = dev_id;
|
struct as5011_device *as5011 = dev_id;
|
||||||
int val = gpio_get_value_cansleep(as5011->button_gpio);
|
int val = gpiod_get_value_cansleep(as5011->button_gpiod);
|
||||||
|
|
||||||
input_report_key(as5011->input_dev, BTN_JOYSTICK, !val);
|
input_report_key(as5011->input_dev, BTN_JOYSTICK, !val);
|
||||||
input_sync(as5011->input_dev);
|
input_sync(as5011->input_dev);
|
||||||
|
@ -248,7 +248,6 @@ static int as5011_probe(struct i2c_client *client)
|
||||||
|
|
||||||
as5011->i2c_client = client;
|
as5011->i2c_client = client;
|
||||||
as5011->input_dev = input_dev;
|
as5011->input_dev = input_dev;
|
||||||
as5011->button_gpio = plat_data->button_gpio;
|
|
||||||
as5011->axis_irq = plat_data->axis_irq;
|
as5011->axis_irq = plat_data->axis_irq;
|
||||||
|
|
||||||
input_dev->name = "Austria Microsystem as5011 joystick";
|
input_dev->name = "Austria Microsystem as5011 joystick";
|
||||||
|
@ -262,18 +261,20 @@ static int as5011_probe(struct i2c_client *client)
|
||||||
input_set_abs_params(as5011->input_dev, ABS_Y,
|
input_set_abs_params(as5011->input_dev, ABS_Y,
|
||||||
AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
|
AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
|
||||||
|
|
||||||
error = gpio_request(as5011->button_gpio, "AS5011 button");
|
as5011->button_gpiod = devm_gpiod_get(&client->dev, NULL, GPIOD_IN);
|
||||||
if (error < 0) {
|
if (IS_ERR(as5011->button_gpiod)) {
|
||||||
dev_err(&client->dev, "Failed to request button gpio\n");
|
error = PTR_ERR(as5011->button_gpiod);
|
||||||
|
dev_err(&client->dev, "Failed to request button GPIO\n");
|
||||||
goto err_free_mem;
|
goto err_free_mem;
|
||||||
}
|
}
|
||||||
|
gpiod_set_consumer_name(as5011->button_gpiod, "AS5011 button");
|
||||||
|
|
||||||
irq = gpio_to_irq(as5011->button_gpio);
|
irq = gpiod_to_irq(as5011->button_gpiod);
|
||||||
if (irq < 0) {
|
if (irq < 0) {
|
||||||
dev_err(&client->dev,
|
dev_err(&client->dev,
|
||||||
"Failed to get irq number for button gpio\n");
|
"Failed to get irq number for button gpio\n");
|
||||||
error = irq;
|
error = irq;
|
||||||
goto err_free_button_gpio;
|
goto err_free_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
as5011->button_irq = irq;
|
as5011->button_irq = irq;
|
||||||
|
@ -286,7 +287,7 @@ static int as5011_probe(struct i2c_client *client)
|
||||||
if (error < 0) {
|
if (error < 0) {
|
||||||
dev_err(&client->dev,
|
dev_err(&client->dev,
|
||||||
"Can't allocate button irq %d\n", as5011->button_irq);
|
"Can't allocate button irq %d\n", as5011->button_irq);
|
||||||
goto err_free_button_gpio;
|
goto err_free_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = as5011_configure_chip(as5011, plat_data);
|
error = as5011_configure_chip(as5011, plat_data);
|
||||||
|
@ -317,8 +318,6 @@ static int as5011_probe(struct i2c_client *client)
|
||||||
free_irq(as5011->axis_irq, as5011);
|
free_irq(as5011->axis_irq, as5011);
|
||||||
err_free_button_irq:
|
err_free_button_irq:
|
||||||
free_irq(as5011->button_irq, as5011);
|
free_irq(as5011->button_irq, as5011);
|
||||||
err_free_button_gpio:
|
|
||||||
gpio_free(as5011->button_gpio);
|
|
||||||
err_free_mem:
|
err_free_mem:
|
||||||
input_free_device(input_dev);
|
input_free_device(input_dev);
|
||||||
kfree(as5011);
|
kfree(as5011);
|
||||||
|
@ -332,7 +331,6 @@ static void as5011_remove(struct i2c_client *client)
|
||||||
|
|
||||||
free_irq(as5011->axis_irq, as5011);
|
free_irq(as5011->axis_irq, as5011);
|
||||||
free_irq(as5011->button_irq, as5011);
|
free_irq(as5011->button_irq, as5011);
|
||||||
gpio_free(as5011->button_gpio);
|
|
||||||
|
|
||||||
input_unregister_device(as5011->input_dev);
|
input_unregister_device(as5011->input_dev);
|
||||||
kfree(as5011);
|
kfree(as5011);
|
||||||
|
|
|
@ -5,15 +5,17 @@
|
||||||
* Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
|
* Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/cleanup.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/input.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
#include <linux/usb/input.h>
|
#include <linux/usb/input.h>
|
||||||
#include <linux/mutex.h>
|
|
||||||
#include <linux/input.h>
|
|
||||||
|
|
||||||
#define PXRC_VENDOR_ID 0x1781
|
#define PXRC_VENDOR_ID 0x1781
|
||||||
#define PXRC_PRODUCT_ID 0x0898
|
#define PXRC_PRODUCT_ID 0x0898
|
||||||
|
@ -81,33 +83,28 @@ static void pxrc_usb_irq(struct urb *urb)
|
||||||
static int pxrc_open(struct input_dev *input)
|
static int pxrc_open(struct input_dev *input)
|
||||||
{
|
{
|
||||||
struct pxrc *pxrc = input_get_drvdata(input);
|
struct pxrc *pxrc = input_get_drvdata(input);
|
||||||
int retval;
|
int error;
|
||||||
|
|
||||||
mutex_lock(&pxrc->pm_mutex);
|
guard(mutex)(&pxrc->pm_mutex);
|
||||||
retval = usb_submit_urb(pxrc->urb, GFP_KERNEL);
|
error = usb_submit_urb(pxrc->urb, GFP_KERNEL);
|
||||||
if (retval) {
|
if (error) {
|
||||||
dev_err(&pxrc->intf->dev,
|
dev_err(&pxrc->intf->dev,
|
||||||
"%s - usb_submit_urb failed, error: %d\n",
|
"%s - usb_submit_urb failed, error: %d\n",
|
||||||
__func__, retval);
|
__func__, error);
|
||||||
retval = -EIO;
|
return -EIO;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pxrc->is_open = true;
|
pxrc->is_open = true;
|
||||||
|
return 0;
|
||||||
out:
|
|
||||||
mutex_unlock(&pxrc->pm_mutex);
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pxrc_close(struct input_dev *input)
|
static void pxrc_close(struct input_dev *input)
|
||||||
{
|
{
|
||||||
struct pxrc *pxrc = input_get_drvdata(input);
|
struct pxrc *pxrc = input_get_drvdata(input);
|
||||||
|
|
||||||
mutex_lock(&pxrc->pm_mutex);
|
guard(mutex)(&pxrc->pm_mutex);
|
||||||
usb_kill_urb(pxrc->urb);
|
usb_kill_urb(pxrc->urb);
|
||||||
pxrc->is_open = false;
|
pxrc->is_open = false;
|
||||||
mutex_unlock(&pxrc->pm_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pxrc_free_urb(void *_pxrc)
|
static void pxrc_free_urb(void *_pxrc)
|
||||||
|
@ -208,10 +205,9 @@ static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)
|
||||||
{
|
{
|
||||||
struct pxrc *pxrc = usb_get_intfdata(intf);
|
struct pxrc *pxrc = usb_get_intfdata(intf);
|
||||||
|
|
||||||
mutex_lock(&pxrc->pm_mutex);
|
guard(mutex)(&pxrc->pm_mutex);
|
||||||
if (pxrc->is_open)
|
if (pxrc->is_open)
|
||||||
usb_kill_urb(pxrc->urb);
|
usb_kill_urb(pxrc->urb);
|
||||||
mutex_unlock(&pxrc->pm_mutex);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -219,14 +215,12 @@ static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)
|
||||||
static int pxrc_resume(struct usb_interface *intf)
|
static int pxrc_resume(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct pxrc *pxrc = usb_get_intfdata(intf);
|
struct pxrc *pxrc = usb_get_intfdata(intf);
|
||||||
int retval = 0;
|
|
||||||
|
|
||||||
mutex_lock(&pxrc->pm_mutex);
|
guard(mutex)(&pxrc->pm_mutex);
|
||||||
if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
|
if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
|
||||||
retval = -EIO;
|
return -EIO;
|
||||||
|
|
||||||
mutex_unlock(&pxrc->pm_mutex);
|
return 0;
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pxrc_pre_reset(struct usb_interface *intf)
|
static int pxrc_pre_reset(struct usb_interface *intf)
|
||||||
|
|
|
@ -1670,7 +1670,7 @@ static int xpad_led_probe(struct usb_xpad *xpad)
|
||||||
if (!led)
|
if (!led)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
xpad->pad_nr = ida_simple_get(&xpad_pad_seq, 0, 0, GFP_KERNEL);
|
xpad->pad_nr = ida_alloc(&xpad_pad_seq, GFP_KERNEL);
|
||||||
if (xpad->pad_nr < 0) {
|
if (xpad->pad_nr < 0) {
|
||||||
error = xpad->pad_nr;
|
error = xpad->pad_nr;
|
||||||
goto err_free_mem;
|
goto err_free_mem;
|
||||||
|
@ -1693,7 +1693,7 @@ static int xpad_led_probe(struct usb_xpad *xpad)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_free_id:
|
err_free_id:
|
||||||
ida_simple_remove(&xpad_pad_seq, xpad->pad_nr);
|
ida_free(&xpad_pad_seq, xpad->pad_nr);
|
||||||
err_free_mem:
|
err_free_mem:
|
||||||
kfree(led);
|
kfree(led);
|
||||||
xpad->led = NULL;
|
xpad->led = NULL;
|
||||||
|
@ -1706,7 +1706,7 @@ static void xpad_led_disconnect(struct usb_xpad *xpad)
|
||||||
|
|
||||||
if (xpad_led) {
|
if (xpad_led) {
|
||||||
led_classdev_unregister(&xpad_led->led_cdev);
|
led_classdev_unregister(&xpad_led->led_cdev);
|
||||||
ida_simple_remove(&xpad_pad_seq, xpad->pad_nr);
|
ida_free(&xpad_pad_seq, xpad->pad_nr);
|
||||||
kfree(xpad_led);
|
kfree(xpad_led);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -791,9 +791,9 @@ static bool atkbd_is_portable_device(void)
|
||||||
* not work. So in this case simply assume a keyboard is connected to avoid
|
* not work. So in this case simply assume a keyboard is connected to avoid
|
||||||
* confusing some laptop keyboards.
|
* confusing some laptop keyboards.
|
||||||
*
|
*
|
||||||
* Skipping ATKBD_CMD_GETID ends up using a fake keyboard id. Using a fake id is
|
* Skipping ATKBD_CMD_GETID ends up using a fake keyboard id. Using the standard
|
||||||
* ok in translated mode, only atkbd_select_set() checks atkbd->id and in
|
* 0xab83 id is ok in translated mode, only atkbd_select_set() checks atkbd->id
|
||||||
* translated mode that is a no-op.
|
* and in translated mode that is a no-op.
|
||||||
*/
|
*/
|
||||||
static bool atkbd_skip_getid(struct atkbd *atkbd)
|
static bool atkbd_skip_getid(struct atkbd *atkbd)
|
||||||
{
|
{
|
||||||
|
@ -811,6 +811,7 @@ static int atkbd_probe(struct atkbd *atkbd)
|
||||||
{
|
{
|
||||||
struct ps2dev *ps2dev = &atkbd->ps2dev;
|
struct ps2dev *ps2dev = &atkbd->ps2dev;
|
||||||
unsigned char param[2];
|
unsigned char param[2];
|
||||||
|
bool skip_getid;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some systems, where the bit-twiddling when testing the io-lines of the
|
* Some systems, where the bit-twiddling when testing the io-lines of the
|
||||||
|
@ -832,7 +833,8 @@ static int atkbd_probe(struct atkbd *atkbd)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
param[0] = param[1] = 0xa5; /* initialize with invalid values */
|
param[0] = param[1] = 0xa5; /* initialize with invalid values */
|
||||||
if (atkbd_skip_getid(atkbd) || ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
|
skip_getid = atkbd_skip_getid(atkbd);
|
||||||
|
if (skip_getid || ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the get ID command was skipped or failed, we check if we can at least set
|
* If the get ID command was skipped or failed, we check if we can at least set
|
||||||
|
@ -842,7 +844,7 @@ static int atkbd_probe(struct atkbd *atkbd)
|
||||||
param[0] = 0;
|
param[0] = 0;
|
||||||
if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
|
if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
|
||||||
return -1;
|
return -1;
|
||||||
atkbd->id = 0xabba;
|
atkbd->id = skip_getid ? 0xab83 : 0xabba;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,11 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/leds.h>
|
#include <linux/leds.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
|
||||||
#define CAP11XX_REG_MAIN_CONTROL 0x00
|
#define CAP11XX_REG_MAIN_CONTROL 0x00
|
||||||
#define CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT (6)
|
#define CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT (6)
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
#define CAP11XX_REG_NOISE_FLAG_STATUS 0x0a
|
#define CAP11XX_REG_NOISE_FLAG_STATUS 0x0a
|
||||||
#define CAP11XX_REG_SENOR_DELTA(X) (0x10 + (X))
|
#define CAP11XX_REG_SENOR_DELTA(X) (0x10 + (X))
|
||||||
#define CAP11XX_REG_SENSITIVITY_CONTROL 0x1f
|
#define CAP11XX_REG_SENSITIVITY_CONTROL 0x1f
|
||||||
|
#define CAP11XX_REG_SENSITIVITY_CONTROL_DELTA_SENSE_MASK 0x70
|
||||||
#define CAP11XX_REG_CONFIG 0x20
|
#define CAP11XX_REG_CONFIG 0x20
|
||||||
#define CAP11XX_REG_SENSOR_ENABLE 0x21
|
#define CAP11XX_REG_SENSOR_ENABLE 0x21
|
||||||
#define CAP11XX_REG_SENSOR_CONFIG 0x22
|
#define CAP11XX_REG_SENSOR_CONFIG 0x22
|
||||||
|
@ -32,6 +34,7 @@
|
||||||
#define CAP11XX_REG_CALIBRATION 0x26
|
#define CAP11XX_REG_CALIBRATION 0x26
|
||||||
#define CAP11XX_REG_INT_ENABLE 0x27
|
#define CAP11XX_REG_INT_ENABLE 0x27
|
||||||
#define CAP11XX_REG_REPEAT_RATE 0x28
|
#define CAP11XX_REG_REPEAT_RATE 0x28
|
||||||
|
#define CAP11XX_REG_SIGNAL_GUARD_ENABLE 0x29
|
||||||
#define CAP11XX_REG_MT_CONFIG 0x2a
|
#define CAP11XX_REG_MT_CONFIG 0x2a
|
||||||
#define CAP11XX_REG_MT_PATTERN_CONFIG 0x2b
|
#define CAP11XX_REG_MT_PATTERN_CONFIG 0x2b
|
||||||
#define CAP11XX_REG_MT_PATTERN 0x2d
|
#define CAP11XX_REG_MT_PATTERN 0x2d
|
||||||
|
@ -47,6 +50,8 @@
|
||||||
#define CAP11XX_REG_SENSOR_BASE_CNT(X) (0x50 + (X))
|
#define CAP11XX_REG_SENSOR_BASE_CNT(X) (0x50 + (X))
|
||||||
#define CAP11XX_REG_LED_POLARITY 0x73
|
#define CAP11XX_REG_LED_POLARITY 0x73
|
||||||
#define CAP11XX_REG_LED_OUTPUT_CONTROL 0x74
|
#define CAP11XX_REG_LED_OUTPUT_CONTROL 0x74
|
||||||
|
#define CAP11XX_REG_CALIB_SENSITIVITY_CONFIG 0x80
|
||||||
|
#define CAP11XX_REG_CALIB_SENSITIVITY_CONFIG2 0x81
|
||||||
|
|
||||||
#define CAP11XX_REG_LED_DUTY_CYCLE_1 0x90
|
#define CAP11XX_REG_LED_DUTY_CYCLE_1 0x90
|
||||||
#define CAP11XX_REG_LED_DUTY_CYCLE_2 0x91
|
#define CAP11XX_REG_LED_DUTY_CYCLE_2 0x91
|
||||||
|
@ -78,12 +83,20 @@ struct cap11xx_led {
|
||||||
|
|
||||||
struct cap11xx_priv {
|
struct cap11xx_priv {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
|
struct device *dev;
|
||||||
struct input_dev *idev;
|
struct input_dev *idev;
|
||||||
|
const struct cap11xx_hw_model *model;
|
||||||
|
u8 id;
|
||||||
|
|
||||||
struct cap11xx_led *leds;
|
struct cap11xx_led *leds;
|
||||||
int num_leds;
|
int num_leds;
|
||||||
|
|
||||||
/* config */
|
/* config */
|
||||||
|
u8 analog_gain;
|
||||||
|
u8 sensitivity_delta_sense;
|
||||||
|
u8 signal_guard_inputs_mask;
|
||||||
|
u32 thresholds[8];
|
||||||
|
u32 calib_sensitivities[8];
|
||||||
u32 keycodes[];
|
u32 keycodes[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -160,9 +173,6 @@ static bool cap11xx_volatile_reg(struct device *dev, unsigned int reg)
|
||||||
case CAP11XX_REG_SENOR_DELTA(3):
|
case CAP11XX_REG_SENOR_DELTA(3):
|
||||||
case CAP11XX_REG_SENOR_DELTA(4):
|
case CAP11XX_REG_SENOR_DELTA(4):
|
||||||
case CAP11XX_REG_SENOR_DELTA(5):
|
case CAP11XX_REG_SENOR_DELTA(5):
|
||||||
case CAP11XX_REG_PRODUCT_ID:
|
|
||||||
case CAP11XX_REG_MANUFACTURER_ID:
|
|
||||||
case CAP11XX_REG_REVISION:
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,10 +187,179 @@ static const struct regmap_config cap11xx_regmap_config = {
|
||||||
.reg_defaults = cap11xx_reg_defaults,
|
.reg_defaults = cap11xx_reg_defaults,
|
||||||
|
|
||||||
.num_reg_defaults = ARRAY_SIZE(cap11xx_reg_defaults),
|
.num_reg_defaults = ARRAY_SIZE(cap11xx_reg_defaults),
|
||||||
.cache_type = REGCACHE_RBTREE,
|
.cache_type = REGCACHE_MAPLE,
|
||||||
.volatile_reg = cap11xx_volatile_reg,
|
.volatile_reg = cap11xx_volatile_reg,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int cap11xx_write_calib_sens_config_1(struct cap11xx_priv *priv)
|
||||||
|
{
|
||||||
|
return regmap_write(priv->regmap,
|
||||||
|
CAP11XX_REG_CALIB_SENSITIVITY_CONFIG,
|
||||||
|
(priv->calib_sensitivities[3] << 6) |
|
||||||
|
(priv->calib_sensitivities[2] << 4) |
|
||||||
|
(priv->calib_sensitivities[1] << 2) |
|
||||||
|
priv->calib_sensitivities[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cap11xx_write_calib_sens_config_2(struct cap11xx_priv *priv)
|
||||||
|
{
|
||||||
|
return regmap_write(priv->regmap,
|
||||||
|
CAP11XX_REG_CALIB_SENSITIVITY_CONFIG2,
|
||||||
|
(priv->calib_sensitivities[7] << 6) |
|
||||||
|
(priv->calib_sensitivities[6] << 4) |
|
||||||
|
(priv->calib_sensitivities[5] << 2) |
|
||||||
|
priv->calib_sensitivities[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cap11xx_init_keys(struct cap11xx_priv *priv)
|
||||||
|
{
|
||||||
|
struct device_node *node = priv->dev->of_node;
|
||||||
|
struct device *dev = priv->dev;
|
||||||
|
int i, error;
|
||||||
|
u32 u32_val;
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
dev_err(dev, "Corresponding DT entry is not available\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!of_property_read_u32(node, "microchip,sensor-gain", &u32_val)) {
|
||||||
|
if (priv->model->no_gain) {
|
||||||
|
dev_warn(dev,
|
||||||
|
"This model doesn't support 'sensor-gain'\n");
|
||||||
|
} else if (is_power_of_2(u32_val) && u32_val <= 8) {
|
||||||
|
priv->analog_gain = (u8)ilog2(u32_val);
|
||||||
|
|
||||||
|
error = regmap_update_bits(priv->regmap,
|
||||||
|
CAP11XX_REG_MAIN_CONTROL,
|
||||||
|
CAP11XX_REG_MAIN_CONTROL_GAIN_MASK,
|
||||||
|
priv->analog_gain << CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
} else {
|
||||||
|
dev_err(dev, "Invalid sensor-gain value %u\n", u32_val);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of_property_read_bool(node, "microchip,irq-active-high")) {
|
||||||
|
if (priv->id == CAP1106 ||
|
||||||
|
priv->id == CAP1126 ||
|
||||||
|
priv->id == CAP1188) {
|
||||||
|
error = regmap_update_bits(priv->regmap,
|
||||||
|
CAP11XX_REG_CONFIG2,
|
||||||
|
CAP11XX_REG_CONFIG2_ALT_POL,
|
||||||
|
0);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
} else {
|
||||||
|
dev_warn(dev,
|
||||||
|
"This model doesn't support 'irq-active-high'\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!of_property_read_u32(node, "microchip,sensitivity-delta-sense", &u32_val)) {
|
||||||
|
if (!is_power_of_2(u32_val) || u32_val > 128) {
|
||||||
|
dev_err(dev, "Invalid sensitivity-delta-sense value %u\n", u32_val);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->sensitivity_delta_sense = (u8)ilog2(u32_val);
|
||||||
|
u32_val = ~(FIELD_PREP(CAP11XX_REG_SENSITIVITY_CONTROL_DELTA_SENSE_MASK,
|
||||||
|
priv->sensitivity_delta_sense));
|
||||||
|
|
||||||
|
error = regmap_update_bits(priv->regmap,
|
||||||
|
CAP11XX_REG_SENSITIVITY_CONTROL,
|
||||||
|
CAP11XX_REG_SENSITIVITY_CONTROL_DELTA_SENSE_MASK,
|
||||||
|
u32_val);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!of_property_read_u32_array(node, "microchip,input-threshold",
|
||||||
|
priv->thresholds, priv->model->num_channels)) {
|
||||||
|
for (i = 0; i < priv->model->num_channels; i++) {
|
||||||
|
if (priv->thresholds[i] > 127) {
|
||||||
|
dev_err(dev, "Invalid input-threshold value %u\n",
|
||||||
|
priv->thresholds[i]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = regmap_write(priv->regmap,
|
||||||
|
CAP11XX_REG_SENSOR_THRESH(i),
|
||||||
|
priv->thresholds[i]);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!of_property_read_u32_array(node, "microchip,calib-sensitivity",
|
||||||
|
priv->calib_sensitivities,
|
||||||
|
priv->model->num_channels)) {
|
||||||
|
if (priv->id == CAP1293 || priv->id == CAP1298) {
|
||||||
|
for (i = 0; i < priv->model->num_channels; i++) {
|
||||||
|
if (!is_power_of_2(priv->calib_sensitivities[i]) ||
|
||||||
|
priv->calib_sensitivities[i] > 4) {
|
||||||
|
dev_err(dev, "Invalid calib-sensitivity value %u\n",
|
||||||
|
priv->calib_sensitivities[i]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
priv->calib_sensitivities[i] = ilog2(priv->calib_sensitivities[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = cap11xx_write_calib_sens_config_1(priv);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (priv->id == CAP1298) {
|
||||||
|
error = cap11xx_write_calib_sens_config_2(priv);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dev_warn(dev,
|
||||||
|
"This model doesn't support 'calib-sensitivity'\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < priv->model->num_channels; i++) {
|
||||||
|
if (!of_property_read_u32_index(node, "microchip,signal-guard",
|
||||||
|
i, &u32_val)) {
|
||||||
|
if (u32_val > 1)
|
||||||
|
return -EINVAL;
|
||||||
|
if (u32_val)
|
||||||
|
priv->signal_guard_inputs_mask |= 0x01 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->signal_guard_inputs_mask) {
|
||||||
|
if (priv->id == CAP1293 || priv->id == CAP1298) {
|
||||||
|
error = regmap_write(priv->regmap,
|
||||||
|
CAP11XX_REG_SIGNAL_GUARD_ENABLE,
|
||||||
|
priv->signal_guard_inputs_mask);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
} else {
|
||||||
|
dev_warn(dev,
|
||||||
|
"This model doesn't support 'signal-guard'\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Provide some useful defaults */
|
||||||
|
for (i = 0; i < priv->model->num_channels; i++)
|
||||||
|
priv->keycodes[i] = KEY_A + i;
|
||||||
|
|
||||||
|
of_property_read_u32_array(node, "linux,keycodes",
|
||||||
|
priv->keycodes, priv->model->num_channels);
|
||||||
|
|
||||||
|
/* Disable autorepeat. The Linux input system has its own handling. */
|
||||||
|
error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static irqreturn_t cap11xx_thread_func(int irq_num, void *data)
|
static irqreturn_t cap11xx_thread_func(int irq_num, void *data)
|
||||||
{
|
{
|
||||||
struct cap11xx_priv *priv = data;
|
struct cap11xx_priv *priv = data;
|
||||||
|
@ -332,11 +511,9 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
|
||||||
const struct i2c_device_id *id = i2c_client_get_device_id(i2c_client);
|
const struct i2c_device_id *id = i2c_client_get_device_id(i2c_client);
|
||||||
struct device *dev = &i2c_client->dev;
|
struct device *dev = &i2c_client->dev;
|
||||||
struct cap11xx_priv *priv;
|
struct cap11xx_priv *priv;
|
||||||
struct device_node *node;
|
|
||||||
const struct cap11xx_hw_model *cap;
|
const struct cap11xx_hw_model *cap;
|
||||||
int i, error, irq, gain = 0;
|
int i, error;
|
||||||
unsigned int val, rev;
|
unsigned int val, rev;
|
||||||
u32 gain32;
|
|
||||||
|
|
||||||
if (id->driver_data >= ARRAY_SIZE(cap11xx_devices)) {
|
if (id->driver_data >= ARRAY_SIZE(cap11xx_devices)) {
|
||||||
dev_err(dev, "Invalid device ID %lu\n", id->driver_data);
|
dev_err(dev, "Invalid device ID %lu\n", id->driver_data);
|
||||||
|
@ -355,6 +532,8 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->dev = dev;
|
||||||
|
|
||||||
priv->regmap = devm_regmap_init_i2c(i2c_client, &cap11xx_regmap_config);
|
priv->regmap = devm_regmap_init_i2c(i2c_client, &cap11xx_regmap_config);
|
||||||
if (IS_ERR(priv->regmap))
|
if (IS_ERR(priv->regmap))
|
||||||
return PTR_ERR(priv->regmap);
|
return PTR_ERR(priv->regmap);
|
||||||
|
@ -385,49 +564,14 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
|
||||||
|
|
||||||
dev_info(dev, "CAP11XX detected, model %s, revision 0x%02x\n",
|
dev_info(dev, "CAP11XX detected, model %s, revision 0x%02x\n",
|
||||||
id->name, rev);
|
id->name, rev);
|
||||||
node = dev->of_node;
|
|
||||||
|
|
||||||
if (!of_property_read_u32(node, "microchip,sensor-gain", &gain32)) {
|
priv->model = cap;
|
||||||
if (cap->no_gain)
|
priv->id = id->driver_data;
|
||||||
dev_warn(dev,
|
|
||||||
"This version doesn't support sensor gain\n");
|
|
||||||
else if (is_power_of_2(gain32) && gain32 <= 8)
|
|
||||||
gain = ilog2(gain32);
|
|
||||||
else
|
|
||||||
dev_err(dev, "Invalid sensor-gain value %d\n", gain32);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id->driver_data == CAP1106 ||
|
dev_info(dev, "CAP11XX device detected, model %s, revision 0x%02x\n",
|
||||||
id->driver_data == CAP1126 ||
|
id->name, rev);
|
||||||
id->driver_data == CAP1188) {
|
|
||||||
if (of_property_read_bool(node, "microchip,irq-active-high")) {
|
|
||||||
error = regmap_update_bits(priv->regmap,
|
|
||||||
CAP11XX_REG_CONFIG2,
|
|
||||||
CAP11XX_REG_CONFIG2_ALT_POL,
|
|
||||||
0);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Provide some useful defaults */
|
error = cap11xx_init_keys(priv);
|
||||||
for (i = 0; i < cap->num_channels; i++)
|
|
||||||
priv->keycodes[i] = KEY_A + i;
|
|
||||||
|
|
||||||
of_property_read_u32_array(node, "linux,keycodes",
|
|
||||||
priv->keycodes, cap->num_channels);
|
|
||||||
|
|
||||||
if (!cap->no_gain) {
|
|
||||||
error = regmap_update_bits(priv->regmap,
|
|
||||||
CAP11XX_REG_MAIN_CONTROL,
|
|
||||||
CAP11XX_REG_MAIN_CONTROL_GAIN_MASK,
|
|
||||||
gain << CAP11XX_REG_MAIN_CONTROL_GAIN_SHIFT);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable autorepeat. The Linux input system has its own handling. */
|
|
||||||
error = regmap_write(priv->regmap, CAP11XX_REG_REPEAT_RATE, 0);
|
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
@ -439,7 +583,7 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
|
||||||
priv->idev->id.bustype = BUS_I2C;
|
priv->idev->id.bustype = BUS_I2C;
|
||||||
priv->idev->evbit[0] = BIT_MASK(EV_KEY);
|
priv->idev->evbit[0] = BIT_MASK(EV_KEY);
|
||||||
|
|
||||||
if (of_property_read_bool(node, "autorepeat"))
|
if (of_property_read_bool(dev->of_node, "autorepeat"))
|
||||||
__set_bit(EV_REP, priv->idev->evbit);
|
__set_bit(EV_REP, priv->idev->evbit);
|
||||||
|
|
||||||
for (i = 0; i < cap->num_channels; i++)
|
for (i = 0; i < cap->num_channels; i++)
|
||||||
|
@ -474,13 +618,8 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
irq = irq_of_parse_and_map(node, 0);
|
error = devm_request_threaded_irq(dev, i2c_client->irq,
|
||||||
if (!irq) {
|
NULL, cap11xx_thread_func,
|
||||||
dev_err(dev, "Unable to parse or map IRQ\n");
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = devm_request_threaded_irq(dev, irq, NULL, cap11xx_thread_func,
|
|
||||||
IRQF_ONESHOT, dev_name(dev), priv);
|
IRQF_ONESHOT, dev_name(dev), priv);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
|
@ -45,7 +45,9 @@ struct gpio_button_data {
|
||||||
unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */
|
unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */
|
||||||
|
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
|
unsigned int wakeirq;
|
||||||
unsigned int wakeup_trigger_type;
|
unsigned int wakeup_trigger_type;
|
||||||
|
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
bool disabled;
|
bool disabled;
|
||||||
bool key_pressed;
|
bool key_pressed;
|
||||||
|
@ -511,6 +513,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||||
struct gpio_button_data *bdata = &ddata->data[idx];
|
struct gpio_button_data *bdata = &ddata->data[idx];
|
||||||
irq_handler_t isr;
|
irq_handler_t isr;
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
const char *wakedesc;
|
||||||
int irq;
|
int irq;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
@ -575,15 +578,23 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||||
!gpiod_cansleep(bdata->gpiod);
|
!gpiod_cansleep(bdata->gpiod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If an interrupt was specified, use it instead of the gpio
|
||||||
|
* interrupt and use the gpio for reading the state. A separate
|
||||||
|
* interrupt may be used as the main button interrupt for
|
||||||
|
* runtime PM to detect events also in deeper idle states. If a
|
||||||
|
* dedicated wakeirq is used for system suspend only, see below
|
||||||
|
* for bdata->wakeirq setup.
|
||||||
|
*/
|
||||||
if (button->irq) {
|
if (button->irq) {
|
||||||
bdata->irq = button->irq;
|
bdata->irq = button->irq;
|
||||||
} else {
|
} else {
|
||||||
irq = gpiod_to_irq(bdata->gpiod);
|
irq = gpiod_to_irq(bdata->gpiod);
|
||||||
if (irq < 0) {
|
if (irq < 0) {
|
||||||
error = irq;
|
error = irq;
|
||||||
dev_err(dev,
|
dev_err_probe(dev, error,
|
||||||
"Unable to get irq number for GPIO %d, error %d\n",
|
"Unable to get irq number for GPIO %d\n",
|
||||||
button->gpio, error);
|
button->gpio);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
bdata->irq = irq;
|
bdata->irq = irq;
|
||||||
|
@ -672,6 +683,36 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!button->wakeirq)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Use :wakeup suffix like drivers/base/power/wakeirq.c does */
|
||||||
|
wakedesc = devm_kasprintf(dev, GFP_KERNEL, "%s:wakeup", desc);
|
||||||
|
if (!wakedesc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
bdata->wakeirq = button->wakeirq;
|
||||||
|
irqflags |= IRQF_NO_SUSPEND;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wakeirq shares the handler with the main interrupt, it's only
|
||||||
|
* active during system suspend. See gpio_keys_button_enable_wakeup()
|
||||||
|
* and gpio_keys_button_disable_wakeup().
|
||||||
|
*/
|
||||||
|
error = devm_request_any_context_irq(dev, bdata->wakeirq, isr,
|
||||||
|
irqflags, wakedesc, bdata);
|
||||||
|
if (error < 0) {
|
||||||
|
dev_err(dev, "Unable to claim wakeirq %d; error %d\n",
|
||||||
|
bdata->irq, error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable wakeirq until suspend. IRQF_NO_AUTOEN won't work if
|
||||||
|
* IRQF_SHARED was set based on !button->can_disable.
|
||||||
|
*/
|
||||||
|
disable_irq(bdata->wakeirq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,7 +769,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
|
||||||
struct gpio_keys_platform_data *pdata;
|
struct gpio_keys_platform_data *pdata;
|
||||||
struct gpio_keys_button *button;
|
struct gpio_keys_button *button;
|
||||||
struct fwnode_handle *child;
|
struct fwnode_handle *child;
|
||||||
int nbuttons;
|
int nbuttons, irq;
|
||||||
|
|
||||||
nbuttons = device_get_child_node_count(dev);
|
nbuttons = device_get_child_node_count(dev);
|
||||||
if (nbuttons == 0)
|
if (nbuttons == 0)
|
||||||
|
@ -750,9 +791,19 @@ gpio_keys_get_devtree_pdata(struct device *dev)
|
||||||
device_property_read_string(dev, "label", &pdata->name);
|
device_property_read_string(dev, "label", &pdata->name);
|
||||||
|
|
||||||
device_for_each_child_node(dev, child) {
|
device_for_each_child_node(dev, child) {
|
||||||
if (is_of_node(child))
|
if (is_of_node(child)) {
|
||||||
|
irq = of_irq_get_byname(to_of_node(child), "irq");
|
||||||
|
if (irq > 0)
|
||||||
|
button->irq = irq;
|
||||||
|
|
||||||
|
irq = of_irq_get_byname(to_of_node(child), "wakeup");
|
||||||
|
if (irq > 0)
|
||||||
|
button->wakeirq = irq;
|
||||||
|
|
||||||
|
if (!button->irq && !button->wakeirq)
|
||||||
button->irq =
|
button->irq =
|
||||||
irq_of_parse_and_map(to_of_node(child), 0);
|
irq_of_parse_and_map(to_of_node(child), 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (fwnode_property_read_u32(child, "linux,code",
|
if (fwnode_property_read_u32(child, "linux,code",
|
||||||
&button->code)) {
|
&button->code)) {
|
||||||
|
@ -921,6 +972,11 @@ gpio_keys_button_enable_wakeup(struct gpio_button_data *bdata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bdata->wakeirq) {
|
||||||
|
enable_irq(bdata->wakeirq);
|
||||||
|
disable_irq(bdata->irq);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,6 +985,11 @@ gpio_keys_button_disable_wakeup(struct gpio_button_data *bdata)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
if (bdata->wakeirq) {
|
||||||
|
enable_irq(bdata->irq);
|
||||||
|
disable_irq(bdata->wakeirq);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The trigger type is always both edges for gpio-based keys and we do
|
* The trigger type is always both edges for gpio-based keys and we do
|
||||||
* not support changing wakeup trigger for interrupt-based keys.
|
* not support changing wakeup trigger for interrupt-based keys.
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/platform_data/gpio-omap.h>
|
#include <linux/platform_data/gpio-omap.h>
|
||||||
#include <linux/platform_data/keypad-omap.h>
|
#include <linux/platform_data/keypad-omap.h>
|
||||||
#include <linux/soc/ti/omap1-io.h>
|
#include <linux/soc/ti/omap1-io.h>
|
||||||
|
@ -49,9 +48,6 @@ struct omap_kp {
|
||||||
|
|
||||||
static DECLARE_TASKLET_DISABLED_OLD(kp_tasklet, omap_kp_tasklet);
|
static DECLARE_TASKLET_DISABLED_OLD(kp_tasklet, omap_kp_tasklet);
|
||||||
|
|
||||||
static unsigned int *row_gpios;
|
|
||||||
static unsigned int *col_gpios;
|
|
||||||
|
|
||||||
static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
|
static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
/* disable keyboard interrupt and schedule for handling */
|
/* disable keyboard interrupt and schedule for handling */
|
||||||
|
@ -180,7 +176,7 @@ static int omap_kp_probe(struct platform_device *pdev)
|
||||||
struct omap_kp *omap_kp;
|
struct omap_kp *omap_kp;
|
||||||
struct input_dev *input_dev;
|
struct input_dev *input_dev;
|
||||||
struct omap_kp_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
struct omap_kp_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||||
int i, col_idx, row_idx, ret;
|
int ret;
|
||||||
unsigned int row_shift, keycodemax;
|
unsigned int row_shift, keycodemax;
|
||||||
|
|
||||||
if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
|
if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
|
||||||
|
@ -209,17 +205,9 @@ static int omap_kp_probe(struct platform_device *pdev)
|
||||||
if (pdata->delay)
|
if (pdata->delay)
|
||||||
omap_kp->delay = pdata->delay;
|
omap_kp->delay = pdata->delay;
|
||||||
|
|
||||||
if (pdata->row_gpios && pdata->col_gpios) {
|
|
||||||
row_gpios = pdata->row_gpios;
|
|
||||||
col_gpios = pdata->col_gpios;
|
|
||||||
}
|
|
||||||
|
|
||||||
omap_kp->rows = pdata->rows;
|
omap_kp->rows = pdata->rows;
|
||||||
omap_kp->cols = pdata->cols;
|
omap_kp->cols = pdata->cols;
|
||||||
|
|
||||||
col_idx = 0;
|
|
||||||
row_idx = 0;
|
|
||||||
|
|
||||||
timer_setup(&omap_kp->timer, omap_kp_timer, 0);
|
timer_setup(&omap_kp->timer, omap_kp_timer, 0);
|
||||||
|
|
||||||
/* get the irq and init timer*/
|
/* get the irq and init timer*/
|
||||||
|
@ -276,11 +264,6 @@ static int omap_kp_probe(struct platform_device *pdev)
|
||||||
err3:
|
err3:
|
||||||
device_remove_file(&pdev->dev, &dev_attr_enable);
|
device_remove_file(&pdev->dev, &dev_attr_enable);
|
||||||
err2:
|
err2:
|
||||||
for (i = row_idx - 1; i >= 0; i--)
|
|
||||||
gpio_free(row_gpios[i]);
|
|
||||||
for (i = col_idx - 1; i >= 0; i--)
|
|
||||||
gpio_free(col_gpios[i]);
|
|
||||||
|
|
||||||
kfree(omap_kp);
|
kfree(omap_kp);
|
||||||
input_free_device(input_dev);
|
input_free_device(input_dev);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
@ -83,6 +84,7 @@ struct omap4_keypad {
|
||||||
bool no_autorepeat;
|
bool no_autorepeat;
|
||||||
u64 keys;
|
u64 keys;
|
||||||
unsigned short *keymap;
|
unsigned short *keymap;
|
||||||
|
struct clk *fck;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset)
|
static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset)
|
||||||
|
@ -209,6 +211,10 @@ static int omap4_keypad_open(struct input_dev *input)
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
error = clk_prepare_enable(keypad_data->fck);
|
||||||
|
if (error)
|
||||||
|
goto out;
|
||||||
|
|
||||||
disable_irq(keypad_data->irq);
|
disable_irq(keypad_data->irq);
|
||||||
|
|
||||||
kbd_writel(keypad_data, OMAP4_KBD_CTRL,
|
kbd_writel(keypad_data, OMAP4_KBD_CTRL,
|
||||||
|
@ -226,10 +232,11 @@ static int omap4_keypad_open(struct input_dev *input)
|
||||||
|
|
||||||
enable_irq(keypad_data->irq);
|
enable_irq(keypad_data->irq);
|
||||||
|
|
||||||
|
out:
|
||||||
pm_runtime_mark_last_busy(dev);
|
pm_runtime_mark_last_busy(dev);
|
||||||
pm_runtime_put_autosuspend(dev);
|
pm_runtime_put_autosuspend(dev);
|
||||||
|
|
||||||
return 0;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void omap4_keypad_stop(struct omap4_keypad *keypad_data)
|
static void omap4_keypad_stop(struct omap4_keypad *keypad_data)
|
||||||
|
@ -258,6 +265,7 @@ static void omap4_keypad_close(struct input_dev *input)
|
||||||
disable_irq(keypad_data->irq);
|
disable_irq(keypad_data->irq);
|
||||||
omap4_keypad_stop(keypad_data);
|
omap4_keypad_stop(keypad_data);
|
||||||
enable_irq(keypad_data->irq);
|
enable_irq(keypad_data->irq);
|
||||||
|
clk_disable_unprepare(keypad_data->fck);
|
||||||
|
|
||||||
pm_runtime_mark_last_busy(dev);
|
pm_runtime_mark_last_busy(dev);
|
||||||
pm_runtime_put_autosuspend(dev);
|
pm_runtime_put_autosuspend(dev);
|
||||||
|
@ -356,6 +364,11 @@ static int omap4_keypad_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
keypad_data->irq = irq;
|
keypad_data->irq = irq;
|
||||||
|
keypad_data->fck = devm_clk_get(&pdev->dev, "fck");
|
||||||
|
if (IS_ERR(keypad_data->fck))
|
||||||
|
return dev_err_probe(&pdev->dev, PTR_ERR(keypad_data->fck),
|
||||||
|
"unable to get fck");
|
||||||
|
|
||||||
mutex_init(&keypad_data->lock);
|
mutex_init(&keypad_data->lock);
|
||||||
platform_set_drvdata(pdev, keypad_data);
|
platform_set_drvdata(pdev, keypad_data);
|
||||||
|
|
||||||
|
|
|
@ -213,7 +213,7 @@ static struct regmap_config qt1050_regmap_config = {
|
||||||
.val_bits = 8,
|
.val_bits = 8,
|
||||||
.max_register = QT1050_RES_CAL,
|
.max_register = QT1050_RES_CAL,
|
||||||
|
|
||||||
.cache_type = REGCACHE_RBTREE,
|
.cache_type = REGCACHE_MAPLE,
|
||||||
|
|
||||||
.wr_table = &qt1050_writeable_table,
|
.wr_table = &qt1050_writeable_table,
|
||||||
.rd_table = &qt1050_readable_table,
|
.rd_table = &qt1050_readable_table,
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/gpio.h>
|
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/tca6416_keypad.h>
|
#include <linux/tca6416_keypad.h>
|
||||||
|
|
|
@ -9,11 +9,12 @@
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/mod_devicetable.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm_wakeirq.h>
|
#include <linux/pm_wakeirq.h>
|
||||||
|
#include <linux/property.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/mfd/da9063/core.h>
|
#include <linux/mfd/da9063/core.h>
|
||||||
#include <linux/mfd/da9063/registers.h>
|
#include <linux/mfd/da9063/registers.h>
|
||||||
#include <linux/mfd/da9062/core.h>
|
#include <linux/mfd/da9062/core.h>
|
||||||
|
@ -74,13 +75,6 @@ static const struct da906x_chip_config da9062_regs = {
|
||||||
.name = "da9062-onkey",
|
.name = "da9062-onkey",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id da9063_compatible_reg_id_table[] = {
|
|
||||||
{ .compatible = "dlg,da9063-onkey", .data = &da9063_regs },
|
|
||||||
{ .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
|
|
||||||
{ },
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
|
|
||||||
|
|
||||||
static void da9063_poll_on(struct work_struct *work)
|
static void da9063_poll_on(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct da9063_onkey *onkey = container_of(work,
|
struct da9063_onkey *onkey = container_of(work,
|
||||||
|
@ -187,56 +181,43 @@ static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
|
||||||
static int da9063_onkey_probe(struct platform_device *pdev)
|
static int da9063_onkey_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct da9063_onkey *onkey;
|
struct da9063_onkey *onkey;
|
||||||
const struct of_device_id *match;
|
|
||||||
int irq;
|
|
||||||
int error;
|
int error;
|
||||||
|
int irq;
|
||||||
match = of_match_node(da9063_compatible_reg_id_table,
|
|
||||||
pdev->dev.of_node);
|
|
||||||
if (!match)
|
|
||||||
return -ENXIO;
|
|
||||||
|
|
||||||
onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey),
|
onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!onkey) {
|
if (!onkey)
|
||||||
dev_err(&pdev->dev, "Failed to allocate memory.\n");
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
onkey->config = match->data;
|
onkey->config = device_get_match_data(&pdev->dev);
|
||||||
|
if (!onkey->config)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
onkey->dev = &pdev->dev;
|
onkey->dev = &pdev->dev;
|
||||||
|
|
||||||
onkey->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
onkey->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||||
if (!onkey->regmap) {
|
if (!onkey->regmap)
|
||||||
dev_err(&pdev->dev, "Parent regmap unavailable.\n");
|
return dev_err_probe(&pdev->dev, -ENXIO,
|
||||||
return -ENXIO;
|
"Parent regmap unavailable.\n");
|
||||||
}
|
|
||||||
|
|
||||||
onkey->key_power = !of_property_read_bool(pdev->dev.of_node,
|
onkey->key_power = !device_property_read_bool(&pdev->dev,
|
||||||
"dlg,disable-key-power");
|
"dlg,disable-key-power");
|
||||||
|
|
||||||
onkey->input = devm_input_allocate_device(&pdev->dev);
|
onkey->input = devm_input_allocate_device(&pdev->dev);
|
||||||
if (!onkey->input) {
|
if (!onkey->input)
|
||||||
dev_err(&pdev->dev, "Failed to allocated input device.\n");
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
onkey->input->name = onkey->config->name;
|
onkey->input->name = onkey->config->name;
|
||||||
snprintf(onkey->phys, sizeof(onkey->phys), "%s/input0",
|
snprintf(onkey->phys, sizeof(onkey->phys), "%s/input0",
|
||||||
onkey->config->name);
|
onkey->config->name);
|
||||||
onkey->input->phys = onkey->phys;
|
onkey->input->phys = onkey->phys;
|
||||||
onkey->input->dev.parent = &pdev->dev;
|
|
||||||
|
|
||||||
input_set_capability(onkey->input, EV_KEY, KEY_POWER);
|
input_set_capability(onkey->input, EV_KEY, KEY_POWER);
|
||||||
|
|
||||||
error = devm_delayed_work_autocancel(&pdev->dev, &onkey->work,
|
error = devm_delayed_work_autocancel(&pdev->dev, &onkey->work,
|
||||||
da9063_poll_on);
|
da9063_poll_on);
|
||||||
if (error) {
|
if (error)
|
||||||
dev_err(&pdev->dev,
|
|
||||||
"Failed to add cancel poll action: %d\n",
|
|
||||||
error);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
|
|
||||||
irq = platform_get_irq_byname(pdev, "ONKEY");
|
irq = platform_get_irq_byname(pdev, "ONKEY");
|
||||||
if (irq < 0)
|
if (irq < 0)
|
||||||
|
@ -246,11 +227,9 @@ static int da9063_onkey_probe(struct platform_device *pdev)
|
||||||
NULL, da9063_onkey_irq_handler,
|
NULL, da9063_onkey_irq_handler,
|
||||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||||
"ONKEY", onkey);
|
"ONKEY", onkey);
|
||||||
if (error) {
|
if (error)
|
||||||
dev_err(&pdev->dev,
|
return dev_err_probe(&pdev->dev, error,
|
||||||
"Failed to request IRQ %d: %d\n", irq, error);
|
"Failed to allocate onkey IRQ\n");
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = dev_pm_set_wake_irq(&pdev->dev, irq);
|
error = dev_pm_set_wake_irq(&pdev->dev, irq);
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -261,15 +240,19 @@ static int da9063_onkey_probe(struct platform_device *pdev)
|
||||||
device_init_wakeup(&pdev->dev, true);
|
device_init_wakeup(&pdev->dev, true);
|
||||||
|
|
||||||
error = input_register_device(onkey->input);
|
error = input_register_device(onkey->input);
|
||||||
if (error) {
|
if (error)
|
||||||
dev_err(&pdev->dev,
|
|
||||||
"Failed to register input device: %d\n", error);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id da9063_compatible_reg_id_table[] = {
|
||||||
|
{ .compatible = "dlg,da9063-onkey", .data = &da9063_regs },
|
||||||
|
{ .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
|
||||||
|
|
||||||
static struct platform_driver da9063_onkey_driver = {
|
static struct platform_driver da9063_onkey_driver = {
|
||||||
.probe = da9063_onkey_probe,
|
.probe = da9063_onkey_probe,
|
||||||
.driver = {
|
.driver = {
|
||||||
|
|
|
@ -1050,7 +1050,7 @@ static ssize_t ims_pcu_attribute_show(struct device *dev,
|
||||||
container_of(dattr, struct ims_pcu_attribute, dattr);
|
container_of(dattr, struct ims_pcu_attribute, dattr);
|
||||||
char *field = (char *)pcu + attr->field_offset;
|
char *field = (char *)pcu + attr->field_offset;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%.*s\n", attr->field_length, field);
|
return sysfs_emit(buf, "%.*s\n", attr->field_length, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ims_pcu_attribute_store(struct device *dev,
|
static ssize_t ims_pcu_attribute_store(struct device *dev,
|
||||||
|
@ -1206,7 +1206,7 @@ ims_pcu_update_firmware_status_show(struct device *dev,
|
||||||
struct usb_interface *intf = to_usb_interface(dev);
|
struct usb_interface *intf = to_usb_interface(dev);
|
||||||
struct ims_pcu *pcu = usb_get_intfdata(intf);
|
struct ims_pcu *pcu = usb_get_intfdata(intf);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%d\n", pcu->update_firmware_status);
|
return sysfs_emit(buf, "%d\n", pcu->update_firmware_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR(update_firmware_status, S_IRUGO,
|
static DEVICE_ATTR(update_firmware_status, S_IRUGO,
|
||||||
|
@ -1309,7 +1309,7 @@ static ssize_t ims_pcu_ofn_reg_data_show(struct device *dev,
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%x\n", data);
|
return sysfs_emit(buf, "%x\n", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ims_pcu_ofn_reg_data_store(struct device *dev,
|
static ssize_t ims_pcu_ofn_reg_data_store(struct device *dev,
|
||||||
|
@ -1344,7 +1344,7 @@ static ssize_t ims_pcu_ofn_reg_addr_show(struct device *dev,
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
mutex_lock(&pcu->cmd_mutex);
|
mutex_lock(&pcu->cmd_mutex);
|
||||||
error = scnprintf(buf, PAGE_SIZE, "%x\n", pcu->ofn_reg_addr);
|
error = sysfs_emit(buf, "%x\n", pcu->ofn_reg_addr);
|
||||||
mutex_unlock(&pcu->cmd_mutex);
|
mutex_unlock(&pcu->cmd_mutex);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
|
@ -1397,7 +1397,7 @@ static ssize_t ims_pcu_ofn_bit_show(struct device *dev,
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%d\n", !!(data & (1 << attr->nr)));
|
return sysfs_emit(buf, "%d\n", !!(data & (1 << attr->nr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ims_pcu_ofn_bit_store(struct device *dev,
|
static ssize_t ims_pcu_ofn_bit_store(struct device *dev,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
* axial sliders presented by the device.
|
* axial sliders presented by the device.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/bits.h>
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
@ -26,6 +27,8 @@
|
||||||
|
|
||||||
#define IQS269_VER_INFO 0x00
|
#define IQS269_VER_INFO 0x00
|
||||||
#define IQS269_VER_INFO_PROD_NUM 0x4F
|
#define IQS269_VER_INFO_PROD_NUM 0x4F
|
||||||
|
#define IQS269_VER_INFO_FW_NUM_2 0x03
|
||||||
|
#define IQS269_VER_INFO_FW_NUM_3 0x10
|
||||||
|
|
||||||
#define IQS269_SYS_FLAGS 0x02
|
#define IQS269_SYS_FLAGS 0x02
|
||||||
#define IQS269_SYS_FLAGS_SHOW_RESET BIT(15)
|
#define IQS269_SYS_FLAGS_SHOW_RESET BIT(15)
|
||||||
|
@ -53,6 +56,7 @@
|
||||||
#define IQS269_SYS_SETTINGS_ULP_UPDATE_MASK GENMASK(10, 8)
|
#define IQS269_SYS_SETTINGS_ULP_UPDATE_MASK GENMASK(10, 8)
|
||||||
#define IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT 8
|
#define IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT 8
|
||||||
#define IQS269_SYS_SETTINGS_ULP_UPDATE_MAX 7
|
#define IQS269_SYS_SETTINGS_ULP_UPDATE_MAX 7
|
||||||
|
#define IQS269_SYS_SETTINGS_SLIDER_SWIPE BIT(7)
|
||||||
#define IQS269_SYS_SETTINGS_RESEED_OFFSET BIT(6)
|
#define IQS269_SYS_SETTINGS_RESEED_OFFSET BIT(6)
|
||||||
#define IQS269_SYS_SETTINGS_EVENT_MODE BIT(5)
|
#define IQS269_SYS_SETTINGS_EVENT_MODE BIT(5)
|
||||||
#define IQS269_SYS_SETTINGS_EVENT_MODE_LP BIT(4)
|
#define IQS269_SYS_SETTINGS_EVENT_MODE_LP BIT(4)
|
||||||
|
@ -69,6 +73,7 @@
|
||||||
#define IQS269_FILT_STR_MAX 3
|
#define IQS269_FILT_STR_MAX 3
|
||||||
|
|
||||||
#define IQS269_EVENT_MASK_SYS BIT(6)
|
#define IQS269_EVENT_MASK_SYS BIT(6)
|
||||||
|
#define IQS269_EVENT_MASK_GESTURE BIT(3)
|
||||||
#define IQS269_EVENT_MASK_DEEP BIT(2)
|
#define IQS269_EVENT_MASK_DEEP BIT(2)
|
||||||
#define IQS269_EVENT_MASK_TOUCH BIT(1)
|
#define IQS269_EVENT_MASK_TOUCH BIT(1)
|
||||||
#define IQS269_EVENT_MASK_PROX BIT(0)
|
#define IQS269_EVENT_MASK_PROX BIT(0)
|
||||||
|
@ -97,6 +102,15 @@
|
||||||
#define IQS269_MISC_B_TRACKING_UI_ENABLE BIT(4)
|
#define IQS269_MISC_B_TRACKING_UI_ENABLE BIT(4)
|
||||||
#define IQS269_MISC_B_FILT_STR_SLIDER GENMASK(1, 0)
|
#define IQS269_MISC_B_FILT_STR_SLIDER GENMASK(1, 0)
|
||||||
|
|
||||||
|
#define IQS269_TOUCH_HOLD_SLIDER_SEL 0x89
|
||||||
|
#define IQS269_TOUCH_HOLD_DEFAULT 0x14
|
||||||
|
#define IQS269_TOUCH_HOLD_MS_MIN 256
|
||||||
|
#define IQS269_TOUCH_HOLD_MS_MAX 65280
|
||||||
|
|
||||||
|
#define IQS269_TIMEOUT_TAP_MS_MAX 4080
|
||||||
|
#define IQS269_TIMEOUT_SWIPE_MS_MAX 4080
|
||||||
|
#define IQS269_THRESH_SWIPE_MAX 255
|
||||||
|
|
||||||
#define IQS269_CHx_ENG_A_MEAS_CAP_SIZE BIT(15)
|
#define IQS269_CHx_ENG_A_MEAS_CAP_SIZE BIT(15)
|
||||||
#define IQS269_CHx_ENG_A_RX_GND_INACTIVE BIT(13)
|
#define IQS269_CHx_ENG_A_RX_GND_INACTIVE BIT(13)
|
||||||
#define IQS269_CHx_ENG_A_LOCAL_CAP_SIZE BIT(12)
|
#define IQS269_CHx_ENG_A_LOCAL_CAP_SIZE BIT(12)
|
||||||
|
@ -142,6 +156,10 @@
|
||||||
|
|
||||||
#define IQS269_MAX_REG 0xFF
|
#define IQS269_MAX_REG 0xFF
|
||||||
|
|
||||||
|
#define IQS269_OTP_OPTION_DEFAULT 0x00
|
||||||
|
#define IQS269_OTP_OPTION_TWS 0xD0
|
||||||
|
#define IQS269_OTP_OPTION_HOLD BIT(7)
|
||||||
|
|
||||||
#define IQS269_NUM_CH 8
|
#define IQS269_NUM_CH 8
|
||||||
#define IQS269_NUM_SL 2
|
#define IQS269_NUM_SL 2
|
||||||
|
|
||||||
|
@ -175,6 +193,20 @@ enum iqs269_event_id {
|
||||||
IQS269_EVENT_DEEP_UP,
|
IQS269_EVENT_DEEP_UP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum iqs269_slider_id {
|
||||||
|
IQS269_SLIDER_NONE,
|
||||||
|
IQS269_SLIDER_KEY,
|
||||||
|
IQS269_SLIDER_RAW,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum iqs269_gesture_id {
|
||||||
|
IQS269_GESTURE_TAP,
|
||||||
|
IQS269_GESTURE_HOLD,
|
||||||
|
IQS269_GESTURE_FLICK_POS,
|
||||||
|
IQS269_GESTURE_FLICK_NEG,
|
||||||
|
IQS269_NUM_GESTURES,
|
||||||
|
};
|
||||||
|
|
||||||
struct iqs269_switch_desc {
|
struct iqs269_switch_desc {
|
||||||
unsigned int code;
|
unsigned int code;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
@ -234,7 +266,7 @@ struct iqs269_ver_info {
|
||||||
u8 prod_num;
|
u8 prod_num;
|
||||||
u8 sw_num;
|
u8 sw_num;
|
||||||
u8 hw_num;
|
u8 hw_num;
|
||||||
u8 padding;
|
u8 fw_num;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct iqs269_ch_reg {
|
struct iqs269_ch_reg {
|
||||||
|
@ -285,16 +317,42 @@ struct iqs269_private {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct iqs269_switch_desc switches[ARRAY_SIZE(iqs269_events)];
|
struct iqs269_switch_desc switches[ARRAY_SIZE(iqs269_events)];
|
||||||
|
struct iqs269_ver_info ver_info;
|
||||||
struct iqs269_sys_reg sys_reg;
|
struct iqs269_sys_reg sys_reg;
|
||||||
struct completion ati_done;
|
struct completion ati_done;
|
||||||
struct input_dev *keypad;
|
struct input_dev *keypad;
|
||||||
struct input_dev *slider[IQS269_NUM_SL];
|
struct input_dev *slider[IQS269_NUM_SL];
|
||||||
unsigned int keycode[ARRAY_SIZE(iqs269_events) * IQS269_NUM_CH];
|
unsigned int keycode[ARRAY_SIZE(iqs269_events) * IQS269_NUM_CH];
|
||||||
|
unsigned int sl_code[IQS269_NUM_SL][IQS269_NUM_GESTURES];
|
||||||
|
unsigned int otp_option;
|
||||||
unsigned int ch_num;
|
unsigned int ch_num;
|
||||||
bool hall_enable;
|
bool hall_enable;
|
||||||
bool ati_current;
|
bool ati_current;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static enum iqs269_slider_id iqs269_slider_type(struct iqs269_private *iqs269,
|
||||||
|
int slider_num)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Slider 1 is unavailable if the touch-and-hold option is enabled via
|
||||||
|
* OTP. In that case, the channel selection register is repurposed for
|
||||||
|
* the touch-and-hold timer ceiling.
|
||||||
|
*/
|
||||||
|
if (slider_num && (iqs269->otp_option & IQS269_OTP_OPTION_HOLD))
|
||||||
|
return IQS269_SLIDER_NONE;
|
||||||
|
|
||||||
|
if (!iqs269->sys_reg.slider_select[slider_num])
|
||||||
|
return IQS269_SLIDER_NONE;
|
||||||
|
|
||||||
|
for (i = 0; i < IQS269_NUM_GESTURES; i++)
|
||||||
|
if (iqs269->sl_code[slider_num][i] != KEY_RESERVED)
|
||||||
|
return IQS269_SLIDER_KEY;
|
||||||
|
|
||||||
|
return IQS269_SLIDER_RAW;
|
||||||
|
}
|
||||||
|
|
||||||
static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
|
static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
|
||||||
unsigned int ch_num, unsigned int mode)
|
unsigned int ch_num, unsigned int mode)
|
||||||
{
|
{
|
||||||
|
@ -525,7 +583,8 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
|
||||||
if (fwnode_property_present(ch_node, "azoteq,slider0-select"))
|
if (fwnode_property_present(ch_node, "azoteq,slider0-select"))
|
||||||
iqs269->sys_reg.slider_select[0] |= BIT(reg);
|
iqs269->sys_reg.slider_select[0] |= BIT(reg);
|
||||||
|
|
||||||
if (fwnode_property_present(ch_node, "azoteq,slider1-select"))
|
if (fwnode_property_present(ch_node, "azoteq,slider1-select") &&
|
||||||
|
!(iqs269->otp_option & IQS269_OTP_OPTION_HOLD))
|
||||||
iqs269->sys_reg.slider_select[1] |= BIT(reg);
|
iqs269->sys_reg.slider_select[1] |= BIT(reg);
|
||||||
|
|
||||||
ch_reg = &iqs269->sys_reg.ch_reg[reg];
|
ch_reg = &iqs269->sys_reg.ch_reg[reg];
|
||||||
|
@ -950,7 +1009,43 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
|
||||||
sys_reg->blocking = 0;
|
sys_reg->blocking = 0;
|
||||||
|
|
||||||
sys_reg->slider_select[0] = 0;
|
sys_reg->slider_select[0] = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If configured via OTP to do so, the device asserts a pulse on the
|
||||||
|
* GPIO4 pin for approximately 60 ms once a selected channel is held
|
||||||
|
* in a state of touch for a configurable length of time.
|
||||||
|
*
|
||||||
|
* In that case, the register used for slider 1 channel selection is
|
||||||
|
* repurposed for the touch-and-hold timer ceiling.
|
||||||
|
*/
|
||||||
|
if (iqs269->otp_option & IQS269_OTP_OPTION_HOLD) {
|
||||||
|
if (!device_property_read_u32(&client->dev,
|
||||||
|
"azoteq,touch-hold-ms", &val)) {
|
||||||
|
if (val < IQS269_TOUCH_HOLD_MS_MIN ||
|
||||||
|
val > IQS269_TOUCH_HOLD_MS_MAX) {
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"Invalid touch-and-hold ceiling: %u\n",
|
||||||
|
val);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_reg->slider_select[1] = val / 256;
|
||||||
|
} else if (iqs269->ver_info.fw_num < IQS269_VER_INFO_FW_NUM_3) {
|
||||||
|
/*
|
||||||
|
* The default touch-and-hold timer ceiling initially
|
||||||
|
* read from early revisions of silicon is invalid if
|
||||||
|
* the device experienced a soft reset between power-
|
||||||
|
* on and the read operation.
|
||||||
|
*
|
||||||
|
* To protect against this case, explicitly cache the
|
||||||
|
* default value so that it is restored each time the
|
||||||
|
* device is re-initialized.
|
||||||
|
*/
|
||||||
|
sys_reg->slider_select[1] = IQS269_TOUCH_HOLD_DEFAULT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
sys_reg->slider_select[1] = 0;
|
sys_reg->slider_select[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS);
|
sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS);
|
||||||
|
|
||||||
|
@ -1004,6 +1099,76 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
|
||||||
general |= (val << IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT);
|
general |= (val << IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (device_property_present(&client->dev, "linux,keycodes")) {
|
||||||
|
int scale = 1;
|
||||||
|
int count = device_property_count_u32(&client->dev,
|
||||||
|
"linux,keycodes");
|
||||||
|
if (count > IQS269_NUM_GESTURES * IQS269_NUM_SL) {
|
||||||
|
dev_err(&client->dev, "Too many keycodes present\n");
|
||||||
|
return -EINVAL;
|
||||||
|
} else if (count < 0) {
|
||||||
|
dev_err(&client->dev, "Failed to count keycodes: %d\n",
|
||||||
|
count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = device_property_read_u32_array(&client->dev,
|
||||||
|
"linux,keycodes",
|
||||||
|
*iqs269->sl_code, count);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&client->dev, "Failed to read keycodes: %d\n",
|
||||||
|
error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device_property_present(&client->dev,
|
||||||
|
"azoteq,gesture-swipe"))
|
||||||
|
general |= IQS269_SYS_SETTINGS_SLIDER_SWIPE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Early revisions of silicon use a more granular step size for
|
||||||
|
* tap and swipe gesture timeouts; scale them appropriately.
|
||||||
|
*/
|
||||||
|
if (iqs269->ver_info.fw_num < IQS269_VER_INFO_FW_NUM_3)
|
||||||
|
scale = 4;
|
||||||
|
|
||||||
|
if (!device_property_read_u32(&client->dev,
|
||||||
|
"azoteq,timeout-tap-ms", &val)) {
|
||||||
|
if (val > IQS269_TIMEOUT_TAP_MS_MAX / scale) {
|
||||||
|
dev_err(&client->dev, "Invalid timeout: %u\n",
|
||||||
|
val);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_reg->timeout_tap = val / (16 / scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!device_property_read_u32(&client->dev,
|
||||||
|
"azoteq,timeout-swipe-ms",
|
||||||
|
&val)) {
|
||||||
|
if (val > IQS269_TIMEOUT_SWIPE_MS_MAX / scale) {
|
||||||
|
dev_err(&client->dev, "Invalid timeout: %u\n",
|
||||||
|
val);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_reg->timeout_swipe = val / (16 / scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!device_property_read_u32(&client->dev,
|
||||||
|
"azoteq,thresh-swipe", &val)) {
|
||||||
|
if (val > IQS269_THRESH_SWIPE_MAX) {
|
||||||
|
dev_err(&client->dev, "Invalid threshold: %u\n",
|
||||||
|
val);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_reg->thresh_swipe = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_reg->event_mask &= ~IQS269_EVENT_MASK_GESTURE;
|
||||||
|
}
|
||||||
|
|
||||||
general &= ~IQS269_SYS_SETTINGS_RESEED_OFFSET;
|
general &= ~IQS269_SYS_SETTINGS_RESEED_OFFSET;
|
||||||
if (device_property_present(&client->dev, "azoteq,reseed-offset"))
|
if (device_property_present(&client->dev, "azoteq,reseed-offset"))
|
||||||
general |= IQS269_SYS_SETTINGS_RESEED_OFFSET;
|
general |= IQS269_SYS_SETTINGS_RESEED_OFFSET;
|
||||||
|
@ -1012,10 +1177,11 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As per the datasheet, enable streaming during normal-power mode if
|
* As per the datasheet, enable streaming during normal-power mode if
|
||||||
* either slider is in use. In that case, the device returns to event
|
* raw coordinates will be read from either slider. In that case, the
|
||||||
* mode during low-power mode.
|
* device returns to event mode during low-power mode.
|
||||||
*/
|
*/
|
||||||
if (sys_reg->slider_select[0] || sys_reg->slider_select[1])
|
if (iqs269_slider_type(iqs269, 0) == IQS269_SLIDER_RAW ||
|
||||||
|
iqs269_slider_type(iqs269, 1) == IQS269_SLIDER_RAW)
|
||||||
general |= IQS269_SYS_SETTINGS_EVENT_MODE_LP;
|
general |= IQS269_SYS_SETTINGS_EVENT_MODE_LP;
|
||||||
|
|
||||||
general |= IQS269_SYS_SETTINGS_REDO_ATI;
|
general |= IQS269_SYS_SETTINGS_REDO_ATI;
|
||||||
|
@ -1026,12 +1192,30 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct reg_sequence iqs269_tws_init[] = {
|
||||||
|
{ IQS269_TOUCH_HOLD_SLIDER_SEL, IQS269_TOUCH_HOLD_DEFAULT },
|
||||||
|
{ 0xF0, 0x580F },
|
||||||
|
{ 0xF0, 0x59EF },
|
||||||
|
};
|
||||||
|
|
||||||
static int iqs269_dev_init(struct iqs269_private *iqs269)
|
static int iqs269_dev_init(struct iqs269_private *iqs269)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
mutex_lock(&iqs269->lock);
|
mutex_lock(&iqs269->lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Early revisions of silicon require the following workaround in order
|
||||||
|
* to restore any OTP-enabled functionality after a soft reset.
|
||||||
|
*/
|
||||||
|
if (iqs269->otp_option == IQS269_OTP_OPTION_TWS &&
|
||||||
|
iqs269->ver_info.fw_num < IQS269_VER_INFO_FW_NUM_3) {
|
||||||
|
error = regmap_multi_reg_write(iqs269->regmap, iqs269_tws_init,
|
||||||
|
ARRAY_SIZE(iqs269_tws_init));
|
||||||
|
if (error)
|
||||||
|
goto err_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
error = regmap_update_bits(iqs269->regmap, IQS269_HALL_UI,
|
error = regmap_update_bits(iqs269->regmap, IQS269_HALL_UI,
|
||||||
IQS269_HALL_UI_ENABLE,
|
IQS269_HALL_UI_ENABLE,
|
||||||
iqs269->hall_enable ? ~0 : 0);
|
iqs269->hall_enable ? ~0 : 0);
|
||||||
|
@ -1106,19 +1290,37 @@ static int iqs269_input_init(struct iqs269_private *iqs269)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < IQS269_NUM_SL; i++) {
|
for (i = 0; i < IQS269_NUM_SL; i++) {
|
||||||
if (!iqs269->sys_reg.slider_select[i])
|
if (iqs269_slider_type(iqs269, i) == IQS269_SLIDER_NONE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
iqs269->slider[i] = devm_input_allocate_device(&client->dev);
|
iqs269->slider[i] = devm_input_allocate_device(&client->dev);
|
||||||
if (!iqs269->slider[i])
|
if (!iqs269->slider[i])
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
iqs269->slider[i]->keycodemax = ARRAY_SIZE(iqs269->sl_code[i]);
|
||||||
|
iqs269->slider[i]->keycode = iqs269->sl_code[i];
|
||||||
|
iqs269->slider[i]->keycodesize = sizeof(**iqs269->sl_code);
|
||||||
|
|
||||||
iqs269->slider[i]->name = i ? "iqs269a_slider_1"
|
iqs269->slider[i]->name = i ? "iqs269a_slider_1"
|
||||||
: "iqs269a_slider_0";
|
: "iqs269a_slider_0";
|
||||||
iqs269->slider[i]->id.bustype = BUS_I2C;
|
iqs269->slider[i]->id.bustype = BUS_I2C;
|
||||||
|
|
||||||
input_set_capability(iqs269->slider[i], EV_KEY, BTN_TOUCH);
|
for (j = 0; j < IQS269_NUM_GESTURES; j++)
|
||||||
input_set_abs_params(iqs269->slider[i], ABS_X, 0, 255, 0, 0);
|
if (iqs269->sl_code[i][j] != KEY_RESERVED)
|
||||||
|
input_set_capability(iqs269->slider[i], EV_KEY,
|
||||||
|
iqs269->sl_code[i][j]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Present the slider as a narrow trackpad if one or more chan-
|
||||||
|
* nels have been selected to participate, but no gestures have
|
||||||
|
* been mapped to a keycode.
|
||||||
|
*/
|
||||||
|
if (iqs269_slider_type(iqs269, i) == IQS269_SLIDER_RAW) {
|
||||||
|
input_set_capability(iqs269->slider[i],
|
||||||
|
EV_KEY, BTN_TOUCH);
|
||||||
|
input_set_abs_params(iqs269->slider[i],
|
||||||
|
ABS_X, 0, 255, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
error = input_register_device(iqs269->slider[i]);
|
error = input_register_device(iqs269->slider[i]);
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -1167,28 +1369,62 @@ static int iqs269_report(struct iqs269_private *iqs269)
|
||||||
if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_IN_ATI)
|
if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_IN_ATI)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error = regmap_raw_read(iqs269->regmap, IQS269_SLIDER_X, slider_x,
|
if (iqs269_slider_type(iqs269, 0) == IQS269_SLIDER_RAW ||
|
||||||
sizeof(slider_x));
|
iqs269_slider_type(iqs269, 1) == IQS269_SLIDER_RAW) {
|
||||||
|
error = regmap_raw_read(iqs269->regmap, IQS269_SLIDER_X,
|
||||||
|
slider_x, sizeof(slider_x));
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(&client->dev, "Failed to read slider position: %d\n",
|
dev_err(&client->dev,
|
||||||
error);
|
"Failed to read slider position: %d\n", error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < IQS269_NUM_SL; i++) {
|
for (i = 0; i < IQS269_NUM_SL; i++) {
|
||||||
if (!iqs269->sys_reg.slider_select[i])
|
flags.gesture >>= (i * IQS269_NUM_GESTURES);
|
||||||
|
|
||||||
|
switch (iqs269_slider_type(iqs269, i)) {
|
||||||
|
case IQS269_SLIDER_NONE:
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case IQS269_SLIDER_KEY:
|
||||||
|
for (j = 0; j < IQS269_NUM_GESTURES; j++)
|
||||||
|
input_report_key(iqs269->slider[i],
|
||||||
|
iqs269->sl_code[i][j],
|
||||||
|
flags.gesture & BIT(j));
|
||||||
|
|
||||||
|
if (!(flags.gesture & (BIT(IQS269_GESTURE_FLICK_NEG) |
|
||||||
|
BIT(IQS269_GESTURE_FLICK_POS) |
|
||||||
|
BIT(IQS269_GESTURE_TAP))))
|
||||||
|
break;
|
||||||
|
|
||||||
|
input_sync(iqs269->slider[i]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Report BTN_TOUCH if any channel that participates in the
|
* Momentary gestures are followed by a complementary
|
||||||
* slider is in a state of touch.
|
* release cycle so as to emulate a full keystroke.
|
||||||
*/
|
*/
|
||||||
if (flags.states[IQS269_ST_OFFS_TOUCH] &
|
for (j = 0; j < IQS269_NUM_GESTURES; j++)
|
||||||
iqs269->sys_reg.slider_select[i]) {
|
if (j != IQS269_GESTURE_HOLD)
|
||||||
input_report_key(iqs269->slider[i], BTN_TOUCH, 1);
|
input_report_key(iqs269->slider[i],
|
||||||
input_report_abs(iqs269->slider[i], ABS_X, slider_x[i]);
|
iqs269->sl_code[i][j],
|
||||||
} else {
|
0);
|
||||||
input_report_key(iqs269->slider[i], BTN_TOUCH, 0);
|
break;
|
||||||
|
|
||||||
|
case IQS269_SLIDER_RAW:
|
||||||
|
/*
|
||||||
|
* The slider is considered to be in a state of touch
|
||||||
|
* if any selected channels are in a state of touch.
|
||||||
|
*/
|
||||||
|
state = flags.states[IQS269_ST_OFFS_TOUCH];
|
||||||
|
state &= iqs269->sys_reg.slider_select[i];
|
||||||
|
|
||||||
|
input_report_key(iqs269->slider[i], BTN_TOUCH, state);
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
input_report_abs(iqs269->slider[i],
|
||||||
|
ABS_X, slider_x[i]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
input_sync(iqs269->slider[i]);
|
input_sync(iqs269->slider[i]);
|
||||||
|
@ -1286,7 +1522,7 @@ static ssize_t counts_show(struct device *dev,
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u\n", le16_to_cpu(counts));
|
return sysfs_emit(buf, "%u\n", le16_to_cpu(counts));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t hall_bin_show(struct device *dev,
|
static ssize_t hall_bin_show(struct device *dev,
|
||||||
|
@ -1324,7 +1560,7 @@ static ssize_t hall_bin_show(struct device *dev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u\n", val);
|
return sysfs_emit(buf, "%u\n", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t hall_enable_show(struct device *dev,
|
static ssize_t hall_enable_show(struct device *dev,
|
||||||
|
@ -1332,7 +1568,7 @@ static ssize_t hall_enable_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
|
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->hall_enable);
|
return sysfs_emit(buf, "%u\n", iqs269->hall_enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t hall_enable_store(struct device *dev,
|
static ssize_t hall_enable_store(struct device *dev,
|
||||||
|
@ -1362,7 +1598,7 @@ static ssize_t ch_number_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
|
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ch_num);
|
return sysfs_emit(buf, "%u\n", iqs269->ch_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ch_number_store(struct device *dev,
|
static ssize_t ch_number_store(struct device *dev,
|
||||||
|
@ -1391,8 +1627,7 @@ static ssize_t rx_enable_show(struct device *dev,
|
||||||
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
|
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
|
||||||
struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
|
struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u\n",
|
return sysfs_emit(buf, "%u\n", ch_reg[iqs269->ch_num].rx_enable);
|
||||||
ch_reg[iqs269->ch_num].rx_enable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t rx_enable_store(struct device *dev,
|
static ssize_t rx_enable_store(struct device *dev,
|
||||||
|
@ -1432,7 +1667,7 @@ static ssize_t ati_mode_show(struct device *dev,
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u\n", val);
|
return sysfs_emit(buf, "%u\n", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ati_mode_store(struct device *dev,
|
static ssize_t ati_mode_store(struct device *dev,
|
||||||
|
@ -1465,7 +1700,7 @@ static ssize_t ati_base_show(struct device *dev,
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u\n", val);
|
return sysfs_emit(buf, "%u\n", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ati_base_store(struct device *dev,
|
static ssize_t ati_base_store(struct device *dev,
|
||||||
|
@ -1498,7 +1733,7 @@ static ssize_t ati_target_show(struct device *dev,
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u\n", val);
|
return sysfs_emit(buf, "%u\n", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ati_target_store(struct device *dev,
|
static ssize_t ati_target_store(struct device *dev,
|
||||||
|
@ -1525,7 +1760,7 @@ static ssize_t ati_trigger_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
|
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u\n",
|
return sysfs_emit(buf, "%u\n",
|
||||||
iqs269->ati_current &&
|
iqs269->ati_current &&
|
||||||
completion_done(&iqs269->ati_done));
|
completion_done(&iqs269->ati_done));
|
||||||
}
|
}
|
||||||
|
@ -1596,7 +1831,6 @@ static const struct regmap_config iqs269_regmap_config = {
|
||||||
|
|
||||||
static int iqs269_probe(struct i2c_client *client)
|
static int iqs269_probe(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
struct iqs269_ver_info ver_info;
|
|
||||||
struct iqs269_private *iqs269;
|
struct iqs269_private *iqs269;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
@ -1618,14 +1852,16 @@ static int iqs269_probe(struct i2c_client *client)
|
||||||
mutex_init(&iqs269->lock);
|
mutex_init(&iqs269->lock);
|
||||||
init_completion(&iqs269->ati_done);
|
init_completion(&iqs269->ati_done);
|
||||||
|
|
||||||
error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO, &ver_info,
|
iqs269->otp_option = (uintptr_t)device_get_match_data(&client->dev);
|
||||||
sizeof(ver_info));
|
|
||||||
|
error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO,
|
||||||
|
&iqs269->ver_info, sizeof(iqs269->ver_info));
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (ver_info.prod_num != IQS269_VER_INFO_PROD_NUM) {
|
if (iqs269->ver_info.prod_num != IQS269_VER_INFO_PROD_NUM) {
|
||||||
dev_err(&client->dev, "Unrecognized product number: 0x%02X\n",
|
dev_err(&client->dev, "Unrecognized product number: 0x%02X\n",
|
||||||
ver_info.prod_num);
|
iqs269->ver_info.prod_num);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1728,7 +1964,18 @@ static int iqs269_resume(struct device *dev)
|
||||||
static DEFINE_SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume);
|
static DEFINE_SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume);
|
||||||
|
|
||||||
static const struct of_device_id iqs269_of_match[] = {
|
static const struct of_device_id iqs269_of_match[] = {
|
||||||
{ .compatible = "azoteq,iqs269a" },
|
{
|
||||||
|
.compatible = "azoteq,iqs269a",
|
||||||
|
.data = (void *)IQS269_OTP_OPTION_DEFAULT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "azoteq,iqs269a-00",
|
||||||
|
.data = (void *)IQS269_OTP_OPTION_DEFAULT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.compatible = "azoteq,iqs269a-d0",
|
||||||
|
.data = (void *)IQS269_OTP_OPTION_TWS,
|
||||||
|
},
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, iqs269_of_match);
|
MODULE_DEVICE_TABLE(of, iqs269_of_match);
|
||||||
|
|
|
@ -307,7 +307,7 @@ static int max77693_haptic_probe(struct platform_device *pdev)
|
||||||
haptic->suspend_state = false;
|
haptic->suspend_state = false;
|
||||||
|
|
||||||
/* Variant-specific init */
|
/* Variant-specific init */
|
||||||
haptic->dev_type = platform_get_device_id(pdev)->driver_data;
|
haptic->dev_type = max77693->type;
|
||||||
switch (haptic->dev_type) {
|
switch (haptic->dev_type) {
|
||||||
case TYPE_MAX77693:
|
case TYPE_MAX77693:
|
||||||
haptic->regmap_haptic = max77693->regmap_haptic;
|
haptic->regmap_haptic = max77693->regmap_haptic;
|
||||||
|
@ -406,16 +406,24 @@ static DEFINE_SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops,
|
||||||
max77693_haptic_resume);
|
max77693_haptic_resume);
|
||||||
|
|
||||||
static const struct platform_device_id max77693_haptic_id[] = {
|
static const struct platform_device_id max77693_haptic_id[] = {
|
||||||
{ "max77693-haptic", TYPE_MAX77693 },
|
{ "max77693-haptic", },
|
||||||
{ "max77843-haptic", TYPE_MAX77843 },
|
{ "max77843-haptic", },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(platform, max77693_haptic_id);
|
MODULE_DEVICE_TABLE(platform, max77693_haptic_id);
|
||||||
|
|
||||||
|
static const struct of_device_id of_max77693_haptic_dt_match[] = {
|
||||||
|
{ .compatible = "maxim,max77693-haptic", },
|
||||||
|
{ .compatible = "maxim,max77843-haptic", },
|
||||||
|
{ /* sentinel */ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, of_max77693_haptic_dt_match);
|
||||||
|
|
||||||
static struct platform_driver max77693_haptic_driver = {
|
static struct platform_driver max77693_haptic_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "max77693-haptic",
|
.name = "max77693-haptic",
|
||||||
.pm = pm_sleep_ptr(&max77693_haptic_pm_ops),
|
.pm = pm_sleep_ptr(&max77693_haptic_pm_ops),
|
||||||
|
.of_match_table = of_max77693_haptic_dt_match,
|
||||||
},
|
},
|
||||||
.probe = max77693_haptic_probe,
|
.probe = max77693_haptic_probe,
|
||||||
.id_table = max77693_haptic_id,
|
.id_table = max77693_haptic_id,
|
||||||
|
|
|
@ -756,15 +756,15 @@ static ssize_t cyapa_show_suspend_scanrate(struct device *dev,
|
||||||
|
|
||||||
switch (pwr_cmd) {
|
switch (pwr_cmd) {
|
||||||
case PWR_MODE_BTN_ONLY:
|
case PWR_MODE_BTN_ONLY:
|
||||||
len = scnprintf(buf, PAGE_SIZE, "%s\n", BTN_ONLY_MODE_NAME);
|
len = sysfs_emit(buf, "%s\n", BTN_ONLY_MODE_NAME);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PWR_MODE_OFF:
|
case PWR_MODE_OFF:
|
||||||
len = scnprintf(buf, PAGE_SIZE, "%s\n", OFF_MODE_NAME);
|
len = sysfs_emit(buf, "%s\n", OFF_MODE_NAME);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
len = scnprintf(buf, PAGE_SIZE, "%u\n",
|
len = sysfs_emit(buf, "%u\n",
|
||||||
cyapa->gen == CYAPA_GEN3 ?
|
cyapa->gen == CYAPA_GEN3 ?
|
||||||
cyapa_pwr_cmd_to_sleep_time(pwr_cmd) :
|
cyapa_pwr_cmd_to_sleep_time(pwr_cmd) :
|
||||||
sleep_time);
|
sleep_time);
|
||||||
|
@ -877,7 +877,7 @@ static ssize_t cyapa_show_rt_suspend_scanrate(struct device *dev,
|
||||||
|
|
||||||
mutex_unlock(&cyapa->state_sync_lock);
|
mutex_unlock(&cyapa->state_sync_lock);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u\n",
|
return sysfs_emit(buf, "%u\n",
|
||||||
cyapa->gen == CYAPA_GEN3 ?
|
cyapa->gen == CYAPA_GEN3 ?
|
||||||
cyapa_pwr_cmd_to_sleep_time(pwr_cmd) :
|
cyapa_pwr_cmd_to_sleep_time(pwr_cmd) :
|
||||||
sleep_time);
|
sleep_time);
|
||||||
|
@ -988,8 +988,8 @@ static ssize_t cyapa_show_fm_ver(struct device *dev,
|
||||||
error = mutex_lock_interruptible(&cyapa->state_sync_lock);
|
error = mutex_lock_interruptible(&cyapa->state_sync_lock);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
error = scnprintf(buf, PAGE_SIZE, "%d.%d\n", cyapa->fw_maj_ver,
|
error = sysfs_emit(buf, "%d.%d\n",
|
||||||
cyapa->fw_min_ver);
|
cyapa->fw_maj_ver, cyapa->fw_min_ver);
|
||||||
mutex_unlock(&cyapa->state_sync_lock);
|
mutex_unlock(&cyapa->state_sync_lock);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -1004,7 +1004,7 @@ static ssize_t cyapa_show_product_id(struct device *dev,
|
||||||
error = mutex_lock_interruptible(&cyapa->state_sync_lock);
|
error = mutex_lock_interruptible(&cyapa->state_sync_lock);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
size = scnprintf(buf, PAGE_SIZE, "%s\n", cyapa->product_id);
|
size = sysfs_emit(buf, "%s\n", cyapa->product_id);
|
||||||
mutex_unlock(&cyapa->state_sync_lock);
|
mutex_unlock(&cyapa->state_sync_lock);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
@ -1209,7 +1209,7 @@ static ssize_t cyapa_show_mode(struct device *dev,
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
size = scnprintf(buf, PAGE_SIZE, "gen%d %s\n",
|
size = sysfs_emit(buf, "gen%d %s\n",
|
||||||
cyapa->gen, cyapa_state_to_string(cyapa));
|
cyapa->gen, cyapa_state_to_string(cyapa));
|
||||||
|
|
||||||
mutex_unlock(&cyapa->state_sync_lock);
|
mutex_unlock(&cyapa->state_sync_lock);
|
||||||
|
|
|
@ -860,7 +860,7 @@ static ssize_t cyapa_gen3_show_baseline(struct device *dev,
|
||||||
|
|
||||||
dev_dbg(dev, "Baseline report successful. Max: %d Min: %d\n",
|
dev_dbg(dev, "Baseline report successful. Max: %d Min: %d\n",
|
||||||
max_baseline, min_baseline);
|
max_baseline, min_baseline);
|
||||||
ret = scnprintf(buf, PAGE_SIZE, "%d %d\n", max_baseline, min_baseline);
|
ret = sysfs_emit(buf, "%d %d\n", max_baseline, min_baseline);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -2418,12 +2418,12 @@ static ssize_t cyapa_gen5_show_baseline(struct device *dev,
|
||||||
return resume_error ? resume_error : error;
|
return resume_error ? resume_error : error;
|
||||||
|
|
||||||
/* 12. Output data strings */
|
/* 12. Output data strings */
|
||||||
size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d %d %d %d %d %d ",
|
size = sysfs_emit(buf, "%d %d %d %d %d %d %d %d %d %d %d ",
|
||||||
gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave,
|
gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave,
|
||||||
lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave,
|
lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave,
|
||||||
gidac_self_rx, gidac_self_tx,
|
gidac_self_rx, gidac_self_tx,
|
||||||
lidac_self_min, lidac_self_max, lidac_self_ave);
|
lidac_self_min, lidac_self_max, lidac_self_ave);
|
||||||
size += scnprintf(buf + size, PAGE_SIZE - size,
|
size += sysfs_emit_at(buf, size,
|
||||||
"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
|
"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
|
||||||
raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave,
|
raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave,
|
||||||
raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave,
|
raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave,
|
||||||
|
|
|
@ -629,7 +629,7 @@ static ssize_t cyapa_gen6_show_baseline(struct device *dev,
|
||||||
if (error)
|
if (error)
|
||||||
goto resume_scanning;
|
goto resume_scanning;
|
||||||
|
|
||||||
size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d ",
|
size = sysfs_emit(buf, "%d %d %d %d %d %d ",
|
||||||
data[0], /* RX Attenuator Mutual */
|
data[0], /* RX Attenuator Mutual */
|
||||||
data[1], /* IDAC Mutual */
|
data[1], /* IDAC Mutual */
|
||||||
data[2], /* RX Attenuator Self RX */
|
data[2], /* RX Attenuator Self RX */
|
||||||
|
@ -648,8 +648,8 @@ static ssize_t cyapa_gen6_show_baseline(struct device *dev,
|
||||||
|
|
||||||
/* set attenuator trim values. */
|
/* set attenuator trim values. */
|
||||||
for (i = 0; i < data_len; i++)
|
for (i = 0; i < data_len; i++)
|
||||||
size += scnprintf(buf + size, PAGE_SIZE - size, "%d ", data[i]);
|
size += sysfs_emit_at(buf, size, "%d ", data[i]);
|
||||||
size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
|
size += sysfs_emit_at(buf, size, "\n");
|
||||||
|
|
||||||
resume_scanning:
|
resume_scanning:
|
||||||
/* 4. Resume Scanning*/
|
/* 4. Resume Scanning*/
|
||||||
|
|
|
@ -572,7 +572,7 @@ static ssize_t elan_sysfs_read_fw_checksum(struct device *dev,
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct elan_tp_data *data = i2c_get_clientdata(client);
|
struct elan_tp_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
return sprintf(buf, "0x%04x\n", data->fw_checksum);
|
return sysfs_emit(buf, "0x%04x\n", data->fw_checksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t elan_sysfs_read_product_id(struct device *dev,
|
static ssize_t elan_sysfs_read_product_id(struct device *dev,
|
||||||
|
@ -582,7 +582,7 @@ static ssize_t elan_sysfs_read_product_id(struct device *dev,
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct elan_tp_data *data = i2c_get_clientdata(client);
|
struct elan_tp_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
return sprintf(buf, ETP_PRODUCT_ID_FORMAT_STRING "\n",
|
return sysfs_emit(buf, ETP_PRODUCT_ID_FORMAT_STRING "\n",
|
||||||
data->product_id);
|
data->product_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +593,7 @@ static ssize_t elan_sysfs_read_fw_ver(struct device *dev,
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct elan_tp_data *data = i2c_get_clientdata(client);
|
struct elan_tp_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
return sprintf(buf, "%d.0\n", data->fw_version);
|
return sysfs_emit(buf, "%d.0\n", data->fw_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t elan_sysfs_read_sm_ver(struct device *dev,
|
static ssize_t elan_sysfs_read_sm_ver(struct device *dev,
|
||||||
|
@ -603,7 +603,7 @@ static ssize_t elan_sysfs_read_sm_ver(struct device *dev,
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct elan_tp_data *data = i2c_get_clientdata(client);
|
struct elan_tp_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
return sprintf(buf, "%d.0\n", data->sm_version);
|
return sysfs_emit(buf, "%d.0\n", data->sm_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t elan_sysfs_read_iap_ver(struct device *dev,
|
static ssize_t elan_sysfs_read_iap_ver(struct device *dev,
|
||||||
|
@ -613,7 +613,7 @@ static ssize_t elan_sysfs_read_iap_ver(struct device *dev,
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct elan_tp_data *data = i2c_get_clientdata(client);
|
struct elan_tp_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
return sprintf(buf, "%d.0\n", data->iap_version);
|
return sysfs_emit(buf, "%d.0\n", data->iap_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t elan_sysfs_update_fw(struct device *dev,
|
static ssize_t elan_sysfs_update_fw(struct device *dev,
|
||||||
|
@ -754,7 +754,7 @@ static ssize_t elan_sysfs_read_mode(struct device *dev,
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", (int)mode);
|
return sysfs_emit(buf, "%d\n", (int)mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR(product_id, S_IRUGO, elan_sysfs_read_product_id, NULL);
|
static DEVICE_ATTR(product_id, S_IRUGO, elan_sysfs_read_product_id, NULL);
|
||||||
|
@ -858,7 +858,7 @@ static ssize_t min_show(struct device *dev,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = snprintf(buf, PAGE_SIZE, "%d", data->min_baseline);
|
retval = sysfs_emit(buf, "%d", data->min_baseline);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&data->sysfs_mutex);
|
mutex_unlock(&data->sysfs_mutex);
|
||||||
|
@ -881,7 +881,7 @@ static ssize_t max_show(struct device *dev,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = snprintf(buf, PAGE_SIZE, "%d", data->max_baseline);
|
retval = sysfs_emit(buf, "%d", data->max_baseline);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&data->sysfs_mutex);
|
mutex_unlock(&data->sysfs_mutex);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/input/navpoint.h>
|
#include <linux/input/navpoint.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
@ -32,7 +32,7 @@ struct navpoint {
|
||||||
struct ssp_device *ssp;
|
struct ssp_device *ssp;
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
int gpio;
|
struct gpio_desc *gpiod;
|
||||||
int index;
|
int index;
|
||||||
u8 data[1 + HEADER_LENGTH(0xff)];
|
u8 data[1 + HEADER_LENGTH(0xff)];
|
||||||
};
|
};
|
||||||
|
@ -170,16 +170,14 @@ static void navpoint_up(struct navpoint *navpoint)
|
||||||
dev_err(navpoint->dev,
|
dev_err(navpoint->dev,
|
||||||
"timeout waiting for SSSR[CSS] to clear\n");
|
"timeout waiting for SSSR[CSS] to clear\n");
|
||||||
|
|
||||||
if (gpio_is_valid(navpoint->gpio))
|
gpiod_set_value(navpoint->gpiod, 1);
|
||||||
gpio_set_value(navpoint->gpio, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void navpoint_down(struct navpoint *navpoint)
|
static void navpoint_down(struct navpoint *navpoint)
|
||||||
{
|
{
|
||||||
struct ssp_device *ssp = navpoint->ssp;
|
struct ssp_device *ssp = navpoint->ssp;
|
||||||
|
|
||||||
if (gpio_is_valid(navpoint->gpio))
|
gpiod_set_value(navpoint->gpiod, 0);
|
||||||
gpio_set_value(navpoint->gpio, 0);
|
|
||||||
|
|
||||||
pxa_ssp_write_reg(ssp, SSCR0, 0);
|
pxa_ssp_write_reg(ssp, SSCR0, 0);
|
||||||
|
|
||||||
|
@ -216,18 +214,9 @@ static int navpoint_probe(struct platform_device *pdev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpio_is_valid(pdata->gpio)) {
|
|
||||||
error = gpio_request_one(pdata->gpio, GPIOF_OUT_INIT_LOW,
|
|
||||||
"SYNAPTICS_ON");
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssp = pxa_ssp_request(pdata->port, pdev->name);
|
ssp = pxa_ssp_request(pdata->port, pdev->name);
|
||||||
if (!ssp) {
|
if (!ssp)
|
||||||
error = -ENODEV;
|
return -ENODEV;
|
||||||
goto err_free_gpio;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HaRET does not disable devices before jumping into Linux */
|
/* HaRET does not disable devices before jumping into Linux */
|
||||||
if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
|
if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
|
||||||
|
@ -242,10 +231,18 @@ static int navpoint_probe(struct platform_device *pdev)
|
||||||
goto err_free_mem;
|
goto err_free_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
navpoint->gpiod = gpiod_get_optional(&pdev->dev,
|
||||||
|
NULL, GPIOD_OUT_LOW);
|
||||||
|
if (IS_ERR(navpoint->gpiod)) {
|
||||||
|
error = PTR_ERR(navpoint->gpiod);
|
||||||
|
dev_err(&pdev->dev, "error getting GPIO\n");
|
||||||
|
goto err_free_mem;
|
||||||
|
}
|
||||||
|
gpiod_set_consumer_name(navpoint->gpiod, "SYNAPTICS_ON");
|
||||||
|
|
||||||
navpoint->ssp = ssp;
|
navpoint->ssp = ssp;
|
||||||
navpoint->input = input;
|
navpoint->input = input;
|
||||||
navpoint->dev = &pdev->dev;
|
navpoint->dev = &pdev->dev;
|
||||||
navpoint->gpio = pdata->gpio;
|
|
||||||
|
|
||||||
input->name = pdev->name;
|
input->name = pdev->name;
|
||||||
input->dev.parent = &pdev->dev;
|
input->dev.parent = &pdev->dev;
|
||||||
|
@ -288,17 +285,12 @@ static int navpoint_probe(struct platform_device *pdev)
|
||||||
input_free_device(input);
|
input_free_device(input);
|
||||||
kfree(navpoint);
|
kfree(navpoint);
|
||||||
pxa_ssp_free(ssp);
|
pxa_ssp_free(ssp);
|
||||||
err_free_gpio:
|
|
||||||
if (gpio_is_valid(pdata->gpio))
|
|
||||||
gpio_free(pdata->gpio);
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void navpoint_remove(struct platform_device *pdev)
|
static void navpoint_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const struct navpoint_platform_data *pdata =
|
|
||||||
dev_get_platdata(&pdev->dev);
|
|
||||||
struct navpoint *navpoint = platform_get_drvdata(pdev);
|
struct navpoint *navpoint = platform_get_drvdata(pdev);
|
||||||
struct ssp_device *ssp = navpoint->ssp;
|
struct ssp_device *ssp = navpoint->ssp;
|
||||||
|
|
||||||
|
@ -308,9 +300,6 @@ static void navpoint_remove(struct platform_device *pdev)
|
||||||
kfree(navpoint);
|
kfree(navpoint);
|
||||||
|
|
||||||
pxa_ssp_free(ssp);
|
pxa_ssp_free(ssp);
|
||||||
|
|
||||||
if (gpio_is_valid(pdata->gpio))
|
|
||||||
gpio_free(pdata->gpio);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int navpoint_suspend(struct device *dev)
|
static int navpoint_suspend(struct device *dev)
|
||||||
|
|
|
@ -267,8 +267,7 @@ static ssize_t rmi_driver_manufacturer_id_show(struct device *dev,
|
||||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||||
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%d\n",
|
return sysfs_emit(buf, "%d\n", f01->properties.manufacturer_id);
|
||||||
f01->properties.manufacturer_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR(manufacturer_id, 0444,
|
static DEVICE_ATTR(manufacturer_id, 0444,
|
||||||
|
@ -280,7 +279,7 @@ static ssize_t rmi_driver_dom_show(struct device *dev,
|
||||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||||
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%s\n", f01->properties.dom);
|
return sysfs_emit(buf, "%s\n", f01->properties.dom);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR(date_of_manufacture, 0444, rmi_driver_dom_show, NULL);
|
static DEVICE_ATTR(date_of_manufacture, 0444, rmi_driver_dom_show, NULL);
|
||||||
|
@ -292,7 +291,7 @@ static ssize_t rmi_driver_product_id_show(struct device *dev,
|
||||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||||
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%s\n", f01->properties.product_id);
|
return sysfs_emit(buf, "%s\n", f01->properties.product_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR(product_id, 0444, rmi_driver_product_id_show, NULL);
|
static DEVICE_ATTR(product_id, 0444, rmi_driver_product_id_show, NULL);
|
||||||
|
@ -304,7 +303,7 @@ static ssize_t rmi_driver_firmware_id_show(struct device *dev,
|
||||||
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
struct rmi_driver_data *data = dev_get_drvdata(dev);
|
||||||
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%d\n", f01->properties.firmware_id);
|
return sysfs_emit(buf, "%d\n", f01->properties.firmware_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_ATTR(firmware_id, 0444, rmi_driver_firmware_id_show, NULL);
|
static DEVICE_ATTR(firmware_id, 0444, rmi_driver_firmware_id_show, NULL);
|
||||||
|
@ -318,7 +317,7 @@ static ssize_t rmi_driver_package_id_show(struct device *dev,
|
||||||
|
|
||||||
u32 package_id = f01->properties.package_id;
|
u32 package_id = f01->properties.package_id;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%04x.%04x\n",
|
return sysfs_emit(buf, "%04x.%04x\n",
|
||||||
package_id & 0xffff, (package_id >> 16) & 0xffff);
|
package_id & 0xffff, (package_id >> 16) & 0xffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2818,7 +2818,7 @@ static ssize_t mxt_fw_version_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct mxt_data *data = dev_get_drvdata(dev);
|
struct mxt_data *data = dev_get_drvdata(dev);
|
||||||
struct mxt_info *info = data->info;
|
struct mxt_info *info = data->info;
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n",
|
return sysfs_emit(buf, "%u.%u.%02X\n",
|
||||||
info->version >> 4, info->version & 0xf, info->build);
|
info->version >> 4, info->version & 0xf, info->build);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2828,8 +2828,7 @@ static ssize_t mxt_hw_version_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct mxt_data *data = dev_get_drvdata(dev);
|
struct mxt_data *data = dev_get_drvdata(dev);
|
||||||
struct mxt_info *info = data->info;
|
struct mxt_info *info = data->info;
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u.%u\n",
|
return sysfs_emit(buf, "%u.%u\n", info->family_id, info->variant_id);
|
||||||
info->family_id, info->variant_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mxt_show_instance(char *buf, int count,
|
static ssize_t mxt_show_instance(char *buf, int count,
|
||||||
|
@ -2839,13 +2838,12 @@ static ssize_t mxt_show_instance(char *buf, int count,
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (mxt_obj_instances(object) > 1)
|
if (mxt_obj_instances(object) > 1)
|
||||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
count += sysfs_emit_at(buf, count, "Instance %u\n", instance);
|
||||||
"Instance %u\n", instance);
|
|
||||||
|
|
||||||
for (i = 0; i < mxt_obj_size(object); i++)
|
for (i = 0; i < mxt_obj_size(object); i++)
|
||||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
count += sysfs_emit_at(buf, count, "\t[%2u]: %02x (%d)\n",
|
||||||
"\t[%2u]: %02x (%d)\n", i, val[i], val[i]);
|
i, val[i], val[i]);
|
||||||
count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
|
count += sysfs_emit_at(buf, count, "\n");
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -2872,8 +2870,7 @@ static ssize_t mxt_object_show(struct device *dev,
|
||||||
if (!mxt_object_readable(object->type))
|
if (!mxt_object_readable(object->type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
count += scnprintf(buf + count, PAGE_SIZE - count,
|
count += sysfs_emit_at(buf, count, "T%u:\n", object->type);
|
||||||
"T%u:\n", object->type);
|
|
||||||
|
|
||||||
for (j = 0; j < mxt_obj_instances(object); j++) {
|
for (j = 0; j < mxt_obj_instances(object); j++) {
|
||||||
u16 size = mxt_obj_size(object);
|
u16 size = mxt_obj_size(object);
|
||||||
|
|
|
@ -431,7 +431,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
|
||||||
*field = val;
|
*field = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = scnprintf(buf, PAGE_SIZE, "%d\n", val);
|
count = sysfs_emit(buf, "%d\n", val);
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&tsdata->mutex);
|
mutex_unlock(&tsdata->mutex);
|
||||||
return error ?: count;
|
return error ?: count;
|
||||||
|
|
|
@ -928,8 +928,7 @@ static ssize_t hideep_fw_version_show(struct device *dev,
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
mutex_lock(&ts->dev_mutex);
|
mutex_lock(&ts->dev_mutex);
|
||||||
len = scnprintf(buf, PAGE_SIZE, "%04x\n",
|
len = sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.release_ver));
|
||||||
be16_to_cpu(ts->dwz_info.release_ver));
|
|
||||||
mutex_unlock(&ts->dev_mutex);
|
mutex_unlock(&ts->dev_mutex);
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
|
@ -943,8 +942,7 @@ static ssize_t hideep_product_id_show(struct device *dev,
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
mutex_lock(&ts->dev_mutex);
|
mutex_lock(&ts->dev_mutex);
|
||||||
len = scnprintf(buf, PAGE_SIZE, "%04x\n",
|
len = sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.product_id));
|
||||||
be16_to_cpu(ts->dwz_info.product_id));
|
|
||||||
mutex_unlock(&ts->dev_mutex);
|
mutex_unlock(&ts->dev_mutex);
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
|
|
|
@ -202,7 +202,7 @@ static ssize_t hycon_hy46xx_setting_show(struct device *dev,
|
||||||
*field = val;
|
*field = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = scnprintf(buf, PAGE_SIZE, "%d\n", val);
|
count = sysfs_emit(buf, "%d\n", val);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&tsdata->mutex);
|
mutex_unlock(&tsdata->mutex);
|
||||||
|
|
|
@ -512,7 +512,7 @@ static ssize_t firmware_version_show(struct device *dev,
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct ilitek_ts_data *ts = i2c_get_clientdata(client);
|
struct ilitek_ts_data *ts = i2c_get_clientdata(client);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE,
|
return sysfs_emit(buf,
|
||||||
"fw version: [%02X%02X.%02X%02X.%02X%02X.%02X%02X]\n",
|
"fw version: [%02X%02X.%02X%02X.%02X%02X.%02X%02X]\n",
|
||||||
ts->firmware_ver[0], ts->firmware_ver[1],
|
ts->firmware_ver[0], ts->firmware_ver[1],
|
||||||
ts->firmware_ver[2], ts->firmware_ver[3],
|
ts->firmware_ver[2], ts->firmware_ver[3],
|
||||||
|
@ -527,7 +527,7 @@ static ssize_t product_id_show(struct device *dev,
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct ilitek_ts_data *ts = i2c_get_clientdata(client);
|
struct ilitek_ts_data *ts = i2c_get_clientdata(client);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "product id: [%04X], module: [%s]\n",
|
return sysfs_emit(buf, "product id: [%04X], module: [%s]\n",
|
||||||
ts->mcu_ver, ts->product_id);
|
ts->mcu_ver, ts->product_id);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RO(product_id);
|
static DEVICE_ATTR_RO(product_id);
|
||||||
|
|
|
@ -943,7 +943,7 @@ static ssize_t fw_info_show(struct device *dev,
|
||||||
if (!iqs5xx->dev_id_info.bl_status)
|
if (!iqs5xx->dev_id_info.bl_status)
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u.%u.%u.%u:%u.%u\n",
|
return sysfs_emit(buf, "%u.%u.%u.%u:%u.%u\n",
|
||||||
be16_to_cpu(iqs5xx->dev_id_info.prod_num),
|
be16_to_cpu(iqs5xx->dev_id_info.prod_num),
|
||||||
be16_to_cpu(iqs5xx->dev_id_info.proj_num),
|
be16_to_cpu(iqs5xx->dev_id_info.proj_num),
|
||||||
iqs5xx->dev_id_info.major_ver,
|
iqs5xx->dev_id_info.major_ver,
|
||||||
|
|
|
@ -2401,7 +2401,7 @@ static ssize_t fw_info_show(struct device *dev,
|
||||||
{
|
{
|
||||||
struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
|
struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%u.%u.%u.%u:%u.%u\n",
|
return sysfs_emit(buf, "%u.%u.%u.%u:%u.%u\n",
|
||||||
le16_to_cpu(iqs7211->ver_info.prod_num),
|
le16_to_cpu(iqs7211->ver_info.prod_num),
|
||||||
le32_to_cpu(iqs7211->ver_info.patch),
|
le32_to_cpu(iqs7211->ver_info.patch),
|
||||||
le16_to_cpu(iqs7211->ver_info.major),
|
le16_to_cpu(iqs7211->ver_info.major),
|
||||||
|
|
|
@ -1336,7 +1336,7 @@ static ssize_t mip4_sysfs_read_fw_version(struct device *dev,
|
||||||
/* Take lock to prevent racing with firmware update */
|
/* Take lock to prevent racing with firmware update */
|
||||||
mutex_lock(&ts->input->mutex);
|
mutex_lock(&ts->input->mutex);
|
||||||
|
|
||||||
count = snprintf(buf, PAGE_SIZE, "%04X %04X %04X %04X\n",
|
count = sysfs_emit(buf, "%04X %04X %04X %04X\n",
|
||||||
ts->fw_version.boot, ts->fw_version.core,
|
ts->fw_version.boot, ts->fw_version.core,
|
||||||
ts->fw_version.app, ts->fw_version.param);
|
ts->fw_version.app, ts->fw_version.param);
|
||||||
|
|
||||||
|
@ -1362,7 +1362,7 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
|
||||||
* product_name shows the name or version of the hardware
|
* product_name shows the name or version of the hardware
|
||||||
* paired with current firmware in the chip.
|
* paired with current firmware in the chip.
|
||||||
*/
|
*/
|
||||||
count = snprintf(buf, PAGE_SIZE, "%.*s\n",
|
count = sysfs_emit(buf, "%.*s\n",
|
||||||
(int)sizeof(ts->product_name), ts->product_name);
|
(int)sizeof(ts->product_name), ts->product_name);
|
||||||
|
|
||||||
mutex_unlock(&ts->input->mutex);
|
mutex_unlock(&ts->input->mutex);
|
||||||
|
@ -1382,7 +1382,7 @@ static ssize_t mip4_sysfs_read_product_id(struct device *dev,
|
||||||
|
|
||||||
mutex_lock(&ts->input->mutex);
|
mutex_lock(&ts->input->mutex);
|
||||||
|
|
||||||
count = snprintf(buf, PAGE_SIZE, "%04X\n", ts->product_id);
|
count = sysfs_emit(buf, "%04X\n", ts->product_id);
|
||||||
|
|
||||||
mutex_unlock(&ts->input->mutex);
|
mutex_unlock(&ts->input->mutex);
|
||||||
|
|
||||||
|
@ -1401,7 +1401,7 @@ static ssize_t mip4_sysfs_read_ic_name(struct device *dev,
|
||||||
|
|
||||||
mutex_lock(&ts->input->mutex);
|
mutex_lock(&ts->input->mutex);
|
||||||
|
|
||||||
count = snprintf(buf, PAGE_SIZE, "%.*s\n",
|
count = sysfs_emit(buf, "%.*s\n",
|
||||||
(int)sizeof(ts->ic_name), ts->ic_name);
|
(int)sizeof(ts->ic_name), ts->ic_name);
|
||||||
|
|
||||||
mutex_unlock(&ts->input->mutex);
|
mutex_unlock(&ts->input->mutex);
|
||||||
|
|
|
@ -456,7 +456,7 @@ static ssize_t mtouch_firmware_rev_show(struct device *dev,
|
||||||
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
|
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
|
||||||
struct mtouch_priv *priv = usbtouch->priv;
|
struct mtouch_priv *priv = usbtouch->priv;
|
||||||
|
|
||||||
return scnprintf(output, PAGE_SIZE, "%1x.%1x\n",
|
return sysfs_emit(output, "%1x.%1x\n",
|
||||||
priv->fw_rev_major, priv->fw_rev_minor);
|
priv->fw_rev_major, priv->fw_rev_minor);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR(firmware_rev, 0444, mtouch_firmware_rev_show, NULL);
|
static DEVICE_ATTR(firmware_rev, 0444, mtouch_firmware_rev_show, NULL);
|
||||||
|
|
|
@ -887,7 +887,7 @@ static ssize_t config_csum_show(struct device *dev,
|
||||||
cfg_csum = wdt->param.xmls_id1;
|
cfg_csum = wdt->param.xmls_id1;
|
||||||
cfg_csum = (cfg_csum << 16) | wdt->param.xmls_id2;
|
cfg_csum = (cfg_csum << 16) | wdt->param.xmls_id2;
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%x\n", cfg_csum);
|
return sysfs_emit(buf, "%x\n", cfg_csum);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t fw_version_show(struct device *dev,
|
static ssize_t fw_version_show(struct device *dev,
|
||||||
|
@ -896,7 +896,7 @@ static ssize_t fw_version_show(struct device *dev,
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct wdt87xx_data *wdt = i2c_get_clientdata(client);
|
struct wdt87xx_data *wdt = i2c_get_clientdata(client);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%x\n", wdt->param.fw_id);
|
return sysfs_emit(buf, "%x\n", wdt->param.fw_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t plat_id_show(struct device *dev,
|
static ssize_t plat_id_show(struct device *dev,
|
||||||
|
@ -905,7 +905,7 @@ static ssize_t plat_id_show(struct device *dev,
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct wdt87xx_data *wdt = i2c_get_clientdata(client);
|
struct wdt87xx_data *wdt = i2c_get_clientdata(client);
|
||||||
|
|
||||||
return scnprintf(buf, PAGE_SIZE, "%x\n", wdt->param.plat_id);
|
return sysfs_emit(buf, "%x\n", wdt->param.plat_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t update_config_store(struct device *dev,
|
static ssize_t update_config_store(struct device *dev,
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/sysfs.h>
|
#include <linux/sysfs.h>
|
||||||
#include <linux/input/mt.h>
|
#include <linux/input/mt.h>
|
||||||
|
#include <linux/input/touchscreen.h>
|
||||||
#include <linux/platform_data/zforce_ts.h>
|
#include <linux/platform_data/zforce_ts.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
@ -106,6 +107,7 @@ struct zforce_point {
|
||||||
struct zforce_ts {
|
struct zforce_ts {
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
|
struct touchscreen_properties prop;
|
||||||
const struct zforce_ts_platdata *pdata;
|
const struct zforce_ts_platdata *pdata;
|
||||||
char phys[32];
|
char phys[32];
|
||||||
|
|
||||||
|
@ -266,7 +268,6 @@ static int zforce_setconfig(struct zforce_ts *ts, char b1)
|
||||||
static int zforce_start(struct zforce_ts *ts)
|
static int zforce_start(struct zforce_ts *ts)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = ts->client;
|
struct i2c_client *client = ts->client;
|
||||||
const struct zforce_ts_platdata *pdata = ts->pdata;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_dbg(&client->dev, "starting device\n");
|
dev_dbg(&client->dev, "starting device\n");
|
||||||
|
@ -277,7 +278,7 @@ static int zforce_start(struct zforce_ts *ts)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = zforce_resolution(ts, pdata->x_max, pdata->y_max);
|
ret = zforce_resolution(ts, ts->prop.max_x, ts->prop.max_y);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&client->dev, "Unable to set resolution, %d\n", ret);
|
dev_err(&client->dev, "Unable to set resolution, %d\n", ret);
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -337,7 +338,6 @@ static int zforce_stop(struct zforce_ts *ts)
|
||||||
static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
|
static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = ts->client;
|
struct i2c_client *client = ts->client;
|
||||||
const struct zforce_ts_platdata *pdata = ts->pdata;
|
|
||||||
struct zforce_point point;
|
struct zforce_point point;
|
||||||
int count, i, num = 0;
|
int count, i, num = 0;
|
||||||
|
|
||||||
|
@ -355,8 +355,8 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
|
||||||
point.coord_y =
|
point.coord_y =
|
||||||
payload[9 * i + 4] << 8 | payload[9 * i + 3];
|
payload[9 * i + 4] << 8 | payload[9 * i + 3];
|
||||||
|
|
||||||
if (point.coord_x > pdata->x_max ||
|
if (point.coord_x > ts->prop.max_x ||
|
||||||
point.coord_y > pdata->y_max) {
|
point.coord_y > ts->prop.max_y) {
|
||||||
dev_warn(&client->dev, "coordinates (%d,%d) invalid\n",
|
dev_warn(&client->dev, "coordinates (%d,%d) invalid\n",
|
||||||
point.coord_x, point.coord_y);
|
point.coord_x, point.coord_y);
|
||||||
point.coord_x = point.coord_y = 0;
|
point.coord_x = point.coord_y = 0;
|
||||||
|
@ -390,10 +390,9 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
|
||||||
point.state != STATE_UP);
|
point.state != STATE_UP);
|
||||||
|
|
||||||
if (point.state != STATE_UP) {
|
if (point.state != STATE_UP) {
|
||||||
input_report_abs(ts->input, ABS_MT_POSITION_X,
|
touchscreen_report_pos(ts->input, &ts->prop,
|
||||||
point.coord_x);
|
point.coord_x, point.coord_y,
|
||||||
input_report_abs(ts->input, ABS_MT_POSITION_Y,
|
true);
|
||||||
point.coord_y);
|
|
||||||
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
|
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
|
||||||
point.area_major);
|
point.area_major);
|
||||||
input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
|
input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
|
||||||
|
@ -719,15 +718,8 @@ static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (of_property_read_u32(np, "x-size", &pdata->x_max)) {
|
of_property_read_u32(np, "x-size", &pdata->x_max);
|
||||||
dev_err(dev, "failed to get x-size property\n");
|
of_property_read_u32(np, "y-size", &pdata->y_max);
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (of_property_read_u32(np, "y-size", &pdata->y_max)) {
|
|
||||||
dev_err(dev, "failed to get y-size property\n");
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pdata;
|
return pdata;
|
||||||
}
|
}
|
||||||
|
@ -856,6 +848,12 @@ static int zforce_probe(struct i2c_client *client)
|
||||||
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
|
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
|
||||||
pdata->y_max, 0, 0);
|
pdata->y_max, 0, 0);
|
||||||
|
|
||||||
|
touchscreen_parse_properties(input_dev, true, &ts->prop);
|
||||||
|
if (ts->prop.max_x == 0 || ts->prop.max_y == 0) {
|
||||||
|
dev_err(&client->dev, "no size specified\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
|
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
|
||||||
ZFORCE_MAX_AREA, 0, 0);
|
ZFORCE_MAX_AREA, 0, 0);
|
||||||
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0,
|
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0,
|
||||||
|
|
|
@ -27,10 +27,10 @@ ssize_t vivaldi_function_row_physmap_show(const struct vivaldi_data *data,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < data->num_function_row_keys; i++)
|
for (i = 0; i < data->num_function_row_keys; i++)
|
||||||
size += scnprintf(buf + size, PAGE_SIZE - size,
|
size += sysfs_emit_at(buf, size,
|
||||||
"%s%02X", size ? " " : "", physmap[i]);
|
"%s%02X", size ? " " : "", physmap[i]);
|
||||||
if (size)
|
if (size)
|
||||||
size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
|
size += sysfs_emit_at(buf, size, "\n");
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ struct device;
|
||||||
* disable button via sysfs
|
* disable button via sysfs
|
||||||
* @value: axis value for %EV_ABS
|
* @value: axis value for %EV_ABS
|
||||||
* @irq: Irq number in case of interrupt keys
|
* @irq: Irq number in case of interrupt keys
|
||||||
|
* @wakeirq: Optional dedicated wake-up interrupt
|
||||||
*/
|
*/
|
||||||
struct gpio_keys_button {
|
struct gpio_keys_button {
|
||||||
unsigned int code;
|
unsigned int code;
|
||||||
|
@ -34,6 +35,7 @@ struct gpio_keys_button {
|
||||||
bool can_disable;
|
bool can_disable;
|
||||||
int value;
|
int value;
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
|
unsigned int wakeirq;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct as5011_platform_data {
|
struct as5011_platform_data {
|
||||||
unsigned int button_gpio;
|
|
||||||
unsigned int axis_irq; /* irq number */
|
unsigned int axis_irq; /* irq number */
|
||||||
unsigned long axis_irqflags;
|
unsigned long axis_irqflags;
|
||||||
char xp, xn; /* threshold for x axis */
|
char xp, xn; /* threshold for x axis */
|
||||||
|
|
|
@ -5,5 +5,4 @@
|
||||||
|
|
||||||
struct navpoint_platform_data {
|
struct navpoint_platform_data {
|
||||||
int port; /* PXA SSP port for pxa_ssp_request() */
|
int port; /* PXA SSP port for pxa_ssp_request() */
|
||||||
int gpio; /* GPIO for power on/off */
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,9 +19,6 @@ struct omap_kp_platform_data {
|
||||||
bool rep;
|
bool rep;
|
||||||
unsigned long delay;
|
unsigned long delay;
|
||||||
bool dbounce;
|
bool dbounce;
|
||||||
/* specific to OMAP242x*/
|
|
||||||
unsigned int *row_gpios;
|
|
||||||
unsigned int *col_gpios;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Group (0..3) -- when multiple keys are pressed, only the
|
/* Group (0..3) -- when multiple keys are pressed, only the
|
||||||
|
|
Loading…
Reference in a new issue