Commit 9ae2940c authored by Linus Torvalds's avatar Linus Torvalds

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

Pull input updates from Dmitry Torokhov:

 - support for PixArt PS/2 touchpad

 - updates to tsc2004/5, usbtouchscreen, and zforce_ts drivers

 - support for GPIO-only mode for ADP55888 controller

 - support for touch keys in Zinitix driver

 - support for querying density of Synaptics sensors

 - sysfs interface for Goodex "Berlin" devices to read and write touch
   IC registers

 - more quirks to i8042 to handle various Tuxedo laptops

 - a number of drivers have been converted to using "guard" notation
   when acquiring various locks, as well as using other cleanup
   functions to simplify releasing of resources (with more drivers to
   follow)

 - evdev will limit amount of data that can be written into an evdev
   instance at a given time to 4096 bytes (170 input events) to avoid
   holding evdev->mutex for too long and starving other users

 - Spitz has been converted to use software nodes/properties to describe
   its matrix keypad and GPIO-connected LEDs

 - msc5000_ts, msc_touchkey and keypad-nomadik-ske drivers have been
   removed since noone in mainline have been using them

 - other assorted cleanups and fixes

* tag 'input-for-v6.12-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (98 commits)
  ARM: spitz: fix compile error when matrix keypad driver is enabled
  Input: hynitron_cstxxx - drop explicit initialization of struct i2c_device_id::driver_data to 0
  Input: adp5588-keys - fix check on return code
  Input: Convert comma to semicolon
  Input: i8042 - add TUXEDO Stellaris 15 Slim Gen6 AMD to i8042 quirk table
  Input: i8042 - add another board name for TUXEDO Stellaris Gen5 AMD line
  Input: tegra-kbc - use of_property_read_variable_u32_array() and of_property_present()
  Input: ps2-gpio - use IRQF_NO_AUTOEN flag in request_irq()
  Input: ims-pcu - fix calling interruptible mutex
  Input: zforce_ts - switch to using asynchronous probing
  Input: zforce_ts - remove assert/deassert wrappers
  Input: zforce_ts - do not hardcode interrupt level
  Input: zforce_ts - switch to using devm_regulator_get_enable()
  Input: zforce_ts - stop treating VDD regulator as optional
  Input: zforce_ts - make zforce_idtable constant
  Input: zforce_ts - use dev_err_probe() where appropriate
  Input: zforce_ts - do not ignore errors when acquiring regulator
  Input: zforce_ts - make parsing of contacts less confusing
  Input: zforce_ts - switch to using get_unaligned_le16
  Input: zforce_ts - use guard notation when acquiring mutexes
  ...
parents 6db6a19f 358800b7
...@@ -49,7 +49,10 @@ properties: ...@@ -49,7 +49,10 @@ properties:
interrupt-controller: interrupt-controller:
description: description:
This property applies if either keypad,num-rows lower than 8 or This property applies if either keypad,num-rows lower than 8 or
keypad,num-columns lower than 10. keypad,num-columns lower than 10. This property is optional if
keypad,num-rows or keypad,num-columns are not specified as the
device is then configured to be used purely for gpio during which
interrupts may or may not be utilized.
'#interrupt-cells': '#interrupt-cells':
const: 2 const: 2
...@@ -65,13 +68,23 @@ properties: ...@@ -65,13 +68,23 @@ properties:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 2
dependencies:
keypad,num-rows:
- linux,keymap
- keypad,num-columns
keypad,num-columns:
- linux,keymap
- keypad,num-rows
linux,keymap:
- keypad,num-rows
- keypad,num-columns
- interrupts
interrupt-controller:
- interrupts
required: required:
- compatible - compatible
- reg - reg
- interrupts
- keypad,num-rows
- keypad,num-columns
- linux,keymap
unevaluatedProperties: false unevaluatedProperties: false
...@@ -108,4 +121,19 @@ examples: ...@@ -108,4 +121,19 @@ examples:
>; >;
}; };
}; };
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
gpio@34 {
compatible = "adi,adp5588";
reg = <0x34>;
#gpio-cells = <2>;
gpio-controller;
};
};
... ...
Rotary encoder DT bindings
Required properties:
- gpios: a spec for at least two GPIOs to be used, most significant first
Optional properties:
- linux,axis: the input subsystem axis to map to this rotary encoder.
Defaults to 0 (ABS_X / REL_X)
- rotary-encoder,steps: Number of steps in a full turnaround of the
encoder. Only relevant for absolute axis. Defaults to 24 which is a
typical value for such devices.
- rotary-encoder,relative-axis: register a relative axis rather than an
absolute one. Relative axis will only generate +1/-1 events on the input
device, hence no steps need to be passed.
- rotary-encoder,rollover: Automatic rollover when the rotary value becomes
greater than the specified steps or smaller than 0. For absolute axis only.
- rotary-encoder,steps-per-period: Number of steps (stable states) per period.
The values have the following meaning:
1: Full-period mode (default)
2: Half-period mode
4: Quarter-period mode
- wakeup-source: Boolean, rotary encoder can wake up the system.
- rotary-encoder,encoding: String, the method used to encode steps.
Supported are "gray" (the default and more common) and "binary".
Deprecated properties:
- rotary-encoder,half-period: Makes the driver work on half-period mode.
This property is deprecated. Instead, a 'steps-per-period ' value should
be used, such as "rotary-encoder,steps-per-period = <2>".
See Documentation/input/devices/rotary-encoder.rst for more information.
Example:
rotary@0 {
compatible = "rotary-encoder";
gpios = <&gpio 19 1>, <&gpio 20 0>; /* GPIO19 is inverted */
linux,axis = <0>; /* REL_X */
rotary-encoder,encoding = "gray";
rotary-encoder,relative-axis;
};
rotary@1 {
compatible = "rotary-encoder";
gpios = <&gpio 21 0>, <&gpio 22 0>;
linux,axis = <1>; /* ABS_Y */
rotary-encoder,steps = <24>;
rotary-encoder,encoding = "binary";
rotary-encoder,rollover;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/rotary-encoder.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rotary encoder
maintainers:
- Frank Li <Frank.Li@nxp.com>
description:
See Documentation/input/devices/rotary-encoder.rst for more information.
properties:
compatible:
const: rotary-encoder
gpios:
minItems: 2
linux,axis:
default: 0
description:
the input subsystem axis to map to this rotary encoder.
Defaults to 0 (ABS_X / REL_X)
rotary-encoder,steps:
$ref: /schemas/types.yaml#/definitions/uint32
default: 24
description:
Number of steps in a full turnaround of the
encoder. Only relevant for absolute axis. Defaults to 24 which is a
typical value for such devices.
rotary-encoder,relative-axis:
$ref: /schemas/types.yaml#/definitions/flag
description:
register a relative axis rather than an
absolute one. Relative axis will only generate +1/-1 events on the input
device, hence no steps need to be passed.
rotary-encoder,rollover:
$ref: /schemas/types.yaml#/definitions/int32
description:
Automatic rollover when the rotary value becomes
greater than the specified steps or smaller than 0. For absolute axis only.
rotary-encoder,steps-per-period:
$ref: /schemas/types.yaml#/definitions/uint32
default: 1
enum: [1, 2, 4]
description: |
Number of steps (stable states) per period.
The values have the following meaning:
1: Full-period mode (default)
2: Half-period mode
4: Quarter-period mode
wakeup-source: true
rotary-encoder,encoding:
$ref: /schemas/types.yaml#/definitions/string
description: the method used to encode steps.
enum: [gray, binary]
rotary-encoder,half-period:
$ref: /schemas/types.yaml#/definitions/flag
deprecated: true
description:
Makes the driver work on half-period mode.
This property is deprecated. Instead, a 'steps-per-period ' value should
be used, such as "rotary-encoder,steps-per-period = <2>".
required:
- compatible
- gpios
additionalProperties: false
examples:
- |
rotary {
compatible = "rotary-encoder";
gpios = <&gpio 19 1>, <&gpio 20 0>; /* GPIO19 is inverted */
linux,axis = <0>; /* REL_X */
rotary-encoder,encoding = "gray";
rotary-encoder,relative-axis;
};
* Analog Devices AD7879(-1)/AD7889(-1) touchscreen interface (SPI/I2C)
Required properties:
- compatible : for SPI slave, use "adi,ad7879"
for I2C slave, use "adi,ad7879-1"
- reg : SPI chipselect/I2C slave address
See spi-bus.txt for more SPI slave properties
- interrupts : touch controller interrupt
- touchscreen-max-pressure : maximum reported pressure
- adi,resistance-plate-x : total resistance of X-plate (for pressure
calculation)
Optional properties:
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
- adi,first-conversion-delay : 0-12: In 128us steps (starting with 128us)
13 : 2.560ms
14 : 3.584ms
15 : 4.096ms
This property has to be a '/bits/ 8' value
- adi,acquisition-time : 0: 2us
1: 4us
2: 8us
3: 16us
This property has to be a '/bits/ 8' value
- adi,median-filter-size : 0: disabled
1: 4 measurements
2: 8 measurements
3: 16 measurements
This property has to be a '/bits/ 8' value
- adi,averaging : 0: 2 middle values (1 if median disabled)
1: 4 middle values
2: 8 middle values
3: 16 values
This property has to be a '/bits/ 8' value
- adi,conversion-interval: : 0 : convert one time only
1-255: 515us + val * 35us (up to 9.440ms)
This property has to be a '/bits/ 8' value
- gpio-controller : Switch AUX/VBAT/GPIO pin to GPIO mode
Example:
touchscreen0@2c {
compatible = "adi,ad7879-1";
reg = <0x2c>;
interrupt-parent = <&gpio1>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
touchscreen-max-pressure = <4096>;
adi,resistance-plate-x = <120>;
adi,first-conversion-delay = /bits/ 8 <3>;
adi,acquisition-time = /bits/ 8 <1>;
adi,median-filter-size = /bits/ 8 <2>;
adi,averaging = /bits/ 8 <1>;
adi,conversion-interval = /bits/ 8 <255>;
};
touchscreen1@1 {
compatible = "adi,ad7879";
spi-max-frequency = <5000000>;
reg = <1>;
spi-cpol;
spi-cpha;
gpio-controller;
interrupt-parent = <&gpio1>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
touchscreen-max-pressure = <4096>;
adi,resistance-plate-x = <120>;
adi,first-conversion-delay = /bits/ 8 <3>;
adi,acquisition-time = /bits/ 8 <1>;
adi,median-filter-size = /bits/ 8 <2>;
adi,averaging = /bits/ 8 <1>;
adi,conversion-interval = /bits/ 8 <255>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/touchscreen/adi,ad7879.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD7879(-1)/AD7889(-1) touchscreen interface (SPI/I2C)
maintainers:
- Frank Li <Frank.Li@nxp.com>
properties:
compatible:
description: |
for SPI slave, use "adi,ad7879"
for I2C slave, use "adi,ad7879-1"
enum:
- adi,ad7879
- adi,ad7879-1
reg:
maxItems: 1
interrupts:
maxItems: 1
touchscreen-max-pressure:
$ref: /schemas/types.yaml#/definitions/uint32
description: maximum reported pressure
adi,resistance-plate-x:
$ref: /schemas/types.yaml#/definitions/uint32
description: total resistance of X-plate (for pressure calculation)
touchscreen-swapped-x-y:
$ref: /schemas/types.yaml#/definitions/flag
description: X and Y axis are swapped (boolean)
adi,first-conversion-delay:
$ref: /schemas/types.yaml#/definitions/uint8
default: 0
minimum: 0
maximum: 15
description: |
0-12: In 128us steps (starting with 128us)
13 : 2.560ms
14 : 3.584ms
15 : 4.096ms
This property has to be a '/bits/ 8' value
adi,acquisition-time:
$ref: /schemas/types.yaml#/definitions/uint8
default: 0
enum: [0, 1, 2, 3]
description: |
0: 2us
1: 4us
2: 8us
3: 16us
This property has to be a '/bits/ 8' value
adi,median-filter-size:
$ref: /schemas/types.yaml#/definitions/uint8
default: 0
enum: [0, 1, 2, 3]
description: |
0: disabled
1: 4 measurements
2: 8 measurements
3: 16 measurements
This property has to be a '/bits/ 8' value
adi,averaging:
$ref: /schemas/types.yaml#/definitions/uint8
default: 0
enum: [0, 1, 2, 3]
description: |
0: 2 middle values (1 if median disabled)
1: 4 middle values
2: 8 middle values
3: 16 values
This property has to be a '/bits/ 8' value
adi,conversion-interval:
$ref: /schemas/types.yaml#/definitions/uint8
default: 0
description: |
0 : convert one time only
1-255: 515us + val * 35us (up to 9.440ms)
This property has to be a '/bits/ 8' value
gpio-controller: true
"#gpio-cells":
const: 1
required:
- compatible
- reg
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
touchscreen0@2c {
compatible = "adi,ad7879-1";
reg = <0x2c>;
interrupt-parent = <&gpio1>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
touchscreen-max-pressure = <4096>;
adi,resistance-plate-x = <120>;
adi,first-conversion-delay = /bits/ 8 <3>;
adi,acquisition-time = /bits/ 8 <1>;
adi,median-filter-size = /bits/ 8 <2>;
adi,averaging = /bits/ 8 <1>;
adi,conversion-interval = /bits/ 8 <255>;
};
};
- |
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
touchscreen1@1 {
compatible = "adi,ad7879";
reg = <1>;
spi-max-frequency = <5000000>;
gpio-controller;
#gpio-cells = <1>;
interrupt-parent = <&gpio1>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
touchscreen-max-pressure = <4096>;
adi,resistance-plate-x = <120>;
adi,first-conversion-delay = /bits/ 8 <3>;
adi,acquisition-time = /bits/ 8 <1>;
adi,median-filter-size = /bits/ 8 <2>;
adi,averaging = /bits/ 8 <1>;
adi,conversion-interval = /bits/ 8 <255>;
};
};
Device tree bindings for TI's ADS7843, ADS7845, ADS7846, ADS7873, TSC2046
SPI driven touch screen controllers.
The node for this driver must be a child node of a SPI controller, hence
all mandatory properties described in
Documentation/devicetree/bindings/spi/spi-bus.txt
must be specified.
Additional required properties:
compatible Must be one of the following, depending on the
model:
"ti,tsc2046"
"ti,ads7843"
"ti,ads7845"
"ti,ads7846"
"ti,ads7873"
interrupts An interrupt node describing the IRQ line the chip's
!PENIRQ pin is connected to.
vcc-supply A regulator node for the supply voltage.
Optional properties:
ti,vref-delay-usecs vref supply delay in usecs, 0 for
external vref (u16).
ti,vref-mv The VREF voltage, in millivolts (u16).
Set to 0 to use internal references
(ADS7846).
ti,keep-vref-on set to keep vref on for differential
measurements as well
ti,settle-delay-usec Settling time of the analog signals;
a function of Vcc and the capacitance
on the X/Y drivers. If set to non-zero,
two samples are taken with settle_delay
us apart, and the second one is used.
~150 uSec with 0.01uF caps (u16).
ti,penirq-recheck-delay-usecs If set to non-zero, after samples are
taken this delay is applied and penirq
is rechecked, to help avoid false
events. This value is affected by the
material used to build the touch layer
(u16).
ti,x-plate-ohms Resistance of the X-plate,
in Ohms (u16).
ti,y-plate-ohms Resistance of the Y-plate,
in Ohms (u16).
ti,x-min Minimum value on the X axis (u16).
ti,y-min Minimum value on the Y axis (u16).
ti,debounce-tol Tolerance used for filtering (u16).
ti,debounce-rep Additional consecutive good readings
required after the first two (u16).
ti,pendown-gpio-debounce Platform specific debounce time for the
pendown-gpio (u32).
pendown-gpio GPIO handle describing the pin the !PENIRQ
line is connected to.
ti,hsync-gpios GPIO line to poll for hsync
wakeup-source use any event on touchscreen as wakeup event.
(Legacy property support: "linux,wakeup")
touchscreen-size-x General touchscreen binding, see [1].
touchscreen-size-y General touchscreen binding, see [1].
touchscreen-max-pressure General touchscreen binding, see [1].
touchscreen-min-pressure General touchscreen binding, see [1].
touchscreen-average-samples General touchscreen binding, see [1].
touchscreen-inverted-x General touchscreen binding, see [1].
touchscreen-inverted-y General touchscreen binding, see [1].
touchscreen-swapped-x-y General touchscreen binding, see [1].
[1] All general touchscreen properties are described in
Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt.
Deprecated properties:
ti,swap-xy swap x and y axis
ti,x-max Maximum value on the X axis (u16).
ti,y-max Maximum value on the Y axis (u16).
ti,pressure-min Minimum reported pressure value
(threshold) - u16.
ti,pressure-max Maximum reported pressure value (u16).
ti,debounce-max Max number of additional readings per
sample (u16).
Example for a TSC2046 chip connected to an McSPI controller of an OMAP SoC::
spi_controller {
tsc2046@0 {
reg = <0>; /* CS0 */
compatible = "ti,tsc2046";
interrupt-parent = <&gpio1>;
interrupts = <8 0>; /* BOOT6 / GPIO 8 */
spi-max-frequency = <1000000>;
pendown-gpio = <&gpio1 8 0>;
vcc-supply = <&reg_vcc3>;
ti,x-min = /bits/ 16 <0>;
ti,x-max = /bits/ 16 <8000>;
ti,y-min = /bits/ 16 <0>;
ti,y-max = /bits/ 16 <4800>;
ti,x-plate-ohms = /bits/ 16 <40>;
ti,pressure-max = /bits/ 16 <255>;
wakeup-source;
};
};
...@@ -666,7 +666,7 @@ examples: ...@@ -666,7 +666,7 @@ examples:
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
touch@56 { touchscreen@56 {
compatible = "azoteq,iqs7210a"; compatible = "azoteq,iqs7210a";
reg = <0x56>; reg = <0x56>;
irq-gpios = <&gpio 4 GPIO_ACTIVE_LOW>; irq-gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
...@@ -704,7 +704,7 @@ examples: ...@@ -704,7 +704,7 @@ examples:
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
touch@56 { touchscreen@56 {
compatible = "azoteq,iqs7211e"; compatible = "azoteq,iqs7211e";
reg = <0x56>; reg = <0x56>;
irq-gpios = <&gpio 4 (GPIO_ACTIVE_LOW | irq-gpios = <&gpio 4 (GPIO_ACTIVE_LOW |
......
* Toradex Colibri VF50 Touchscreen driver
Required Properties:
- compatible must be toradex,vf50-touchscreen
- io-channels: adc channels being used by the Colibri VF50 module
IIO ADC for Y-, X-, Y+, X+ connections
- xp-gpios: FET gate driver for input of X+
- xm-gpios: FET gate driver for input of X-
- yp-gpios: FET gate driver for input of Y+
- ym-gpios: FET gate driver for input of Y-
- interrupts: pen irq interrupt for touch detection, signal from X plate
- pinctrl-names: "idle", "default"
- pinctrl-0: pinctrl node for pen/touch detection, pinctrl must provide
pull-up resistor on X+, X-.
- pinctrl-1: pinctrl node for X/Y and pressure measurement (ADC) state pinmux
- vf50-ts-min-pressure: pressure level at which to stop measuring X/Y values
Example:
touchctrl: vf50_touchctrl {
compatible = "toradex,vf50-touchscreen";
io-channels = <&adc1 0>,<&adc0 0>,
<&adc0 1>,<&adc1 2>;
xp-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
xm-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
yp-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
ym-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
interrupt-parent = <&gpio0>;
interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "idle","default";
pinctrl-0 = <&pinctrl_touchctrl_idle>, <&pinctrl_touchctrl_gpios>;
pinctrl-1 = <&pinctrl_touchctrl_default>, <&pinctrl_touchctrl_gpios>;
vf50-ts-min-pressure = <200>;
};
...@@ -126,7 +126,7 @@ examples: ...@@ -126,7 +126,7 @@ examples:
i2c { i2c {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
edt-ft5x06@38 { touchscreen@38 {
compatible = "edt,edt-ft5406"; compatible = "edt,edt-ft5406";
reg = <0x38>; reg = <0x38>;
interrupt-parent = <&gpio2>; interrupt-parent = <&gpio2>;
......
...@@ -69,7 +69,7 @@ examples: ...@@ -69,7 +69,7 @@ examples:
i2c { i2c {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
gt928@5d { touchscreen@5d {
compatible = "goodix,gt928"; compatible = "goodix,gt928";
reg = <0x5d>; reg = <0x5d>;
interrupt-parent = <&gpio>; interrupt-parent = <&gpio>;
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/touchscreen/ti,ads7843.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI's SPI driven touch screen controllers
maintainers:
- Alexander Stein <alexander.stein@ew.tq-group.com>
- Dmitry Torokhov <dmitry.torokhov@gmail.com>
- Marek Vasut <marex@denx.de>
description:
TI's ADS7843, ADS7845, ADS7846, ADS7873, TSC2046 SPI driven touch screen
controllers.
properties:
compatible:
enum:
- ti,ads7843
- ti,ads7845
- ti,ads7846
- ti,ads7873
- ti,tsc2046
interrupts:
maxItems: 1
pendown-gpio:
maxItems: 1
description:
GPIO handle describing the pin the !PENIRQ line is connected to.
vcc-supply:
description:
A regulator node for the supply voltage.
wakeup-source: true
ti,debounce-max:
deprecated: true
$ref: /schemas/types.yaml#/definitions/uint16
description:
Max number of additional readings per sample.
ti,debounce-rep:
$ref: /schemas/types.yaml#/definitions/uint16
description:
Additional consecutive good readings required after the first two.
ti,debounce-tol:
$ref: /schemas/types.yaml#/definitions/uint16
description:
Tolerance used for filtering.
ti,hsync-gpios:
maxItems: 1
description:
GPIO line to poll for hsync.
ti,keep-vref-on:
$ref: /schemas/types.yaml#/definitions/flag
description:
Set to keep Vref on for differential measurements as well.
ti,pendown-gpio-debounce:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Platform specific debounce time for the pendown-gpio.
ti,penirq-recheck-delay-usecs:
$ref: /schemas/types.yaml#/definitions/uint16
description:
If set to non-zero, after samples are taken this delay is applied and
penirq is rechecked, to help avoid false events. This value is
affected by the material used to build the touch layer.
ti,pressure-max:
deprecated: true
$ref: /schemas/types.yaml#/definitions/uint16
description:
Maximum reported pressure value.
ti,pressure-min:
deprecated: true
$ref: /schemas/types.yaml#/definitions/uint16
description:
Minimum reported pressure value (threshold).
ti,settle-delay-usec:
$ref: /schemas/types.yaml#/definitions/uint16
description:
Settling time of the analog signals; a function of Vcc and the
capacitance on the X/Y drivers. If set to non-zero, two samples are
taken with settle_delay us apart, and the second one is used. ~150
uSec with 0.01uF caps.
ti,swap-xy:
deprecated: true
$ref: /schemas/types.yaml#/definitions/flag
description:
Swap x and y axis.
ti,vref-delay-usecs:
$ref: /schemas/types.yaml#/definitions/uint16
description:
Vref supply delay in usecs, 0 for external Vref.
ti,vref-mv:
$ref: /schemas/types.yaml#/definitions/uint16
description:
The VREF voltage, in millivolts.
Set to 0 to use internal references (ADS7846).
ti,x-plate-ohms:
$ref: /schemas/types.yaml#/definitions/uint16
description:
Resistance of the X-plate, in Ohms.
ti,x-max:
deprecated: true
$ref: /schemas/types.yaml#/definitions/uint16
description:
Maximum value on the X axis.
ti,x-min:
deprecated: true
$ref: /schemas/types.yaml#/definitions/uint16
description:
Minimum value on the X axis.
ti,y-plate-ohms:
$ref: /schemas/types.yaml#/definitions/uint16
description:
Resistance of the Y-plate, in Ohms.
ti,y-max:
deprecated: true
$ref: /schemas/types.yaml#/definitions/uint16
description:
Maximum value on the Y axis.
ti,y-min:
deprecated: true
$ref: /schemas/types.yaml#/definitions/uint16
description:
Minimum value on the Y axis.
required:
- compatible
- reg
allOf:
- $ref: touchscreen.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
spi{
#address-cells = <1>;
#size-cells = <0>;
touchscreen@0 {
compatible = "ti,tsc2046";
reg = <0>; /* CS0 */
interrupt-parent = <&gpio1>;
interrupts = <8 0>; /* BOOT6 / GPIO 8 */
pendown-gpio = <&gpio1 8 0>;
spi-max-frequency = <1000000>;
vcc-supply = <&reg_vcc3>;
wakeup-source;
ti,pressure-max = /bits/ 16 <255>;
ti,x-max = /bits/ 16 <8000>;
ti,x-min = /bits/ 16 <0>;
ti,x-plate-ohms = /bits/ 16 <40>;
ti,y-max = /bits/ 16 <4800>;
ti,y-min = /bits/ 16 <0>;
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/touchscreen/toradex,vf50-touchscreen.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Toradex Colibri VF50 Touchscreen
maintainers:
- Dmitry Torokhov <dmitry.torokhov@gmail.com>
- Sanchayan Maity <maitysanchayan@gmail.com>
properties:
compatible:
const: toradex,vf50-touchscreen
interrupts:
maxItems: 1
io-channels:
maxItems: 4
description:
adc channels being used by the Colibri VF50 module
IIO ADC for Y-, X-, Y+, X+ connections
xp-gpios:
description: FET gate driver for input of X+
xm-gpios:
description: FET gate driver for input of X-
yp-gpios:
description: FET gate driver for input of Y+
ym-gpios:
description: FET gate driver for input of Y-
vf50-ts-min-pressure:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 50
maximum: 2000
description: pressure level at which to stop measuring X/Y values
required:
- compatible
- io-channels
- xp-gpios
- xm-gpios
- yp-gpios
- ym-gpios
- interrupts
- vf50-ts-min-pressure
allOf:
- $ref: touchscreen.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
touchscreen {
compatible = "toradex,vf50-touchscreen";
interrupt-parent = <&gpio0>;
interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
io-channels = <&adc1 0>, <&adc0 0>, <&adc0 1>, <&adc1 2>;
xp-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
xm-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
yp-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
ym-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
pinctrl-names = "idle", "default";
pinctrl-0 = <&pinctrl_touchctrl_idle>, <&pinctrl_touchctrl_gpios>;
pinctrl-1 = <&pinctrl_touchctrl_default>, <&pinctrl_touchctrl_gpios>;
vf50-ts-min-pressure = <200>;
};
...@@ -16,6 +16,7 @@ maintainers: ...@@ -16,6 +16,7 @@ maintainers:
allOf: allOf:
- $ref: touchscreen.yaml# - $ref: touchscreen.yaml#
- $ref: ../input.yaml#
properties: properties:
$nodename: $nodename:
...@@ -79,6 +80,15 @@ properties: ...@@ -79,6 +80,15 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2] enum: [1, 2]
linux,keycodes:
description:
This property specifies an array of keycodes assigned to the
touch-keys that can be present in some touchscreen configurations.
If the touch-keys are enabled, controller firmware will assign some
touch sense lines to those keys.
minItems: 1
maxItems: 8
touchscreen-size-x: true touchscreen-size-x: true
touchscreen-size-y: true touchscreen-size-y: true
touchscreen-fuzz-x: true touchscreen-fuzz-x: true
......
...@@ -25,7 +25,7 @@ List of legacy properties and respective binding document ...@@ -25,7 +25,7 @@ List of legacy properties and respective binding document
2. "has-tpo" Documentation/devicetree/bindings/rtc/rtc-opal.txt 2. "has-tpo" Documentation/devicetree/bindings/rtc/rtc-opal.txt
3. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt 3. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
Documentation/devicetree/bindings/mfd/tc3589x.txt Documentation/devicetree/bindings/mfd/tc3589x.txt
Documentation/devicetree/bindings/input/touchscreen/ads7846.txt Documentation/devicetree/bindings/input/touchscreen/ti,ads7843.yaml
4. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8921-keypad.yaml 4. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8921-keypad.yaml
5. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung,s3c6410-keypad.yaml 5. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung,s3c6410-keypad.yaml
6. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt 6. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
......
...@@ -11198,10 +11198,17 @@ F: Documentation/devicetree/bindings/serio/ ...@@ -11198,10 +11198,17 @@ F: Documentation/devicetree/bindings/serio/
F: Documentation/input/ F: Documentation/input/
F: drivers/input/ F: drivers/input/
F: include/dt-bindings/input/ F: include/dt-bindings/input/
F: include/linux/gameport.h
F: include/linux/i8042.h
F: include/linux/input.h F: include/linux/input.h
F: include/linux/input/ F: include/linux/input/
F: include/linux/libps2.h
F: include/linux/serio.h
F: include/uapi/linux/gameport.h
F: include/uapi/linux/input-event-codes.h F: include/uapi/linux/input-event-codes.h
F: include/uapi/linux/input.h F: include/uapi/linux/input.h
F: include/uapi/linux/serio.h
F: include/uapi/linux/uinput.h
INPUT MULTITOUCH (MT) PROTOCOL INPUT MULTITOUCH (MT) PROTOCOL
M: Henrik Rydberg <rydberg@bitmath.org> M: Henrik Rydberg <rydberg@bitmath.org>
...@@ -25532,7 +25539,6 @@ F: tools/net/ynl/ ...@@ -25532,7 +25539,6 @@ F: tools/net/ynl/
YEALINK PHONE DRIVER YEALINK PHONE DRIVER
M: Henk Vergonet <Henk.Vergonet@gmail.com> M: Henk Vergonet <Henk.Vergonet@gmail.com>
L: usbb2k-api-dev@nongnu.org
S: Maintained S: Maintained
F: Documentation/input/devices/yealink.rst F: Documentation/input/devices/yealink.rst
F: drivers/input/misc/yealink.* F: drivers/input/misc/yealink.*
......
...@@ -378,38 +378,56 @@ static const uint32_t spitz_keymap[] = { ...@@ -378,38 +378,56 @@ static const uint32_t spitz_keymap[] = {
KEY(6, 8, KEY_RIGHT), KEY(6, 8, KEY_RIGHT),
}; };
static const struct matrix_keymap_data spitz_keymap_data = { static const struct software_node_ref_args spitz_mkp_row_gpios[] = {
.keymap = spitz_keymap, SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 12, GPIO_ACTIVE_HIGH),
.keymap_size = ARRAY_SIZE(spitz_keymap), SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 17, GPIO_ACTIVE_HIGH),
SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 91, GPIO_ACTIVE_HIGH),
SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 34, GPIO_ACTIVE_HIGH),
SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 36, GPIO_ACTIVE_HIGH),
SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 38, GPIO_ACTIVE_HIGH),
SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 39, GPIO_ACTIVE_HIGH),
}; };
static const uint32_t spitz_row_gpios[] = static const struct software_node_ref_args spitz_mkp_col_gpios[] = {
{ 12, 17, 91, 34, 36, 38, 39 }; SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 88, GPIO_ACTIVE_HIGH),
static const uint32_t spitz_col_gpios[] = SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 23, GPIO_ACTIVE_HIGH),
{ 88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114 }; SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 24, GPIO_ACTIVE_HIGH),
SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 25, GPIO_ACTIVE_HIGH),
static struct matrix_keypad_platform_data spitz_mkp_pdata = { SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 26, GPIO_ACTIVE_HIGH),
.keymap_data = &spitz_keymap_data, SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 27, GPIO_ACTIVE_HIGH),
.row_gpios = spitz_row_gpios, SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 52, GPIO_ACTIVE_HIGH),
.col_gpios = spitz_col_gpios, SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 103, GPIO_ACTIVE_HIGH),
.num_row_gpios = ARRAY_SIZE(spitz_row_gpios), SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 107, GPIO_ACTIVE_HIGH),
.num_col_gpios = ARRAY_SIZE(spitz_col_gpios), SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 108, GPIO_ACTIVE_HIGH),
.col_scan_delay_us = 10, SOFTWARE_NODE_REFERENCE(&pxa2xx_gpiochip_node, 114, GPIO_ACTIVE_HIGH),
.debounce_ms = 10,
.wakeup = 1,
}; };
static struct platform_device spitz_mkp_device = { static const struct property_entry spitz_mkp_properties[] = {
PROPERTY_ENTRY_U32_ARRAY("linux,keymap", spitz_keymap),
PROPERTY_ENTRY_REF_ARRAY("row-gpios", spitz_mkp_row_gpios),
PROPERTY_ENTRY_REF_ARRAY("col-gpios", spitz_mkp_col_gpios),
PROPERTY_ENTRY_U32("col-scan-delay-us", 10),
PROPERTY_ENTRY_U32("debounce-delay-ms", 10),
PROPERTY_ENTRY_BOOL("wakeup-source"),
{ }
};
static const struct platform_device_info spitz_mkp_info __initconst = {
.name = "matrix-keypad", .name = "matrix-keypad",
.id = -1, .id = PLATFORM_DEVID_NONE,
.dev = { .properties = spitz_mkp_properties,
.platform_data = &spitz_mkp_pdata,
},
}; };
static void __init spitz_mkp_init(void) static void __init spitz_mkp_init(void)
{ {
platform_device_register(&spitz_mkp_device); struct platform_device *pd;
int err;
pd = platform_device_register_full(&spitz_mkp_info);
err = PTR_ERR_OR_ZERO(pd);
if (err)
pr_err("failed to create keypad device: %d\n", err);
} }
#else #else
static inline void spitz_mkp_init(void) {} static inline void spitz_mkp_init(void) {}
...@@ -419,45 +437,82 @@ static inline void spitz_mkp_init(void) {} ...@@ -419,45 +437,82 @@ static inline void spitz_mkp_init(void) {}
* GPIO keys * GPIO keys
******************************************************************************/ ******************************************************************************/
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
static struct gpio_keys_button spitz_gpio_keys[] = { static const struct software_node spitz_gpio_keys_node = {
{ .name = "spitz-gpio-keys",
.type = EV_PWR,
.code = KEY_SUSPEND,
.gpio = SPITZ_GPIO_ON_KEY,
.desc = "On Off",
.wakeup = 1,
},
/* Two buttons detecting the lid state */
{
.type = EV_SW,
.code = 0,
.gpio = SPITZ_GPIO_SWA,
.desc = "Display Down",
},
{
.type = EV_SW,
.code = 1,
.gpio = SPITZ_GPIO_SWB,
.desc = "Lid Closed",
},
}; };
static struct gpio_keys_platform_data spitz_gpio_keys_platform_data = { static const struct property_entry spitz_suspend_key_props[] = {
.buttons = spitz_gpio_keys, PROPERTY_ENTRY_U32("linux,input-type", EV_PWR),
.nbuttons = ARRAY_SIZE(spitz_gpio_keys), PROPERTY_ENTRY_U32("linux,code", KEY_SUSPEND),
PROPERTY_ENTRY_GPIO("gpios", &pxa2xx_gpiochip_node,
SPITZ_GPIO_ON_KEY, GPIO_ACTIVE_HIGH),
PROPERTY_ENTRY_STRING("label", "On Off"),
PROPERTY_ENTRY_BOOL("wakeup-source"),
{ }
}; };
static struct platform_device spitz_gpio_keys_device = { static const struct software_node spitz_suspend_key_node = {
.name = "gpio-keys", .parent = &spitz_gpio_keys_node,
.id = -1, .properties = spitz_suspend_key_props,
.dev = { };
.platform_data = &spitz_gpio_keys_platform_data,
}, static const struct property_entry spitz_sw1_props[] = {
PROPERTY_ENTRY_U32("linux,input-type", EV_SW),
PROPERTY_ENTRY_U32("linux,code", 0),
PROPERTY_ENTRY_GPIO("gpios", &pxa2xx_gpiochip_node,
SPITZ_GPIO_SWA, GPIO_ACTIVE_HIGH),
PROPERTY_ENTRY_STRING("label", "Display Down"),
{ }
};
static const struct software_node spitz_sw1_node = {
.parent = &spitz_gpio_keys_node,
.properties = spitz_sw1_props,
};
static const struct property_entry spitz_sw2_props[] = {
PROPERTY_ENTRY_U32("linux,input-type", EV_SW),
PROPERTY_ENTRY_U32("linux,code", 1),
PROPERTY_ENTRY_GPIO("gpios", &pxa2xx_gpiochip_node,
SPITZ_GPIO_SWB, GPIO_ACTIVE_HIGH),
PROPERTY_ENTRY_STRING("label", "Lid Closed"),
{ }
};
static const struct software_node spitz_sw2_node = {
.parent = &spitz_gpio_keys_node,
.properties = spitz_sw2_props,
};
static const struct software_node *spitz_gpio_keys_swnodes[] = {
&spitz_gpio_keys_node,
&spitz_suspend_key_node,
&spitz_sw1_node,
&spitz_sw2_node,
NULL
}; };
static void __init spitz_keys_init(void) static void __init spitz_keys_init(void)
{ {
platform_device_register(&spitz_gpio_keys_device); struct platform_device_info keys_info = {
.name = "gpio-keys",
.id = PLATFORM_DEVID_NONE,
};
struct platform_device *pd;
int err;
err = software_node_register_node_group(spitz_gpio_keys_swnodes);
if (err) {
pr_err("failed to register gpio-keys software nodes: %d\n", err);
return;
}
keys_info.fwnode = software_node_fwnode(&spitz_gpio_keys_node);
pd = platform_device_register_full(&keys_info);
err = PTR_ERR_OR_ZERO(pd);
if (err)
pr_err("failed to create gpio-keys device: %d\n", err);
} }
#else #else
static inline void spitz_keys_init(void) {} static inline void spitz_keys_init(void) {}
......
...@@ -498,6 +498,13 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, ...@@ -498,6 +498,13 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
struct input_event event; struct input_event event;
int retval = 0; int retval = 0;
/*
* Limit amount of data we inject into the input subsystem so that
* we do not hold evdev->mutex for too long. 4096 bytes corresponds
* to 170 input events.
*/
count = min(count, 4096);
if (count != 0 && count < input_event_size()) if (count != 0 && count < input_event_size())
return -EINVAL; return -EINVAL;
......
...@@ -2221,7 +2221,7 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev) ...@@ -2221,7 +2221,7 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
mt_slots = dev->mt->num_slots; mt_slots = dev->mt->num_slots;
} else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1;
mt_slots = clamp(mt_slots, 2, 32); mt_slots = clamp(mt_slots, 2, 32);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
mt_slots = 2; mt_slots = 2;
......
...@@ -132,7 +132,6 @@ static void adc_joystick_cleanup(void *data) ...@@ -132,7 +132,6 @@ static void adc_joystick_cleanup(void *data)
static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy) static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
{ {
struct adc_joystick_axis *axes = joy->axes; struct adc_joystick_axis *axes = joy->axes;
struct fwnode_handle *child;
s32 range[2], fuzz, flat; s32 range[2], fuzz, flat;
unsigned int num_axes; unsigned int num_axes;
int error, i; int error, i;
...@@ -149,31 +148,30 @@ static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy) ...@@ -149,31 +148,30 @@ static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
return -EINVAL; return -EINVAL;
} }
device_for_each_child_node(dev, child) { device_for_each_child_node_scoped(dev, child) {
error = fwnode_property_read_u32(child, "reg", &i); error = fwnode_property_read_u32(child, "reg", &i);
if (error) { if (error) {
dev_err(dev, "reg invalid or missing\n"); dev_err(dev, "reg invalid or missing\n");
goto err_fwnode_put; return error;
} }
if (i >= num_axes) { if (i >= num_axes) {
error = -EINVAL;
dev_err(dev, "No matching axis for reg %d\n", i); dev_err(dev, "No matching axis for reg %d\n", i);
goto err_fwnode_put; return -EINVAL;
} }
error = fwnode_property_read_u32(child, "linux,code", error = fwnode_property_read_u32(child, "linux,code",
&axes[i].code); &axes[i].code);
if (error) { if (error) {
dev_err(dev, "linux,code invalid or missing\n"); dev_err(dev, "linux,code invalid or missing\n");
goto err_fwnode_put; return error;
} }
error = fwnode_property_read_u32_array(child, "abs-range", error = fwnode_property_read_u32_array(child, "abs-range",
range, 2); range, 2);
if (error) { if (error) {
dev_err(dev, "abs-range invalid or missing\n"); dev_err(dev, "abs-range invalid or missing\n");
goto err_fwnode_put; return error;
} }
if (range[0] > range[1]) { if (range[0] > range[1]) {
...@@ -193,10 +191,6 @@ static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy) ...@@ -193,10 +191,6 @@ static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
} }
return 0; return 0;
err_fwnode_put:
fwnode_handle_put(child);
return error;
} }
......
...@@ -421,18 +421,6 @@ config KEYBOARD_MAX7359 ...@@ -421,18 +421,6 @@ config KEYBOARD_MAX7359
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 max7359_keypad. module will be called max7359_keypad.
config KEYBOARD_MCS
tristate "MELFAS MCS Touchkey"
depends on I2C
help
Say Y here if you have the MELFAS MCS5000/5080 touchkey controller
chip in your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mcs_touchkey.
config KEYBOARD_MPR121 config KEYBOARD_MPR121
tristate "Freescale MPR121 Touchkey" tristate "Freescale MPR121 Touchkey"
depends on I2C depends on I2C
...@@ -496,17 +484,6 @@ config KEYBOARD_NEWTON ...@@ -496,17 +484,6 @@ config KEYBOARD_NEWTON
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 newtonkbd. module will be called newtonkbd.
config KEYBOARD_NOMADIK
tristate "ST-Ericsson Nomadik SKE keyboard"
depends on (ARCH_NOMADIK || ARCH_U8500 || COMPILE_TEST)
select INPUT_MATRIXKMAP
help
Say Y here if you want to use a keypad provided on the SKE controller
used on the Ux500 and Nomadik platforms
To compile this driver as a module, choose M here: the
module will be called nmk-ske-keypad.
config KEYBOARD_NSPIRE config KEYBOARD_NSPIRE
tristate "TI-NSPIRE built-in keyboard" tristate "TI-NSPIRE built-in keyboard"
depends on ARCH_NSPIRE && OF depends on ARCH_NSPIRE && OF
......
...@@ -42,12 +42,10 @@ obj-$(CONFIG_KEYBOARD_LPC32XX) += lpc32xx-keys.o ...@@ -42,12 +42,10 @@ obj-$(CONFIG_KEYBOARD_LPC32XX) += lpc32xx-keys.o
obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o
obj-$(CONFIG_KEYBOARD_MT6779) += mt6779-keypad.o obj-$(CONFIG_KEYBOARD_MT6779) += mt6779-keypad.o
obj-$(CONFIG_KEYBOARD_MTK_PMIC) += mtk-pmic-keys.o obj-$(CONFIG_KEYBOARD_MTK_PMIC) += mtk-pmic-keys.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
obj-$(CONFIG_KEYBOARD_NSPIRE) += nspire-keypad.o obj-$(CONFIG_KEYBOARD_NSPIRE) += nspire-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
......
...@@ -66,7 +66,6 @@ static void adc_keys_poll(struct input_dev *input) ...@@ -66,7 +66,6 @@ static void adc_keys_poll(struct input_dev *input)
static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st) static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
{ {
struct adc_keys_button *map; struct adc_keys_button *map;
struct fwnode_handle *child;
int i; int i;
st->num_keys = device_get_child_node_count(dev); st->num_keys = device_get_child_node_count(dev);
...@@ -80,11 +79,10 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st) ...@@ -80,11 +79,10 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
return -ENOMEM; return -ENOMEM;
i = 0; i = 0;
device_for_each_child_node(dev, child) { device_for_each_child_node_scoped(dev, child) {
if (fwnode_property_read_u32(child, "press-threshold-microvolt", if (fwnode_property_read_u32(child, "press-threshold-microvolt",
&map[i].voltage)) { &map[i].voltage)) {
dev_err(dev, "Key with invalid or missing voltage\n"); dev_err(dev, "Key with invalid or missing voltage\n");
fwnode_handle_put(child);
return -EINVAL; return -EINVAL;
} }
map[i].voltage /= 1000; map[i].voltage /= 1000;
...@@ -92,7 +90,6 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st) ...@@ -92,7 +90,6 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
if (fwnode_property_read_u32(child, "linux,code", if (fwnode_property_read_u32(child, "linux,code",
&map[i].keycode)) { &map[i].keycode)) {
dev_err(dev, "Key with invalid or missing linux,code\n"); dev_err(dev, "Key with invalid or missing linux,code\n");
fwnode_handle_put(child);
return -EINVAL; return -EINVAL;
} }
......
...@@ -188,6 +188,7 @@ struct adp5588_kpad { ...@@ -188,6 +188,7 @@ struct adp5588_kpad {
u32 cols; u32 cols;
u32 unlock_keys[2]; u32 unlock_keys[2];
int nkeys_unlock; int nkeys_unlock;
bool gpio_only;
unsigned short keycode[ADP5588_KEYMAPSIZE]; unsigned short keycode[ADP5588_KEYMAPSIZE];
unsigned char gpiomap[ADP5588_MAXGPIO]; unsigned char gpiomap[ADP5588_MAXGPIO];
struct gpio_chip gc; struct gpio_chip gc;
...@@ -221,15 +222,13 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned int off) ...@@ -221,15 +222,13 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned int off)
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int val; int val;
mutex_lock(&kpad->gpio_lock); guard(mutex)(&kpad->gpio_lock);
if (kpad->dir[bank] & bit) if (kpad->dir[bank] & bit)
val = kpad->dat_out[bank]; val = kpad->dat_out[bank];
else else
val = adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank); val = adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank);
mutex_unlock(&kpad->gpio_lock);
return !!(val & bit); return !!(val & bit);
} }
...@@ -240,7 +239,7 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip, ...@@ -240,7 +239,7 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
mutex_lock(&kpad->gpio_lock); guard(mutex)(&kpad->gpio_lock);
if (val) if (val)
kpad->dat_out[bank] |= bit; kpad->dat_out[bank] |= bit;
...@@ -248,8 +247,6 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip, ...@@ -248,8 +247,6 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip,
kpad->dat_out[bank] &= ~bit; kpad->dat_out[bank] &= ~bit;
adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank, kpad->dat_out[bank]); adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank, kpad->dat_out[bank]);
mutex_unlock(&kpad->gpio_lock);
} }
static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off, static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off,
...@@ -259,7 +256,6 @@ static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off, ...@@ -259,7 +256,6 @@ static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off,
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
bool pull_disable; bool pull_disable;
int ret;
switch (pinconf_to_config_param(config)) { switch (pinconf_to_config_param(config)) {
case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_UP:
...@@ -272,19 +268,15 @@ static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off, ...@@ -272,19 +268,15 @@ static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off,
return -ENOTSUPP; return -ENOTSUPP;
} }
mutex_lock(&kpad->gpio_lock); guard(mutex)(&kpad->gpio_lock);
if (pull_disable) if (pull_disable)
kpad->pull_dis[bank] |= bit; kpad->pull_dis[bank] |= bit;
else else
kpad->pull_dis[bank] &= bit; kpad->pull_dis[bank] &= bit;
ret = adp5588_write(kpad->client, GPIO_PULL1 + bank, return adp5588_write(kpad->client, GPIO_PULL1 + bank,
kpad->pull_dis[bank]); kpad->pull_dis[bank]);
mutex_unlock(&kpad->gpio_lock);
return ret;
} }
static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned int off) static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned int off)
...@@ -292,16 +284,11 @@ static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned int off ...@@ -292,16 +284,11 @@ static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned int off
struct adp5588_kpad *kpad = gpiochip_get_data(chip); struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int ret;
mutex_lock(&kpad->gpio_lock); guard(mutex)(&kpad->gpio_lock);
kpad->dir[bank] &= ~bit; kpad->dir[bank] &= ~bit;
ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]); return adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
mutex_unlock(&kpad->gpio_lock);
return ret;
} }
static int adp5588_gpio_direction_output(struct gpio_chip *chip, static int adp5588_gpio_direction_output(struct gpio_chip *chip,
...@@ -310,9 +297,9 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip, ...@@ -310,9 +297,9 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
struct adp5588_kpad *kpad = gpiochip_get_data(chip); struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]); unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int ret; int error;
mutex_lock(&kpad->gpio_lock); guard(mutex)(&kpad->gpio_lock);
kpad->dir[bank] |= bit; kpad->dir[bank] |= bit;
...@@ -321,17 +308,16 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip, ...@@ -321,17 +308,16 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
else else
kpad->dat_out[bank] &= ~bit; kpad->dat_out[bank] &= ~bit;
ret = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank, error = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
kpad->dat_out[bank]); kpad->dat_out[bank]);
if (ret) if (error)
goto out_unlock; return error;
ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
out_unlock: error = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
mutex_unlock(&kpad->gpio_lock); if (error)
return error;
return ret; return 0;
} }
static int adp5588_build_gpiomap(struct adp5588_kpad *kpad) static int adp5588_build_gpiomap(struct adp5588_kpad *kpad)
...@@ -446,10 +432,17 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) ...@@ -446,10 +432,17 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)
kpad->gc.label = kpad->client->name; kpad->gc.label = kpad->client->name;
kpad->gc.owner = THIS_MODULE; kpad->gc.owner = THIS_MODULE;
girq = &kpad->gc.irq; if (device_property_present(dev, "interrupt-controller")) {
gpio_irq_chip_set_chip(girq, &adp5588_irq_chip); if (!kpad->client->irq) {
girq->handler = handle_bad_irq; dev_err(dev, "Unable to serve as interrupt controller without interrupt");
girq->threaded = true; return -EINVAL;
}
girq = &kpad->gc.irq;
gpio_irq_chip_set_chip(girq, &adp5588_irq_chip);
girq->handler = handle_bad_irq;
girq->threaded = true;
}
mutex_init(&kpad->gpio_lock); mutex_init(&kpad->gpio_lock);
...@@ -627,7 +620,7 @@ static int adp5588_setup(struct adp5588_kpad *kpad) ...@@ -627,7 +620,7 @@ static int adp5588_setup(struct adp5588_kpad *kpad)
for (i = 0; i < KEYP_MAX_EVENT; i++) { for (i = 0; i < KEYP_MAX_EVENT; i++) {
ret = adp5588_read(client, KEY_EVENTA); ret = adp5588_read(client, KEY_EVENTA);
if (ret) if (ret < 0)
return ret; return ret;
} }
...@@ -647,6 +640,18 @@ static int adp5588_fw_parse(struct adp5588_kpad *kpad) ...@@ -647,6 +640,18 @@ static int adp5588_fw_parse(struct adp5588_kpad *kpad)
struct i2c_client *client = kpad->client; struct i2c_client *client = kpad->client;
int ret, i; int ret, i;
/*
* Check if the device is to be operated purely in GPIO mode. To do
* so, check that no keypad rows or columns have been specified,
* since all GPINS should be configured as GPIO.
*/
if (!device_property_present(&client->dev, "keypad,num-rows") &&
!device_property_present(&client->dev, "keypad,num-columns")) {
/* If purely GPIO, skip keypad setup */
kpad->gpio_only = true;
return 0;
}
ret = matrix_keypad_parse_properties(&client->dev, &kpad->rows, ret = matrix_keypad_parse_properties(&client->dev, &kpad->rows,
&kpad->cols); &kpad->cols);
if (ret) if (ret)
...@@ -790,17 +795,19 @@ static int adp5588_probe(struct i2c_client *client) ...@@ -790,17 +795,19 @@ static int adp5588_probe(struct i2c_client *client)
if (error) if (error)
return error; return error;
error = devm_request_threaded_irq(&client->dev, client->irq, if (client->irq) {
adp5588_hard_irq, adp5588_thread_irq, error = devm_request_threaded_irq(&client->dev, client->irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, adp5588_hard_irq, adp5588_thread_irq,
client->dev.driver->name, kpad); IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
if (error) { client->dev.driver->name, kpad);
dev_err(&client->dev, "failed to request irq %d: %d\n", if (error) {
client->irq, error); dev_err(&client->dev, "failed to request irq %d: %d\n",
return error; client->irq, error);
return error;
}
} }
dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq); dev_info(&client->dev, "Rev.%d controller\n", revid);
return 0; return 0;
} }
......
...@@ -639,7 +639,7 @@ static void atkbd_event_work(struct work_struct *work) ...@@ -639,7 +639,7 @@ static void atkbd_event_work(struct work_struct *work)
{ {
struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work); struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work);
mutex_lock(&atkbd->mutex); guard(mutex)(&atkbd->mutex);
if (!atkbd->enabled) { if (!atkbd->enabled) {
/* /*
...@@ -657,8 +657,6 @@ static void atkbd_event_work(struct work_struct *work) ...@@ -657,8 +657,6 @@ static void atkbd_event_work(struct work_struct *work)
if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
atkbd_set_repeat_rate(atkbd); atkbd_set_repeat_rate(atkbd);
} }
mutex_unlock(&atkbd->mutex);
} }
/* /*
...@@ -1361,7 +1359,7 @@ static int atkbd_reconnect(struct serio *serio) ...@@ -1361,7 +1359,7 @@ static int atkbd_reconnect(struct serio *serio)
{ {
struct atkbd *atkbd = atkbd_from_serio(serio); struct atkbd *atkbd = atkbd_from_serio(serio);
struct serio_driver *drv = serio->drv; struct serio_driver *drv = serio->drv;
int retval = -1; int error;
if (!atkbd || !drv) { if (!atkbd || !drv) {
dev_dbg(&serio->dev, dev_dbg(&serio->dev,
...@@ -1369,16 +1367,17 @@ static int atkbd_reconnect(struct serio *serio) ...@@ -1369,16 +1367,17 @@ static int atkbd_reconnect(struct serio *serio)
return -1; return -1;
} }
mutex_lock(&atkbd->mutex); guard(mutex)(&atkbd->mutex);
atkbd_disable(atkbd); atkbd_disable(atkbd);
if (atkbd->write) { if (atkbd->write) {
if (atkbd_probe(atkbd)) error = atkbd_probe(atkbd);
goto out; if (error)
return error;
if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
goto out; return -EIO;
/* /*
* Restore LED state and repeat rate. While input core * Restore LED state and repeat rate. While input core
...@@ -1404,11 +1403,7 @@ static int atkbd_reconnect(struct serio *serio) ...@@ -1404,11 +1403,7 @@ static int atkbd_reconnect(struct serio *serio)
if (atkbd->write) if (atkbd->write)
atkbd_activate(atkbd); atkbd_activate(atkbd);
retval = 0; return 0;
out:
mutex_unlock(&atkbd->mutex);
return retval;
} }
static const struct serio_device_id atkbd_serio_ids[] = { static const struct serio_device_id atkbd_serio_ids[] = {
...@@ -1465,17 +1460,15 @@ static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t ...@@ -1465,17 +1460,15 @@ static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t
struct atkbd *atkbd = atkbd_from_serio(serio); struct atkbd *atkbd = atkbd_from_serio(serio);
int retval; int retval;
retval = mutex_lock_interruptible(&atkbd->mutex); scoped_guard(mutex_intr, &atkbd->mutex) {
if (retval) atkbd_disable(atkbd);
return retval; retval = handler(atkbd, buf, count);
atkbd_enable(atkbd);
atkbd_disable(atkbd); return retval;
retval = handler(atkbd, buf, count); }
atkbd_enable(atkbd);
mutex_unlock(&atkbd->mutex);
return retval; return -EINTR;
} }
static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf) static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
......
...@@ -245,23 +245,20 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, ...@@ -245,23 +245,20 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
{ {
int n_events = get_n_events_by_type(type); int n_events = get_n_events_by_type(type);
const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type); const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
unsigned long *bits;
ssize_t error; ssize_t error;
int i; int i;
bits = bitmap_alloc(n_events, GFP_KERNEL); unsigned long *bits __free(bitmap) = bitmap_alloc(n_events, GFP_KERNEL);
if (!bits) if (!bits)
return -ENOMEM; return -ENOMEM;
error = bitmap_parselist(buf, bits, n_events); error = bitmap_parselist(buf, bits, n_events);
if (error) if (error)
goto out; return error;
/* First validate */ /* First validate */
if (!bitmap_subset(bits, bitmap, n_events)) { if (!bitmap_subset(bits, bitmap, n_events))
error = -EINVAL; return -EINVAL;
goto out;
}
for (i = 0; i < ddata->pdata->nbuttons; i++) { for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i]; struct gpio_button_data *bdata = &ddata->data[i];
...@@ -271,12 +268,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, ...@@ -271,12 +268,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
if (test_bit(*bdata->code, bits) && if (test_bit(*bdata->code, bits) &&
!bdata->button->can_disable) { !bdata->button->can_disable) {
error = -EINVAL; return -EINVAL;
goto out;
} }
} }
mutex_lock(&ddata->disable_lock); guard(mutex)(&ddata->disable_lock);
for (i = 0; i < ddata->pdata->nbuttons; i++) { for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i]; struct gpio_button_data *bdata = &ddata->data[i];
...@@ -290,11 +286,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, ...@@ -290,11 +286,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
gpio_keys_enable_button(bdata); gpio_keys_enable_button(bdata);
} }
mutex_unlock(&ddata->disable_lock); return 0;
out:
bitmap_free(bits);
return error;
} }
#define ATTR_SHOW_FN(name, type, only_disabled) \ #define ATTR_SHOW_FN(name, type, only_disabled) \
...@@ -470,11 +462,10 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) ...@@ -470,11 +462,10 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
{ {
struct gpio_button_data *bdata = dev_id; struct gpio_button_data *bdata = dev_id;
struct input_dev *input = bdata->input; struct input_dev *input = bdata->input;
unsigned long flags;
BUG_ON(irq != bdata->irq); BUG_ON(irq != bdata->irq);
spin_lock_irqsave(&bdata->lock, flags); guard(spinlock_irqsave)(&bdata->lock);
if (!bdata->key_pressed) { if (!bdata->key_pressed) {
if (bdata->button->wakeup) if (bdata->button->wakeup)
...@@ -497,7 +488,6 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) ...@@ -497,7 +488,6 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
ms_to_ktime(bdata->release_delay), ms_to_ktime(bdata->release_delay),
HRTIMER_MODE_REL_HARD); HRTIMER_MODE_REL_HARD);
out: out:
spin_unlock_irqrestore(&bdata->lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -768,7 +758,6 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -768,7 +758,6 @@ 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;
int nbuttons, irq; int nbuttons, irq;
nbuttons = device_get_child_node_count(dev); nbuttons = device_get_child_node_count(dev);
...@@ -790,7 +779,7 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -790,7 +779,7 @@ 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_scoped(dev, child) {
if (is_of_node(child)) { if (is_of_node(child)) {
irq = of_irq_get_byname(to_of_node(child), "irq"); irq = of_irq_get_byname(to_of_node(child), "irq");
if (irq > 0) if (irq > 0)
...@@ -808,7 +797,6 @@ gpio_keys_get_devtree_pdata(struct device *dev) ...@@ -808,7 +797,6 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (fwnode_property_read_u32(child, "linux,code", if (fwnode_property_read_u32(child, "linux,code",
&button->code)) { &button->code)) {
dev_err(dev, "Button without keycode\n"); dev_err(dev, "Button without keycode\n");
fwnode_handle_put(child);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
...@@ -1064,10 +1052,10 @@ static int gpio_keys_suspend(struct device *dev) ...@@ -1064,10 +1052,10 @@ static int gpio_keys_suspend(struct device *dev)
if (error) if (error)
return error; return error;
} else { } else {
mutex_lock(&input->mutex); guard(mutex)(&input->mutex);
if (input_device_enabled(input)) if (input_device_enabled(input))
gpio_keys_close(input); gpio_keys_close(input);
mutex_unlock(&input->mutex);
} }
return 0; return 0;
...@@ -1077,20 +1065,20 @@ static int gpio_keys_resume(struct device *dev) ...@@ -1077,20 +1065,20 @@ static int gpio_keys_resume(struct device *dev)
{ {
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input; struct input_dev *input = ddata->input;
int error = 0; int error;
if (device_may_wakeup(dev)) { if (device_may_wakeup(dev)) {
gpio_keys_disable_wakeup(ddata); gpio_keys_disable_wakeup(ddata);
} else { } else {
mutex_lock(&input->mutex); guard(mutex)(&input->mutex);
if (input_device_enabled(input))
if (input_device_enabled(input)) {
error = gpio_keys_open(input); error = gpio_keys_open(input);
mutex_unlock(&input->mutex); if (error)
return error;
}
} }
if (error)
return error;
gpio_keys_report_state(ddata); gpio_keys_report_state(ddata);
return 0; return 0;
} }
......
...@@ -144,7 +144,6 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev) ...@@ -144,7 +144,6 @@ gpio_keys_polled_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;
int nbuttons; int nbuttons;
nbuttons = device_get_child_node_count(dev); nbuttons = device_get_child_node_count(dev);
...@@ -166,11 +165,10 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev) ...@@ -166,11 +165,10 @@ gpio_keys_polled_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_scoped(dev, child) {
if (fwnode_property_read_u32(child, "linux,code", if (fwnode_property_read_u32(child, "linux,code",
&button->code)) { &button->code)) {
dev_err(dev, "button without keycode\n"); dev_err(dev, "button without keycode\n");
fwnode_handle_put(child);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
......
...@@ -45,7 +45,6 @@ struct iqs62x_keys_private { ...@@ -45,7 +45,6 @@ struct iqs62x_keys_private {
static int iqs62x_keys_parse_prop(struct platform_device *pdev, static int iqs62x_keys_parse_prop(struct platform_device *pdev,
struct iqs62x_keys_private *iqs62x_keys) struct iqs62x_keys_private *iqs62x_keys)
{ {
struct fwnode_handle *child;
unsigned int val; unsigned int val;
int ret, i; int ret, i;
...@@ -68,7 +67,8 @@ static int iqs62x_keys_parse_prop(struct platform_device *pdev, ...@@ -68,7 +67,8 @@ static int iqs62x_keys_parse_prop(struct platform_device *pdev,
} }
for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) { for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) {
child = device_get_named_child_node(&pdev->dev, struct fwnode_handle *child __free(fwnode_handle) =
device_get_named_child_node(&pdev->dev,
iqs62x_switch_names[i]); iqs62x_switch_names[i]);
if (!child) if (!child)
continue; continue;
...@@ -77,7 +77,6 @@ static int iqs62x_keys_parse_prop(struct platform_device *pdev, ...@@ -77,7 +77,6 @@ static int iqs62x_keys_parse_prop(struct platform_device *pdev,
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to read switch code: %d\n", dev_err(&pdev->dev, "Failed to read switch code: %d\n",
ret); ret);
fwnode_handle_put(child);
return ret; return ret;
} }
iqs62x_keys->switches[i].code = val; iqs62x_keys->switches[i].code = val;
...@@ -91,8 +90,6 @@ static int iqs62x_keys_parse_prop(struct platform_device *pdev, ...@@ -91,8 +90,6 @@ static int iqs62x_keys_parse_prop(struct platform_device *pdev,
iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ? iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ?
IQS62X_EVENT_HALL_N_T : IQS62X_EVENT_HALL_N_T :
IQS62X_EVENT_HALL_S_T); IQS62X_EVENT_HALL_S_T);
fwnode_handle_put(child);
} }
return 0; return 0;
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Touchkey driver for MELFAS MCS5000/5080 controller
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Author: HeungJun Kim <riverful.kim@samsung.com>
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/platform_data/mcs.h>
#include <linux/pm.h>
/* MCS5000 Touchkey */
#define MCS5000_TOUCHKEY_STATUS 0x04
#define MCS5000_TOUCHKEY_STATUS_PRESS 7
#define MCS5000_TOUCHKEY_FW 0x0a
#define MCS5000_TOUCHKEY_BASE_VAL 0x61
/* MCS5080 Touchkey */
#define MCS5080_TOUCHKEY_STATUS 0x00
#define MCS5080_TOUCHKEY_STATUS_PRESS 3
#define MCS5080_TOUCHKEY_FW 0x01
#define MCS5080_TOUCHKEY_BASE_VAL 0x1
enum mcs_touchkey_type {
MCS5000_TOUCHKEY,
MCS5080_TOUCHKEY,
};
struct mcs_touchkey_chip {
unsigned int status_reg;
unsigned int pressbit;
unsigned int press_invert;
unsigned int baseval;
};
struct mcs_touchkey_data {
void (*poweron)(bool);
struct i2c_client *client;
struct input_dev *input_dev;
struct mcs_touchkey_chip chip;
unsigned int key_code;
unsigned int key_val;
unsigned short keycodes[];
};
static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id)
{
struct mcs_touchkey_data *data = dev_id;
struct mcs_touchkey_chip *chip = &data->chip;
struct i2c_client *client = data->client;
struct input_dev *input = data->input_dev;
unsigned int key_val;
unsigned int pressed;
int val;
val = i2c_smbus_read_byte_data(client, chip->status_reg);
if (val < 0) {
dev_err(&client->dev, "i2c read error [%d]\n", val);
goto out;
}
pressed = (val & (1 << chip->pressbit)) >> chip->pressbit;
if (chip->press_invert)
pressed ^= chip->press_invert;
/* key_val is 0 when released, so we should use key_val of press. */
if (pressed) {
key_val = val & (0xff >> (8 - chip->pressbit));
if (!key_val)
goto out;
key_val -= chip->baseval;
data->key_code = data->keycodes[key_val];
data->key_val = key_val;
}
input_event(input, EV_MSC, MSC_SCAN, data->key_val);
input_report_key(input, data->key_code, pressed);
input_sync(input);
dev_dbg(&client->dev, "key %d %d %s\n", data->key_val, data->key_code,
pressed ? "pressed" : "released");
out:
return IRQ_HANDLED;
}
static void mcs_touchkey_poweroff(void *data)
{
struct mcs_touchkey_data *touchkey = data;
touchkey->poweron(false);
}
static int mcs_touchkey_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct mcs_platform_data *pdata;
struct mcs_touchkey_data *data;
struct input_dev *input_dev;
unsigned int fw_reg;
int fw_ver;
int error;
int i;
pdata = dev_get_platdata(&client->dev);
if (!pdata) {
dev_err(&client->dev, "no platform data defined\n");
return -EINVAL;
}
data = devm_kzalloc(&client->dev,
struct_size(data, keycodes, pdata->key_maxval + 1),
GFP_KERNEL);
if (!data)
return -ENOMEM;
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev) {
dev_err(&client->dev, "Failed to allocate input device\n");
return -ENOMEM;
}
data->client = client;
data->input_dev = input_dev;
if (id->driver_data == MCS5000_TOUCHKEY) {
data->chip.status_reg = MCS5000_TOUCHKEY_STATUS;
data->chip.pressbit = MCS5000_TOUCHKEY_STATUS_PRESS;
data->chip.baseval = MCS5000_TOUCHKEY_BASE_VAL;
fw_reg = MCS5000_TOUCHKEY_FW;
} else {
data->chip.status_reg = MCS5080_TOUCHKEY_STATUS;
data->chip.pressbit = MCS5080_TOUCHKEY_STATUS_PRESS;
data->chip.press_invert = 1;
data->chip.baseval = MCS5080_TOUCHKEY_BASE_VAL;
fw_reg = MCS5080_TOUCHKEY_FW;
}
fw_ver = i2c_smbus_read_byte_data(client, fw_reg);
if (fw_ver < 0) {
dev_err(&client->dev, "i2c read error[%d]\n", fw_ver);
return fw_ver;
}
dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
input_dev->name = "MELFAS MCS Touchkey";
input_dev->id.bustype = BUS_I2C;
input_dev->evbit[0] = BIT_MASK(EV_KEY);
if (!pdata->no_autorepeat)
input_dev->evbit[0] |= BIT_MASK(EV_REP);
input_dev->keycode = data->keycodes;
input_dev->keycodesize = sizeof(data->keycodes[0]);
input_dev->keycodemax = pdata->key_maxval + 1;
for (i = 0; i < pdata->keymap_size; i++) {
unsigned int val = MCS_KEY_VAL(pdata->keymap[i]);
unsigned int code = MCS_KEY_CODE(pdata->keymap[i]);
data->keycodes[val] = code;
__set_bit(code, input_dev->keybit);
}
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, data);
if (pdata->cfg_pin)
pdata->cfg_pin();
if (pdata->poweron) {
data->poweron = pdata->poweron;
data->poweron(true);
error = devm_add_action_or_reset(&client->dev,
mcs_touchkey_poweroff, data);
if (error)
return error;
}
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, mcs_touchkey_interrupt,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->dev.driver->name, data);
if (error) {
dev_err(&client->dev, "Failed to register interrupt\n");
return error;
}
error = input_register_device(input_dev);
if (error)
return error;
i2c_set_clientdata(client, data);
return 0;
}
static void mcs_touchkey_shutdown(struct i2c_client *client)
{
struct mcs_touchkey_data *data = i2c_get_clientdata(client);
if (data->poweron)
data->poweron(false);
}
static int mcs_touchkey_suspend(struct device *dev)
{
struct mcs_touchkey_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
/* Disable the work */
disable_irq(client->irq);
/* Finally turn off the power */
if (data->poweron)
data->poweron(false);
return 0;
}
static int mcs_touchkey_resume(struct device *dev)
{
struct mcs_touchkey_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
/* Enable the device first */
if (data->poweron)
data->poweron(true);
/* Enable irq again */
enable_irq(client->irq);
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(mcs_touchkey_pm_ops,
mcs_touchkey_suspend, mcs_touchkey_resume);
static const struct i2c_device_id mcs_touchkey_id[] = {
{ "mcs5000_touchkey", MCS5000_TOUCHKEY },
{ "mcs5080_touchkey", MCS5080_TOUCHKEY },
{ }
};
MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id);
static struct i2c_driver mcs_touchkey_driver = {
.driver = {
.name = "mcs_touchkey",
.pm = pm_sleep_ptr(&mcs_touchkey_pm_ops),
},
.probe = mcs_touchkey_probe,
.shutdown = mcs_touchkey_shutdown,
.id_table = mcs_touchkey_id,
};
module_i2c_driver(mcs_touchkey_driver);
/* Module information */
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
MODULE_DESCRIPTION("Touchkey driver for MELFAS MCS5000/5080 controller");
MODULE_LICENSE("GPL");
...@@ -92,11 +92,6 @@ static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id) ...@@ -92,11 +92,6 @@ static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void mt6779_keypad_clk_disable(void *data)
{
clk_disable_unprepare(data);
}
static void mt6779_keypad_calc_row_col_single(unsigned int key, static void mt6779_keypad_calc_row_col_single(unsigned int key,
unsigned int *row, unsigned int *row,
unsigned int *col) unsigned int *col)
...@@ -213,21 +208,10 @@ static int mt6779_keypad_pdrv_probe(struct platform_device *pdev) ...@@ -213,21 +208,10 @@ static int mt6779_keypad_pdrv_probe(struct platform_device *pdev)
regmap_update_bits(keypad->regmap, MTK_KPD_SEL, MTK_KPD_SEL_COL, regmap_update_bits(keypad->regmap, MTK_KPD_SEL, MTK_KPD_SEL_COL,
MTK_KPD_SEL_COLMASK(keypad->n_cols)); MTK_KPD_SEL_COLMASK(keypad->n_cols));
keypad->clk = devm_clk_get(&pdev->dev, "kpd"); keypad->clk = devm_clk_get_enabled(&pdev->dev, "kpd");
if (IS_ERR(keypad->clk)) if (IS_ERR(keypad->clk))
return PTR_ERR(keypad->clk); return PTR_ERR(keypad->clk);
error = clk_prepare_enable(keypad->clk);
if (error) {
dev_err(&pdev->dev, "cannot prepare/enable keypad clock\n");
return error;
}
error = devm_add_action_or_reset(&pdev->dev, mt6779_keypad_clk_disable,
keypad->clk);
if (error)
return error;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0)
return irq; return irq;
...@@ -260,6 +244,7 @@ static const struct of_device_id mt6779_keypad_of_match[] = { ...@@ -260,6 +244,7 @@ static const struct of_device_id mt6779_keypad_of_match[] = {
{ .compatible = "mediatek,mt6873-keypad" }, { .compatible = "mediatek,mt6873-keypad" },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, mt6779_keypad_of_match);
static struct platform_driver mt6779_keypad_pdrv = { static struct platform_driver mt6779_keypad_pdrv = {
.probe = mt6779_keypad_pdrv_probe, .probe = mt6779_keypad_pdrv_probe,
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
* Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
*
* Keypad controller driver for the SKE (Scroll Key Encoder) module used in
* the Nomadik 8815 and Ux500 platforms.
*/
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_data/keypad-nomadik-ske.h>
/* SKE_CR bits */
#define SKE_KPMLT (0x1 << 6)
#define SKE_KPCN (0x7 << 3)
#define SKE_KPASEN (0x1 << 2)
#define SKE_KPASON (0x1 << 7)
/* SKE_IMSC bits */
#define SKE_KPIMA (0x1 << 2)
/* SKE_ICR bits */
#define SKE_KPICS (0x1 << 3)
#define SKE_KPICA (0x1 << 2)
/* SKE_RIS bits */
#define SKE_KPRISA (0x1 << 2)
#define SKE_KEYPAD_ROW_SHIFT 3
#define SKE_KPD_NUM_ROWS 8
#define SKE_KPD_NUM_COLS 8
/* keypad auto scan registers */
#define SKE_ASR0 0x20
#define SKE_ASR1 0x24
#define SKE_ASR2 0x28
#define SKE_ASR3 0x2C
#define SKE_NUM_ASRX_REGISTERS (4)
#define KEY_PRESSED_DELAY 10
/**
* struct ske_keypad - data structure used by keypad driver
* @irq: irq no
* @reg_base: ske registers base address
* @input: pointer to input device object
* @board: keypad platform device
* @keymap: matrix scan code table for keycodes
* @clk: clock structure pointer
* @pclk: clock structure pointer
* @ske_keypad_lock: spinlock protecting the keypad read/writes
*/
struct ske_keypad {
int irq;
void __iomem *reg_base;
struct input_dev *input;
const struct ske_keypad_platform_data *board;
unsigned short keymap[SKE_KPD_NUM_ROWS * SKE_KPD_NUM_COLS];
struct clk *clk;
struct clk *pclk;
spinlock_t ske_keypad_lock;
};
static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr,
u8 mask, u8 data)
{
u32 ret;
spin_lock(&keypad->ske_keypad_lock);
ret = readl(keypad->reg_base + addr);
ret &= ~mask;
ret |= data;
writel(ret, keypad->reg_base + addr);
spin_unlock(&keypad->ske_keypad_lock);
}
/*
* ske_keypad_chip_init: init keypad controller configuration
*
* Enable Multi key press detection, auto scan mode
*/
static int __init ske_keypad_chip_init(struct ske_keypad *keypad)
{
u32 value;
int timeout = keypad->board->debounce_ms;
/* check SKE_RIS to be 0 */
while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--)
cpu_relax();
if (timeout == -1)
return -EINVAL;
/*
* set debounce value
* keypad dbounce is configured in DBCR[15:8]
* dbounce value in steps of 32/32.768 ms
*/
spin_lock(&keypad->ske_keypad_lock);
value = readl(keypad->reg_base + SKE_DBCR);
value = value & 0xff;
value |= ((keypad->board->debounce_ms * 32000)/32768) << 8;
writel(value, keypad->reg_base + SKE_DBCR);
spin_unlock(&keypad->ske_keypad_lock);
/* enable multi key detection */
ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPMLT);
/*
* set up the number of columns
* KPCN[5:3] defines no. of keypad columns to be auto scanned
*/
value = (keypad->board->kcol - 1) << 3;
ske_keypad_set_bits(keypad, SKE_CR, SKE_KPCN, value);
/* clear keypad interrupt for auto(and pending SW) scans */
ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA | SKE_KPICS);
/* un-mask keypad interrupts */
ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
/* enable automatic scan */
ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPASEN);
return 0;
}
static void ske_keypad_report(struct ske_keypad *keypad, u8 status, int col)
{
int row = 0, code, pos;
struct input_dev *input = keypad->input;
u32 ske_ris;
int key_pressed;
int num_of_rows;
/* find out the row */
num_of_rows = hweight8(status);
do {
pos = __ffs(status);
row = pos;
status &= ~(1 << pos);
code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT);
ske_ris = readl(keypad->reg_base + SKE_RIS);
key_pressed = ske_ris & SKE_KPRISA;
input_event(input, EV_MSC, MSC_SCAN, code);
input_report_key(input, keypad->keymap[code], key_pressed);
input_sync(input);
num_of_rows--;
} while (num_of_rows);
}
static void ske_keypad_read_data(struct ske_keypad *keypad)
{
u8 status;
int col = 0;
int ske_asr, i;
/*
* Read the auto scan registers
*
* Each SKE_ASRx (x=0 to x=3) contains two row values.
* lower byte contains row value for column 2*x,
* upper byte contains row value for column 2*x + 1
*/
for (i = 0; i < SKE_NUM_ASRX_REGISTERS; i++) {
ske_asr = readl(keypad->reg_base + SKE_ASR0 + (4 * i));
if (!ske_asr)
continue;
/* now that ASRx is zero, find out the coloumn x and row y */
status = ske_asr & 0xff;
if (status) {
col = i * 2;
ske_keypad_report(keypad, status, col);
}
status = (ske_asr & 0xff00) >> 8;
if (status) {
col = (i * 2) + 1;
ske_keypad_report(keypad, status, col);
}
}
}
static irqreturn_t ske_keypad_irq(int irq, void *dev_id)
{
struct ske_keypad *keypad = dev_id;
int timeout = keypad->board->debounce_ms;
/* disable auto scan interrupt; mask the interrupt generated */
ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA);
while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --timeout)
cpu_relax();
/* SKEx registers are stable and can be read */
ske_keypad_read_data(keypad);
/* wait until raw interrupt is clear */
while ((readl(keypad->reg_base + SKE_RIS)) && --timeout)
msleep(KEY_PRESSED_DELAY);
/* enable auto scan interrupts */
ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
return IRQ_HANDLED;
}
static void ske_keypad_board_exit(void *data)
{
struct ske_keypad *keypad = data;
keypad->board->exit();
}
static int __init ske_keypad_probe(struct platform_device *pdev)
{
const struct ske_keypad_platform_data *plat =
dev_get_platdata(&pdev->dev);
struct device *dev = &pdev->dev;
struct ske_keypad *keypad;
struct input_dev *input;
int irq;
int error;
if (!plat) {
dev_err(&pdev->dev, "invalid keypad platform data\n");
return -EINVAL;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
keypad = devm_kzalloc(dev, sizeof(struct ske_keypad),
GFP_KERNEL);
input = devm_input_allocate_device(dev);
if (!keypad || !input) {
dev_err(&pdev->dev, "failed to allocate keypad memory\n");
return -ENOMEM;
}
keypad->irq = irq;
keypad->board = plat;
keypad->input = input;
spin_lock_init(&keypad->ske_keypad_lock);
keypad->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(keypad->reg_base))
return PTR_ERR(keypad->reg_base);
keypad->pclk = devm_clk_get_enabled(dev, "apb_pclk");
if (IS_ERR(keypad->pclk)) {
dev_err(&pdev->dev, "failed to get pclk\n");
return PTR_ERR(keypad->pclk);
}
keypad->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(keypad->clk)) {
dev_err(&pdev->dev, "failed to get clk\n");
return PTR_ERR(keypad->clk);
}
input->id.bustype = BUS_HOST;
input->name = "ux500-ske-keypad";
input->dev.parent = &pdev->dev;
error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
SKE_KPD_NUM_ROWS, SKE_KPD_NUM_COLS,
keypad->keymap, input);
if (error) {
dev_err(&pdev->dev, "Failed to build keymap\n");
return error;
}
input_set_capability(input, EV_MSC, MSC_SCAN);
if (!plat->no_autorepeat)
__set_bit(EV_REP, input->evbit);
/* go through board initialization helpers */
if (keypad->board->init)
keypad->board->init();
if (keypad->board->exit) {
error = devm_add_action_or_reset(dev, ske_keypad_board_exit,
keypad);
if (error)
return error;
}
error = ske_keypad_chip_init(keypad);
if (error) {
dev_err(&pdev->dev, "unable to init keypad hardware\n");
return error;
}
error = devm_request_threaded_irq(dev, keypad->irq,
NULL, ske_keypad_irq,
IRQF_ONESHOT, "ske-keypad", keypad);
if (error) {
dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq);
return error;
}
error = input_register_device(input);
if (error) {
dev_err(&pdev->dev,
"unable to register input device: %d\n", error);
return error;
}
if (plat->wakeup_enable)
device_init_wakeup(&pdev->dev, true);
platform_set_drvdata(pdev, keypad);
return 0;
}
static int ske_keypad_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ske_keypad *keypad = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
if (device_may_wakeup(dev))
enable_irq_wake(irq);
else
ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
return 0;
}
static int ske_keypad_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct ske_keypad *keypad = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
if (device_may_wakeup(dev))
disable_irq_wake(irq);
else
ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(ske_keypad_dev_pm_ops,
ske_keypad_suspend, ske_keypad_resume);
static struct platform_driver ske_keypad_driver = {
.driver = {
.name = "nmk-ske-keypad",
.pm = pm_sleep_ptr(&ske_keypad_dev_pm_ops),
},
};
module_platform_driver_probe(ske_keypad_driver, ske_keypad_probe);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>");
MODULE_DESCRIPTION("Nomadik Scroll-Key-Encoder Keypad Driver");
MODULE_ALIAS("platform:nomadik-ske-keypad");
...@@ -346,35 +346,34 @@ static int qt1050_apply_fw_data(struct qt1050_priv *ts) ...@@ -346,35 +346,34 @@ static int qt1050_apply_fw_data(struct qt1050_priv *ts)
static int qt1050_parse_fw(struct qt1050_priv *ts) static int qt1050_parse_fw(struct qt1050_priv *ts)
{ {
struct device *dev = &ts->client->dev; struct device *dev = &ts->client->dev;
struct fwnode_handle *child;
int nbuttons; int nbuttons;
nbuttons = device_get_child_node_count(dev); nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0 || nbuttons > QT1050_MAX_KEYS) if (nbuttons == 0 || nbuttons > QT1050_MAX_KEYS)
return -ENODEV; return -ENODEV;
device_for_each_child_node(dev, child) { device_for_each_child_node_scoped(dev, child) {
struct qt1050_key button; struct qt1050_key button;
/* Required properties */ /* Required properties */
if (fwnode_property_read_u32(child, "linux,code", if (fwnode_property_read_u32(child, "linux,code",
&button.keycode)) { &button.keycode)) {
dev_err(dev, "Button without keycode\n"); dev_err(dev, "Button without keycode\n");
goto err; return -EINVAL;
} }
if (button.keycode >= KEY_MAX) { if (button.keycode >= KEY_MAX) {
dev_err(dev, "Invalid keycode 0x%x\n", dev_err(dev, "Invalid keycode 0x%x\n",
button.keycode); button.keycode);
goto err; return -EINVAL;
} }
if (fwnode_property_read_u32(child, "reg", if (fwnode_property_read_u32(child, "reg",
&button.num)) { &button.num)) {
dev_err(dev, "Button without pad number\n"); dev_err(dev, "Button without pad number\n");
goto err; return -EINVAL;
} }
if (button.num < 0 || button.num > QT1050_MAX_KEYS - 1) if (button.num < 0 || button.num > QT1050_MAX_KEYS - 1)
goto err; return -EINVAL;
ts->reg_keys |= BIT(button.num); ts->reg_keys |= BIT(button.num);
...@@ -424,10 +423,6 @@ static int qt1050_parse_fw(struct qt1050_priv *ts) ...@@ -424,10 +423,6 @@ static int qt1050_parse_fw(struct qt1050_priv *ts)
} }
return 0; return 0;
err:
fwnode_handle_put(child);
return -EINVAL;
} }
static int qt1050_probe(struct i2c_client *client) static int qt1050_probe(struct i2c_client *client)
......
...@@ -100,11 +100,6 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id) ...@@ -100,11 +100,6 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void imx_snvs_pwrkey_disable_clk(void *data)
{
clk_disable_unprepare(data);
}
static void imx_snvs_pwrkey_act(void *pdata) static void imx_snvs_pwrkey_act(void *pdata)
{ {
struct pwrkey_drv_data *pd = pdata; struct pwrkey_drv_data *pd = pdata;
...@@ -141,28 +136,12 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) ...@@ -141,28 +136,12 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n"); dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
} }
clk = devm_clk_get_optional(&pdev->dev, NULL); clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
dev_err(&pdev->dev, "Failed to get snvs clock (%pe)\n", clk); dev_err(&pdev->dev, "Failed to get snvs clock (%pe)\n", clk);
return PTR_ERR(clk); return PTR_ERR(clk);
} }
error = clk_prepare_enable(clk);
if (error) {
dev_err(&pdev->dev, "Failed to enable snvs clock (%pe)\n",
ERR_PTR(error));
return error;
}
error = devm_add_action_or_reset(&pdev->dev,
imx_snvs_pwrkey_disable_clk, clk);
if (error) {
dev_err(&pdev->dev,
"Failed to register clock cleanup handler (%pe)\n",
ERR_PTR(error));
return error;
}
pdata->wakeup = of_property_read_bool(np, "wakeup-source"); pdata->wakeup = of_property_read_bool(np, "wakeup-source");
pdata->irq = platform_get_irq(pdev, 0); pdata->irq = platform_get_irq(pdev, 0);
...@@ -204,7 +183,6 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) ...@@ -204,7 +183,6 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
error = devm_request_irq(&pdev->dev, pdata->irq, error = devm_request_irq(&pdev->dev, pdata->irq,
imx_snvs_pwrkey_interrupt, imx_snvs_pwrkey_interrupt,
0, pdev->name, pdev); 0, pdev->name, pdev);
if (error) { if (error) {
dev_err(&pdev->dev, "interrupt not available.\n"); dev_err(&pdev->dev, "interrupt not available.\n");
return error; return error;
......
...@@ -222,7 +222,7 @@ static int spear_kbd_probe(struct platform_device *pdev) ...@@ -222,7 +222,7 @@ static int spear_kbd_probe(struct platform_device *pdev)
if (IS_ERR(kbd->io_base)) if (IS_ERR(kbd->io_base))
return PTR_ERR(kbd->io_base); return PTR_ERR(kbd->io_base);
kbd->clk = devm_clk_get(&pdev->dev, NULL); kbd->clk = devm_clk_get_prepared(&pdev->dev, NULL);
if (IS_ERR(kbd->clk)) if (IS_ERR(kbd->clk))
return PTR_ERR(kbd->clk); return PTR_ERR(kbd->clk);
...@@ -255,14 +255,9 @@ static int spear_kbd_probe(struct platform_device *pdev) ...@@ -255,14 +255,9 @@ static int spear_kbd_probe(struct platform_device *pdev)
return error; return error;
} }
error = clk_prepare(kbd->clk);
if (error)
return error;
error = input_register_device(input_dev); error = input_register_device(input_dev);
if (error) { if (error) {
dev_err(&pdev->dev, "Unable to register keyboard device\n"); dev_err(&pdev->dev, "Unable to register keyboard device\n");
clk_unprepare(kbd->clk);
return error; return error;
} }
...@@ -272,14 +267,6 @@ static int spear_kbd_probe(struct platform_device *pdev) ...@@ -272,14 +267,6 @@ static int spear_kbd_probe(struct platform_device *pdev)
return 0; return 0;
} }
static void spear_kbd_remove(struct platform_device *pdev)
{
struct spear_kbd *kbd = platform_get_drvdata(pdev);
input_unregister_device(kbd->input);
clk_unprepare(kbd->clk);
}
static int spear_kbd_suspend(struct device *dev) static int spear_kbd_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
...@@ -373,7 +360,6 @@ MODULE_DEVICE_TABLE(of, spear_kbd_id_table); ...@@ -373,7 +360,6 @@ MODULE_DEVICE_TABLE(of, spear_kbd_id_table);
static struct platform_driver spear_kbd_driver = { static struct platform_driver spear_kbd_driver = {
.probe = spear_kbd_probe, .probe = spear_kbd_probe,
.remove_new = spear_kbd_remove,
.driver = { .driver = {
.name = "keyboard", .name = "keyboard",
.pm = pm_sleep_ptr(&spear_kbd_pm_ops), .pm = pm_sleep_ptr(&spear_kbd_pm_ops),
......
...@@ -325,7 +325,6 @@ tc3589x_keypad_of_probe(struct device *dev) ...@@ -325,7 +325,6 @@ tc3589x_keypad_of_probe(struct device *dev)
struct tc3589x_keypad_platform_data *plat; struct tc3589x_keypad_platform_data *plat;
u32 cols, rows; u32 cols, rows;
u32 debounce_ms; u32 debounce_ms;
int proplen;
if (!np) if (!np)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
...@@ -346,7 +345,7 @@ tc3589x_keypad_of_probe(struct device *dev) ...@@ -346,7 +345,7 @@ tc3589x_keypad_of_probe(struct device *dev)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
if (!of_get_property(np, "linux,keymap", &proplen)) { if (!of_property_present(np, "linux,keymap")) {
dev_err(dev, "property linux,keymap not found\n"); dev_err(dev, "property linux,keymap not found\n");
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
......
...@@ -241,11 +241,10 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable) ...@@ -241,11 +241,10 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
static void tegra_kbc_keypress_timer(struct timer_list *t) static void tegra_kbc_keypress_timer(struct timer_list *t)
{ {
struct tegra_kbc *kbc = from_timer(kbc, t, timer); struct tegra_kbc *kbc = from_timer(kbc, t, timer);
unsigned long flags;
u32 val; u32 val;
unsigned int i; unsigned int i;
spin_lock_irqsave(&kbc->lock, flags); guard(spinlock_irqsave)(&kbc->lock);
val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf; val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf;
if (val) { if (val) {
...@@ -270,17 +269,14 @@ static void tegra_kbc_keypress_timer(struct timer_list *t) ...@@ -270,17 +269,14 @@ static void tegra_kbc_keypress_timer(struct timer_list *t)
/* All keys are released so enable the keypress interrupt */ /* All keys are released so enable the keypress interrupt */
tegra_kbc_set_fifo_interrupt(kbc, true); tegra_kbc_set_fifo_interrupt(kbc, true);
} }
spin_unlock_irqrestore(&kbc->lock, flags);
} }
static irqreturn_t tegra_kbc_isr(int irq, void *args) static irqreturn_t tegra_kbc_isr(int irq, void *args)
{ {
struct tegra_kbc *kbc = args; struct tegra_kbc *kbc = args;
unsigned long flags;
u32 val; u32 val;
spin_lock_irqsave(&kbc->lock, flags); guard(spinlock_irqsave)(&kbc->lock);
/* /*
* Quickly bail out & reenable interrupts if the fifo threshold * Quickly bail out & reenable interrupts if the fifo threshold
...@@ -301,8 +297,6 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args) ...@@ -301,8 +297,6 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args)
kbc->keypress_caused_wake = true; kbc->keypress_caused_wake = true;
} }
spin_unlock_irqrestore(&kbc->lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -413,14 +407,13 @@ static int tegra_kbc_start(struct tegra_kbc *kbc) ...@@ -413,14 +407,13 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
static void tegra_kbc_stop(struct tegra_kbc *kbc) static void tegra_kbc_stop(struct tegra_kbc *kbc)
{ {
unsigned long flags;
u32 val; u32 val;
spin_lock_irqsave(&kbc->lock, flags); scoped_guard(spinlock_irqsave, &kbc->lock) {
val = readl(kbc->mmio + KBC_CONTROL_0); val = readl(kbc->mmio + KBC_CONTROL_0);
val &= ~1; val &= ~1;
writel(val, kbc->mmio + KBC_CONTROL_0); writel(val, kbc->mmio + KBC_CONTROL_0);
spin_unlock_irqrestore(&kbc->lock, flags); }
disable_irq(kbc->irq); disable_irq(kbc->irq);
del_timer_sync(&kbc->timer); del_timer_sync(&kbc->timer);
...@@ -491,12 +484,10 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) ...@@ -491,12 +484,10 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
struct device_node *np = kbc->dev->of_node; struct device_node *np = kbc->dev->of_node;
u32 prop; u32 prop;
int i; int i;
u32 num_rows = 0; int num_rows;
u32 num_cols = 0; int num_cols;
u32 cols_cfg[KBC_MAX_GPIO]; u32 cols_cfg[KBC_MAX_GPIO];
u32 rows_cfg[KBC_MAX_GPIO]; u32 rows_cfg[KBC_MAX_GPIO];
int proplen;
int ret;
if (!of_property_read_u32(np, "nvidia,debounce-delay-ms", &prop)) if (!of_property_read_u32(np, "nvidia,debounce-delay-ms", &prop))
kbc->debounce_cnt = prop; kbc->debounce_cnt = prop;
...@@ -510,56 +501,23 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) ...@@ -510,56 +501,23 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
of_property_read_bool(np, "nvidia,wakeup-source")) /* legacy */ of_property_read_bool(np, "nvidia,wakeup-source")) /* legacy */
kbc->wakeup = true; kbc->wakeup = true;
if (!of_get_property(np, "nvidia,kbc-row-pins", &proplen)) { if (!of_property_present(np, "linux,keymap")) {
dev_err(kbc->dev, "property nvidia,kbc-row-pins not found\n");
return -ENOENT;
}
num_rows = proplen / sizeof(u32);
if (!of_get_property(np, "nvidia,kbc-col-pins", &proplen)) {
dev_err(kbc->dev, "property nvidia,kbc-col-pins not found\n");
return -ENOENT;
}
num_cols = proplen / sizeof(u32);
if (num_rows > kbc->hw_support->max_rows) {
dev_err(kbc->dev,
"Number of rows is more than supported by hardware\n");
return -EINVAL;
}
if (num_cols > kbc->hw_support->max_columns) {
dev_err(kbc->dev,
"Number of cols is more than supported by hardware\n");
return -EINVAL;
}
if (!of_get_property(np, "linux,keymap", &proplen)) {
dev_err(kbc->dev, "property linux,keymap not found\n"); dev_err(kbc->dev, "property linux,keymap not found\n");
return -ENOENT; return -ENOENT;
} }
if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) {
dev_err(kbc->dev,
"keypad rows/columns not properly specified\n");
return -EINVAL;
}
/* Set all pins as non-configured */ /* Set all pins as non-configured */
for (i = 0; i < kbc->num_rows_and_columns; i++) for (i = 0; i < kbc->num_rows_and_columns; i++)
kbc->pin_cfg[i].type = PIN_CFG_IGNORE; kbc->pin_cfg[i].type = PIN_CFG_IGNORE;
ret = of_property_read_u32_array(np, "nvidia,kbc-row-pins", num_rows = of_property_read_variable_u32_array(np, "nvidia,kbc-row-pins",
rows_cfg, num_rows); rows_cfg, 1, KBC_MAX_GPIO);
if (ret < 0) { if (num_rows < 0) {
dev_err(kbc->dev, "Rows configurations are not proper\n"); dev_err(kbc->dev, "Rows configurations are not proper\n");
return -EINVAL; return num_rows;
} } else if (num_rows > kbc->hw_support->max_rows) {
dev_err(kbc->dev,
ret = of_property_read_u32_array(np, "nvidia,kbc-col-pins", "Number of rows is more than supported by hardware\n");
cols_cfg, num_cols);
if (ret < 0) {
dev_err(kbc->dev, "Cols configurations are not proper\n");
return -EINVAL; return -EINVAL;
} }
...@@ -568,11 +526,28 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) ...@@ -568,11 +526,28 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
kbc->pin_cfg[rows_cfg[i]].num = i; kbc->pin_cfg[rows_cfg[i]].num = i;
} }
num_cols = of_property_read_variable_u32_array(np, "nvidia,kbc-col-pins",
cols_cfg, 1, KBC_MAX_GPIO);
if (num_cols < 0) {
dev_err(kbc->dev, "Cols configurations are not proper\n");
return num_cols;
} else if (num_cols > kbc->hw_support->max_columns) {
dev_err(kbc->dev,
"Number of cols is more than supported by hardware\n");
return -EINVAL;
}
for (i = 0; i < num_cols; i++) { for (i = 0; i < num_cols; i++) {
kbc->pin_cfg[cols_cfg[i]].type = PIN_CFG_COL; kbc->pin_cfg[cols_cfg[i]].type = PIN_CFG_COL;
kbc->pin_cfg[cols_cfg[i]].num = i; kbc->pin_cfg[cols_cfg[i]].num = i;
} }
if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) {
dev_err(kbc->dev,
"keypad rows/columns not properly specified\n");
return -EINVAL;
}
return 0; return 0;
} }
...@@ -724,7 +699,8 @@ static int tegra_kbc_suspend(struct device *dev) ...@@ -724,7 +699,8 @@ static int tegra_kbc_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct tegra_kbc *kbc = platform_get_drvdata(pdev); struct tegra_kbc *kbc = platform_get_drvdata(pdev);
mutex_lock(&kbc->idev->mutex); guard(mutex)(&kbc->idev->mutex);
if (device_may_wakeup(&pdev->dev)) { if (device_may_wakeup(&pdev->dev)) {
disable_irq(kbc->irq); disable_irq(kbc->irq);
del_timer_sync(&kbc->timer); del_timer_sync(&kbc->timer);
...@@ -747,11 +723,9 @@ static int tegra_kbc_suspend(struct device *dev) ...@@ -747,11 +723,9 @@ static int tegra_kbc_suspend(struct device *dev)
tegra_kbc_set_keypress_interrupt(kbc, true); tegra_kbc_set_keypress_interrupt(kbc, true);
enable_irq(kbc->irq); enable_irq(kbc->irq);
enable_irq_wake(kbc->irq); enable_irq_wake(kbc->irq);
} else { } else if (input_device_enabled(kbc->idev)) {
if (input_device_enabled(kbc->idev)) tegra_kbc_stop(kbc);
tegra_kbc_stop(kbc);
} }
mutex_unlock(&kbc->idev->mutex);
return 0; return 0;
} }
...@@ -760,9 +734,10 @@ static int tegra_kbc_resume(struct device *dev) ...@@ -760,9 +734,10 @@ static int tegra_kbc_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct tegra_kbc *kbc = platform_get_drvdata(pdev); struct tegra_kbc *kbc = platform_get_drvdata(pdev);
int err = 0; int err;
guard(mutex)(&kbc->idev->mutex);
mutex_lock(&kbc->idev->mutex);
if (device_may_wakeup(&pdev->dev)) { if (device_may_wakeup(&pdev->dev)) {
disable_irq_wake(kbc->irq); disable_irq_wake(kbc->irq);
tegra_kbc_setup_wakekeys(kbc, false); tegra_kbc_setup_wakekeys(kbc, false);
...@@ -787,13 +762,13 @@ static int tegra_kbc_resume(struct device *dev) ...@@ -787,13 +762,13 @@ static int tegra_kbc_resume(struct device *dev)
input_report_key(kbc->idev, kbc->wakeup_key, 0); input_report_key(kbc->idev, kbc->wakeup_key, 0);
input_sync(kbc->idev); input_sync(kbc->idev);
} }
} else { } else if (input_device_enabled(kbc->idev)) {
if (input_device_enabled(kbc->idev)) err = tegra_kbc_start(kbc);
err = tegra_kbc_start(kbc); if (err)
return err;
} }
mutex_unlock(&kbc->idev->mutex);
return err; return 0;
} }
static DEFINE_SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops, static DEFINE_SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops,
......
...@@ -73,10 +73,9 @@ static int matrix_keypad_parse_keymap(const char *propname, ...@@ -73,10 +73,9 @@ static int matrix_keypad_parse_keymap(const char *propname,
struct device *dev = input_dev->dev.parent; struct device *dev = input_dev->dev.parent;
unsigned int row_shift = get_count_order(cols); unsigned int row_shift = get_count_order(cols);
unsigned int max_keys = rows << row_shift; unsigned int max_keys = rows << row_shift;
u32 *keys;
int i; int i;
int size; int size;
int retval; int error;
if (!propname) if (!propname)
propname = "linux,keymap"; propname = "linux,keymap";
...@@ -94,30 +93,24 @@ static int matrix_keypad_parse_keymap(const char *propname, ...@@ -94,30 +93,24 @@ static int matrix_keypad_parse_keymap(const char *propname,
return -EINVAL; return -EINVAL;
} }
keys = kmalloc_array(size, sizeof(u32), GFP_KERNEL); u32 *keys __free(kfree) = kmalloc_array(size, sizeof(*keys), GFP_KERNEL);
if (!keys) if (!keys)
return -ENOMEM; return -ENOMEM;
retval = device_property_read_u32_array(dev, propname, keys, size); error = device_property_read_u32_array(dev, propname, keys, size);
if (retval) { if (error) {
dev_err(dev, "failed to read %s property: %d\n", dev_err(dev, "failed to read %s property: %d\n",
propname, retval); propname, error);
goto out; return error;
} }
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
if (!matrix_keypad_map_key(input_dev, rows, cols, if (!matrix_keypad_map_key(input_dev, rows, cols,
row_shift, keys[i])) { row_shift, keys[i]))
retval = -EINVAL; return -EINVAL;
goto out;
}
} }
retval = 0; return 0;
out:
kfree(keys);
return retval;
} }
/** /**
......
...@@ -1067,7 +1067,7 @@ static ssize_t ims_pcu_attribute_store(struct device *dev, ...@@ -1067,7 +1067,7 @@ static ssize_t ims_pcu_attribute_store(struct device *dev,
if (data_len > attr->field_length) if (data_len > attr->field_length)
return -EINVAL; return -EINVAL;
scoped_cond_guard(mutex, return -EINTR, &pcu->cmd_mutex) { scoped_cond_guard(mutex_intr, return -EINTR, &pcu->cmd_mutex) {
memset(field, 0, attr->field_length); memset(field, 0, attr->field_length);
memcpy(field, buf, data_len); memcpy(field, buf, data_len);
......
...@@ -811,7 +811,6 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269) ...@@ -811,7 +811,6 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
{ {
struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg; struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg;
struct i2c_client *client = iqs269->client; struct i2c_client *client = iqs269->client;
struct fwnode_handle *ch_node;
u16 general, misc_a, misc_b; u16 general, misc_a, misc_b;
unsigned int val; unsigned int val;
int error; int error;
...@@ -1049,12 +1048,10 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269) ...@@ -1049,12 +1048,10 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS); sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS);
device_for_each_child_node(&client->dev, ch_node) { device_for_each_child_node_scoped(&client->dev, ch_node) {
error = iqs269_parse_chan(iqs269, ch_node); error = iqs269_parse_chan(iqs269, ch_node);
if (error) { if (error)
fwnode_handle_put(ch_node);
return error; return error;
}
} }
/* /*
......
...@@ -38,6 +38,7 @@ struct bbnsm_pwrkey { ...@@ -38,6 +38,7 @@ struct bbnsm_pwrkey {
int irq; int irq;
int keycode; int keycode;
int keystate; /* 1:pressed */ int keystate; /* 1:pressed */
bool suspended;
struct timer_list check_timer; struct timer_list check_timer;
struct input_dev *input; struct input_dev *input;
}; };
...@@ -70,6 +71,7 @@ static irqreturn_t bbnsm_pwrkey_interrupt(int irq, void *dev_id) ...@@ -70,6 +71,7 @@ static irqreturn_t bbnsm_pwrkey_interrupt(int irq, void *dev_id)
{ {
struct platform_device *pdev = dev_id; struct platform_device *pdev = dev_id;
struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev); struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev);
struct input_dev *input = bbnsm->input;
u32 event; u32 event;
regmap_read(bbnsm->regmap, BBNSM_EVENTS, &event); regmap_read(bbnsm->regmap, BBNSM_EVENTS, &event);
...@@ -78,6 +80,18 @@ static irqreturn_t bbnsm_pwrkey_interrupt(int irq, void *dev_id) ...@@ -78,6 +80,18 @@ static irqreturn_t bbnsm_pwrkey_interrupt(int irq, void *dev_id)
pm_wakeup_event(bbnsm->input->dev.parent, 0); pm_wakeup_event(bbnsm->input->dev.parent, 0);
/*
* Directly report key event after resume to make sure key press
* event is never missed.
*/
if (bbnsm->suspended) {
bbnsm->keystate = 1;
input_event(input, EV_KEY, bbnsm->keycode, 1);
input_sync(input);
/* Fire at most once per suspend/resume cycle */
bbnsm->suspended = false;
}
mod_timer(&bbnsm->check_timer, mod_timer(&bbnsm->check_timer,
jiffies + msecs_to_jiffies(DEBOUNCE_TIME)); jiffies + msecs_to_jiffies(DEBOUNCE_TIME));
...@@ -173,6 +187,29 @@ static int bbnsm_pwrkey_probe(struct platform_device *pdev) ...@@ -173,6 +187,29 @@ static int bbnsm_pwrkey_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int __maybe_unused bbnsm_pwrkey_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev);
bbnsm->suspended = true;
return 0;
}
static int __maybe_unused bbnsm_pwrkey_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev);
bbnsm->suspended = false;
return 0;
}
static SIMPLE_DEV_PM_OPS(bbnsm_pwrkey_pm_ops, bbnsm_pwrkey_suspend,
bbnsm_pwrkey_resume);
static const struct of_device_id bbnsm_pwrkey_ids[] = { static const struct of_device_id bbnsm_pwrkey_ids[] = {
{ .compatible = "nxp,imx93-bbnsm-pwrkey" }, { .compatible = "nxp,imx93-bbnsm-pwrkey" },
{ /* sentinel */ } { /* sentinel */ }
...@@ -182,6 +219,7 @@ MODULE_DEVICE_TABLE(of, bbnsm_pwrkey_ids); ...@@ -182,6 +219,7 @@ MODULE_DEVICE_TABLE(of, bbnsm_pwrkey_ids);
static struct platform_driver bbnsm_pwrkey_driver = { static struct platform_driver bbnsm_pwrkey_driver = {
.driver = { .driver = {
.name = "bbnsm_pwrkey", .name = "bbnsm_pwrkey",
.pm = &bbnsm_pwrkey_pm_ops,
.of_match_table = bbnsm_pwrkey_ids, .of_match_table = bbnsm_pwrkey_ids,
}, },
.probe = bbnsm_pwrkey_probe, .probe = bbnsm_pwrkey_probe,
......
...@@ -990,8 +990,8 @@ static int __init copy_keymap(void) ...@@ -990,8 +990,8 @@ static int __init copy_keymap(void)
for (key = keymap; key->type != KE_END; key++) for (key = keymap; key->type != KE_END; key++)
length++; length++;
new_keymap = kmemdup(keymap, length * sizeof(struct key_entry), new_keymap = kmemdup_array(keymap, length, sizeof(struct key_entry),
GFP_KERNEL); GFP_KERNEL);
if (!new_keymap) if (!new_keymap)
return -ENOMEM; return -ENOMEM;
......
...@@ -69,6 +69,18 @@ config MOUSE_PS2_LOGIPS2PP ...@@ -69,6 +69,18 @@ config MOUSE_PS2_LOGIPS2PP
If unsure, say Y. If unsure, say Y.
config MOUSE_PS2_PIXART
bool "PixArt PS/2 touchpad protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
This driver supports the PixArt PS/2 touchpad found in some
laptops.
Say Y here if you have a PixArt PS/2 TouchPad connected to
your system.
If unsure, say Y.
config MOUSE_PS2_SYNAPTICS config MOUSE_PS2_SYNAPTICS
bool "Synaptics PS/2 mouse protocol extension" if EXPERT bool "Synaptics PS/2 mouse protocol extension" if EXPERT
default y default y
......
...@@ -32,6 +32,7 @@ psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o ...@@ -32,6 +32,7 @@ psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o
psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o
psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
psmouse-$(CONFIG_MOUSE_PS2_PIXART) += pixart_ps2.o
psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o
psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
......
...@@ -1396,24 +1396,16 @@ static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse) ...@@ -1396,24 +1396,16 @@ static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
static DEFINE_MUTEX(alps_mutex); static DEFINE_MUTEX(alps_mutex);
static void alps_register_bare_ps2_mouse(struct work_struct *work) static int alps_do_register_bare_ps2_mouse(struct alps_data *priv)
{ {
struct alps_data *priv =
container_of(work, struct alps_data, dev3_register_work.work);
struct psmouse *psmouse = priv->psmouse; struct psmouse *psmouse = priv->psmouse;
struct input_dev *dev3; struct input_dev *dev3;
int error = 0; int error;
mutex_lock(&alps_mutex);
if (priv->dev3)
goto out;
dev3 = input_allocate_device(); dev3 = input_allocate_device();
if (!dev3) { if (!dev3) {
psmouse_err(psmouse, "failed to allocate secondary device\n"); psmouse_err(psmouse, "failed to allocate secondary device\n");
error = -ENOMEM; return -ENOMEM;
goto out;
} }
snprintf(priv->phys3, sizeof(priv->phys3), "%s/%s", snprintf(priv->phys3, sizeof(priv->phys3), "%s/%s",
...@@ -1446,21 +1438,35 @@ static void alps_register_bare_ps2_mouse(struct work_struct *work) ...@@ -1446,21 +1438,35 @@ static void alps_register_bare_ps2_mouse(struct work_struct *work)
psmouse_err(psmouse, psmouse_err(psmouse,
"failed to register secondary device: %d\n", "failed to register secondary device: %d\n",
error); error);
input_free_device(dev3); goto err_free_input;
goto out;
} }
priv->dev3 = dev3; priv->dev3 = dev3;
return 0;
out: err_free_input:
/* input_free_device(dev3);
* Save the error code so that we can detect that we return error;
* already tried to create the device. }
*/
if (error)
priv->dev3 = ERR_PTR(error);
mutex_unlock(&alps_mutex); static void alps_register_bare_ps2_mouse(struct work_struct *work)
{
struct alps_data *priv = container_of(work, struct alps_data,
dev3_register_work.work);
int error;
guard(mutex)(&alps_mutex);
if (!priv->dev3) {
error = alps_do_register_bare_ps2_mouse(priv);
if (error) {
/*
* Save the error code so that we can detect that we
* already tried to create the device.
*/
priv->dev3 = ERR_PTR(error);
}
}
} }
static void alps_report_bare_ps2_packet(struct psmouse *psmouse, static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
......
...@@ -834,13 +834,11 @@ static int bcm5974_open(struct input_dev *input) ...@@ -834,13 +834,11 @@ static int bcm5974_open(struct input_dev *input)
if (error) if (error)
return error; return error;
mutex_lock(&dev->pm_mutex); scoped_guard(mutex, &dev->pm_mutex) {
error = bcm5974_start_traffic(dev);
error = bcm5974_start_traffic(dev); if (!error)
if (!error) dev->opened = 1;
dev->opened = 1; }
mutex_unlock(&dev->pm_mutex);
if (error) if (error)
usb_autopm_put_interface(dev->intf); usb_autopm_put_interface(dev->intf);
...@@ -852,12 +850,10 @@ static void bcm5974_close(struct input_dev *input) ...@@ -852,12 +850,10 @@ static void bcm5974_close(struct input_dev *input)
{ {
struct bcm5974 *dev = input_get_drvdata(input); struct bcm5974 *dev = input_get_drvdata(input);
mutex_lock(&dev->pm_mutex); scoped_guard(mutex, &dev->pm_mutex) {
bcm5974_pause_traffic(dev);
bcm5974_pause_traffic(dev); dev->opened = 0;
dev->opened = 0; }
mutex_unlock(&dev->pm_mutex);
usb_autopm_put_interface(dev->intf); usb_autopm_put_interface(dev->intf);
} }
...@@ -866,29 +862,24 @@ static int bcm5974_suspend(struct usb_interface *iface, pm_message_t message) ...@@ -866,29 +862,24 @@ static int bcm5974_suspend(struct usb_interface *iface, pm_message_t message)
{ {
struct bcm5974 *dev = usb_get_intfdata(iface); struct bcm5974 *dev = usb_get_intfdata(iface);
mutex_lock(&dev->pm_mutex); guard(mutex)(&dev->pm_mutex);
if (dev->opened) if (dev->opened)
bcm5974_pause_traffic(dev); bcm5974_pause_traffic(dev);
mutex_unlock(&dev->pm_mutex);
return 0; return 0;
} }
static int bcm5974_resume(struct usb_interface *iface) static int bcm5974_resume(struct usb_interface *iface)
{ {
struct bcm5974 *dev = usb_get_intfdata(iface); struct bcm5974 *dev = usb_get_intfdata(iface);
int error = 0;
mutex_lock(&dev->pm_mutex); guard(mutex)(&dev->pm_mutex);
if (dev->opened) if (dev->opened)
error = bcm5974_start_traffic(dev); return bcm5974_start_traffic(dev);
mutex_unlock(&dev->pm_mutex); return 0;
return error;
} }
static int bcm5974_probe(struct usb_interface *iface, static int bcm5974_probe(struct usb_interface *iface,
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Pixart Touchpad Controller 1336U PS2 driver
*
* Author: Jon Xie <jon_xie@pixart.com>
* Jay Lee <jay_lee@pixart.com>
* Further cleanup and restructuring by:
* Binbin Zhou <zhoubinbin@loongson.cn>
*
* Copyright (C) 2021-2024 Pixart Imaging.
* Copyright (C) 2024 Loongson Technology Corporation Limited.
*
*/
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/libps2.h>
#include <linux/serio.h>
#include <linux/slab.h>
#include "pixart_ps2.h"
static int pixart_read_tp_mode(struct ps2dev *ps2dev, u8 *mode)
{
int error;
u8 param[1] = { 0 };
error = ps2_command(ps2dev, param, PIXART_CMD_REPORT_FORMAT);
if (error)
return error;
*mode = param[0] == 1 ? PIXART_MODE_ABS : PIXART_MODE_REL;
return 0;
}
static int pixart_read_tp_type(struct ps2dev *ps2dev, u8 *type)
{
int error;
u8 param[3] = { 0 };
param[0] = 0x0a;
error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
if (error)
return error;
param[0] = 0x0;
error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
if (error)
return error;
error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
if (error)
return error;
error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
if (error)
return error;
param[0] = 0x03;
error = ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
if (error)
return error;
error = ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
if (error)
return error;
*type = param[0] == 0x0e ? PIXART_TYPE_TOUCHPAD : PIXART_TYPE_CLICKPAD;
return 0;
}
static void pixart_reset(struct psmouse *psmouse)
{
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
/* according to PixArt, 100ms is required for the upcoming reset */
msleep(100);
psmouse_reset(psmouse);
}
static void pixart_process_packet(struct psmouse *psmouse)
{
struct pixart_data *priv = psmouse->private;
struct input_dev *dev = psmouse->dev;
const u8 *pkt = psmouse->packet;
unsigned int contact_cnt = FIELD_GET(CONTACT_CNT_MASK, pkt[0]);
unsigned int i, id, abs_x, abs_y;
bool tip;
for (i = 0; i < contact_cnt; i++) {
const u8 *p = &pkt[i * 3];
id = FIELD_GET(SLOT_ID_MASK, p[3]);
abs_y = FIELD_GET(ABS_Y_MASK, p[3]) << 8 | p[1];
abs_x = FIELD_GET(ABS_X_MASK, p[3]) << 8 | p[2];
if (i == PIXART_MAX_FINGERS - 1)
tip = pkt[14] & BIT(1);
else
tip = pkt[3 * contact_cnt + 1] & BIT(2 * i + 1);
input_mt_slot(dev, id);
if (input_mt_report_slot_state(dev, MT_TOOL_FINGER, tip)) {
input_report_abs(dev, ABS_MT_POSITION_Y, abs_y);
input_report_abs(dev, ABS_MT_POSITION_X, abs_x);
}
}
input_mt_sync_frame(dev);
if (priv->type == PIXART_TYPE_CLICKPAD) {
input_report_key(dev, BTN_LEFT, pkt[0] & 0x03);
} else {
input_report_key(dev, BTN_LEFT, pkt[0] & BIT(0));
input_report_key(dev, BTN_RIGHT, pkt[0] & BIT(1));
}
input_sync(dev);
}
static psmouse_ret_t pixart_protocol_handler(struct psmouse *psmouse)
{
u8 *pkt = psmouse->packet;
u8 contact_cnt;
if ((pkt[0] & 0x8c) != 0x80)
return PSMOUSE_BAD_DATA;
contact_cnt = FIELD_GET(CONTACT_CNT_MASK, pkt[0]);
if (contact_cnt > PIXART_MAX_FINGERS)
return PSMOUSE_BAD_DATA;
if (contact_cnt == PIXART_MAX_FINGERS &&
psmouse->pktcnt < psmouse->pktsize) {
return PSMOUSE_GOOD_DATA;
}
if (contact_cnt == 0 && psmouse->pktcnt < 5)
return PSMOUSE_GOOD_DATA;
if (psmouse->pktcnt < 3 * contact_cnt + 2)
return PSMOUSE_GOOD_DATA;
pixart_process_packet(psmouse);
return PSMOUSE_FULL_PACKET;
}
static void pixart_disconnect(struct psmouse *psmouse)
{
pixart_reset(psmouse);
kfree(psmouse->private);
psmouse->private = NULL;
}
static int pixart_reconnect(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
u8 mode;
int error;
pixart_reset(psmouse);
error = pixart_read_tp_mode(ps2dev, &mode);
if (error)
return error;
if (mode != PIXART_MODE_ABS)
return -EIO;
error = ps2_command(ps2dev, NULL, PIXART_CMD_SWITCH_PROTO);
if (error)
return error;
return 0;
}
static int pixart_set_input_params(struct input_dev *dev,
struct pixart_data *priv)
{
/* No relative support */
__clear_bit(EV_REL, dev->evbit);
__clear_bit(REL_X, dev->relbit);
__clear_bit(REL_Y, dev->relbit);
__clear_bit(BTN_MIDDLE, dev->keybit);
/* Buttons */
__set_bit(EV_KEY, dev->evbit);
__set_bit(BTN_LEFT, dev->keybit);
if (priv->type == PIXART_TYPE_CLICKPAD)
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
else
__set_bit(BTN_RIGHT, dev->keybit);
/* Absolute position */
input_set_abs_params(dev, ABS_X, 0, PIXART_PAD_WIDTH, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, PIXART_PAD_HEIGHT, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_X,
0, PIXART_PAD_WIDTH, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y,
0, PIXART_PAD_HEIGHT, 0, 0);
return input_mt_init_slots(dev, PIXART_MAX_FINGERS, INPUT_MT_POINTER);
}
static int pixart_query_hardware(struct ps2dev *ps2dev, u8 *mode, u8 *type)
{
int error;
error = pixart_read_tp_type(ps2dev, type);
if (error)
return error;
error = pixart_read_tp_mode(ps2dev, mode);
if (error)
return error;
return 0;
}
int pixart_detect(struct psmouse *psmouse, bool set_properties)
{
u8 type;
int error;
pixart_reset(psmouse);
error = pixart_read_tp_type(&psmouse->ps2dev, &type);
if (error)
return error;
if (set_properties) {
psmouse->vendor = "PixArt";
psmouse->name = (type == PIXART_TYPE_TOUCHPAD) ?
"touchpad" : "clickpad";
}
return 0;
}
int pixart_init(struct psmouse *psmouse)
{
int error;
struct pixart_data *priv;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
psmouse->private = priv;
pixart_reset(psmouse);
error = pixart_query_hardware(&psmouse->ps2dev,
&priv->mode, &priv->type);
if (error) {
psmouse_err(psmouse, "init: Unable to query PixArt touchpad hardware.\n");
goto err_exit;
}
/* Relative mode follows standard PS/2 mouse protocol */
if (priv->mode != PIXART_MODE_ABS) {
error = -EIO;
goto err_exit;
}
/* Set absolute mode */
error = ps2_command(&psmouse->ps2dev, NULL, PIXART_CMD_SWITCH_PROTO);
if (error) {
psmouse_err(psmouse, "init: Unable to initialize PixArt absolute mode.\n");
goto err_exit;
}
error = pixart_set_input_params(psmouse->dev, priv);
if (error) {
psmouse_err(psmouse, "init: Unable to set input params.\n");
goto err_exit;
}
psmouse->pktsize = 15;
psmouse->protocol_handler = pixart_protocol_handler;
psmouse->disconnect = pixart_disconnect;
psmouse->reconnect = pixart_reconnect;
psmouse->cleanup = pixart_reset;
/* resync is not supported yet */
psmouse->resync_time = 0;
return 0;
err_exit:
pixart_reset(psmouse);
kfree(priv);
psmouse->private = NULL;
return error;
}
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _PIXART_PS2_H
#define _PIXART_PS2_H
#include "psmouse.h"
#define PIXART_PAD_WIDTH 1023
#define PIXART_PAD_HEIGHT 579
#define PIXART_MAX_FINGERS 4
#define PIXART_CMD_REPORT_FORMAT 0x01d8
#define PIXART_CMD_SWITCH_PROTO 0x00de
#define PIXART_MODE_REL 0
#define PIXART_MODE_ABS 1
#define PIXART_TYPE_CLICKPAD 0
#define PIXART_TYPE_TOUCHPAD 1
#define CONTACT_CNT_MASK GENMASK(6, 4)
#define SLOT_ID_MASK GENMASK(2, 0)
#define ABS_Y_MASK GENMASK(5, 4)
#define ABS_X_MASK GENMASK(7, 6)
struct pixart_data {
u8 mode;
u8 type;
int x_max;
int y_max;
};
int pixart_detect(struct psmouse *psmouse, bool set_properties);
int pixart_init(struct psmouse *psmouse);
#endif /* _PIXART_PS2_H */
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "focaltech.h" #include "focaltech.h"
#include "vmmouse.h" #include "vmmouse.h"
#include "byd.h" #include "byd.h"
#include "pixart_ps2.h"
#define DRIVER_DESC "PS/2 mouse driver" #define DRIVER_DESC "PS/2 mouse driver"
...@@ -905,6 +906,15 @@ static const struct psmouse_protocol psmouse_protocols[] = { ...@@ -905,6 +906,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.detect = byd_detect, .detect = byd_detect,
.init = byd_init, .init = byd_init,
}, },
#endif
#ifdef CONFIG_MOUSE_PS2_PIXART
{
.type = PSMOUSE_PIXART,
.name = "PixArtPS/2",
.alias = "pixart",
.detect = pixart_detect,
.init = pixart_init,
},
#endif #endif
{ {
.type = PSMOUSE_AUTO, .type = PSMOUSE_AUTO,
...@@ -1172,6 +1182,13 @@ static int psmouse_extensions(struct psmouse *psmouse, ...@@ -1172,6 +1182,13 @@ static int psmouse_extensions(struct psmouse *psmouse,
return ret; return ret;
} }
/* Try PixArt touchpad */
if (max_proto > PSMOUSE_IMEX &&
psmouse_try_protocol(psmouse, PSMOUSE_PIXART, &max_proto,
set_properties, true)) {
return PSMOUSE_PIXART;
}
if (max_proto > PSMOUSE_IMEX) { if (max_proto > PSMOUSE_IMEX) {
if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS, if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS,
&max_proto, set_properties, true)) &max_proto, set_properties, true))
......
...@@ -69,6 +69,7 @@ enum psmouse_type { ...@@ -69,6 +69,7 @@ enum psmouse_type {
PSMOUSE_BYD, PSMOUSE_BYD,
PSMOUSE_SYNAPTICS_SMBUS, PSMOUSE_SYNAPTICS_SMBUS,
PSMOUSE_ELANTECH_SMBUS, PSMOUSE_ELANTECH_SMBUS,
PSMOUSE_PIXART,
PSMOUSE_AUTO /* This one should always be last */ PSMOUSE_AUTO /* This one should always be last */
}; };
...@@ -94,7 +95,7 @@ struct psmouse { ...@@ -94,7 +95,7 @@ struct psmouse {
const char *vendor; const char *vendor;
const char *name; const char *name;
const struct psmouse_protocol *protocol; const struct psmouse_protocol *protocol;
unsigned char packet[8]; unsigned char packet[16];
unsigned char badbyte; unsigned char badbyte;
unsigned char pktcnt; unsigned char pktcnt;
unsigned char pktsize; unsigned char pktsize;
......
...@@ -24,6 +24,7 @@ enum rmi_f12_object_type { ...@@ -24,6 +24,7 @@ enum rmi_f12_object_type {
}; };
#define F12_DATA1_BYTES_PER_OBJ 8 #define F12_DATA1_BYTES_PER_OBJ 8
#define RMI_F12_QUERY_RESOLUTION 29
struct f12_data { struct f12_data {
struct rmi_2d_sensor sensor; struct rmi_2d_sensor sensor;
...@@ -73,6 +74,8 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) ...@@ -73,6 +74,8 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
int pitch_y = 0; int pitch_y = 0;
int rx_receivers = 0; int rx_receivers = 0;
int tx_receivers = 0; int tx_receivers = 0;
u16 query_dpm_addr = 0;
int dpm_resolution = 0;
item = rmi_get_register_desc_item(&f12->control_reg_desc, 8); item = rmi_get_register_desc_item(&f12->control_reg_desc, 8);
if (!item) { if (!item) {
...@@ -122,18 +125,38 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) ...@@ -122,18 +125,38 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
offset += 4; offset += 4;
} }
if (rmi_register_desc_has_subpacket(item, 3)) { /*
rx_receivers = buf[offset]; * Use the Query DPM feature when the resolution query register
tx_receivers = buf[offset + 1]; * exists.
offset += 2; */
} if (rmi_get_register_desc_item(&f12->query_reg_desc,
RMI_F12_QUERY_RESOLUTION)) {
offset = rmi_register_desc_calc_reg_offset(&f12->query_reg_desc,
RMI_F12_QUERY_RESOLUTION);
query_dpm_addr = fn->fd.query_base_addr + offset;
ret = rmi_read(fn->rmi_dev, query_dpm_addr, buf);
if (ret < 0) {
dev_err(&fn->dev, "Failed to read DPM value: %d\n", ret);
return -ENODEV;
}
dpm_resolution = buf[0];
/* Skip over sensor flags */ sensor->x_mm = sensor->max_x / dpm_resolution;
if (rmi_register_desc_has_subpacket(item, 4)) sensor->y_mm = sensor->max_y / dpm_resolution;
offset += 1; } else {
if (rmi_register_desc_has_subpacket(item, 3)) {
rx_receivers = buf[offset];
tx_receivers = buf[offset + 1];
offset += 2;
}
sensor->x_mm = (pitch_x * rx_receivers) >> 12; /* Skip over sensor flags */
sensor->y_mm = (pitch_y * tx_receivers) >> 12; if (rmi_register_desc_has_subpacket(item, 4))
offset += 1;
sensor->x_mm = (pitch_x * rx_receivers) >> 12;
sensor->y_mm = (pitch_y * tx_receivers) >> 12;
}
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x_mm: %d y_mm: %d\n", __func__, rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x_mm: %d y_mm: %d\n", __func__,
sensor->x_mm, sensor->y_mm); sensor->x_mm, sensor->y_mm);
......
...@@ -1120,6 +1120,43 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { ...@@ -1120,6 +1120,43 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
}, },
.driver_data = (void *)(SERIO_QUIRK_NOLOOP) .driver_data = (void *)(SERIO_QUIRK_NOLOOP)
}, },
/*
* Some TongFang barebones have touchpad and/or keyboard issues after
* suspend fixable with nomux + reset + noloop + nopnp. Luckily, none of
* them have an external PS/2 port so this can safely be set for all of
* them.
* TongFang barebones come with board_vendor and/or system_vendor set to
* a different value for each individual reseller. The only somewhat
* universal way to identify them is by board_name.
*/
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "GMxXGxX"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
/* /*
* A lot of modern Clevo barebones have touchpad and/or keyboard issues * A lot of modern Clevo barebones have touchpad and/or keyboard issues
* after suspend fixable with nomux + reset + noloop + nopnp. Luckily, * after suspend fixable with nomux + reset + noloop + nopnp. Luckily,
......
...@@ -429,16 +429,14 @@ static int ps2_gpio_probe(struct platform_device *pdev) ...@@ -429,16 +429,14 @@ static int ps2_gpio_probe(struct platform_device *pdev)
} }
error = devm_request_irq(dev, drvdata->irq, ps2_gpio_irq, error = devm_request_irq(dev, drvdata->irq, ps2_gpio_irq,
IRQF_NO_THREAD, DRIVER_NAME, drvdata); IRQF_NO_THREAD | IRQF_NO_AUTOEN, DRIVER_NAME,
drvdata);
if (error) { if (error) {
dev_err(dev, "failed to request irq %d: %d\n", dev_err(dev, "failed to request irq %d: %d\n",
drvdata->irq, error); drvdata->irq, error);
goto err_free_serio; goto err_free_serio;
} }
/* Keep irq disabled until serio->open is called. */
disable_irq(drvdata->irq);
serio->id.type = SERIO_8042; serio->id.type = SERIO_8042;
serio->open = ps2_gpio_open; serio->open = ps2_gpio_open;
serio->close = ps2_gpio_close; serio->close = ps2_gpio_close;
......
...@@ -254,36 +254,6 @@ config TOUCHSCREEN_CYTTSP_SPI ...@@ -254,36 +254,6 @@ config TOUCHSCREEN_CYTTSP_SPI
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 cyttsp_spi. module will be called cyttsp_spi.
config TOUCHSCREEN_CYTTSP4_CORE
tristate "Cypress TrueTouch Gen4 Touchscreen Driver"
help
Core driver for Cypress TrueTouch(tm) Standard Product
Generation4 touchscreen controllers.
Say Y here if you have a Cypress Gen4 touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_CYTTSP4_I2C
tristate "support I2C bus connection"
depends on TOUCHSCREEN_CYTTSP4_CORE && I2C
help
Say Y here if the touchscreen is connected via I2C bus.
To compile this driver as a module, choose M here: the
module will be called cyttsp4_i2c.
config TOUCHSCREEN_CYTTSP4_SPI
tristate "support SPI bus connection"
depends on TOUCHSCREEN_CYTTSP4_CORE && SPI_MASTER
help
Say Y here if the touchscreen is connected via SPI bus.
To compile this driver as a module, choose M here: the
module will be called cyttsp4_spi.
config TOUCHSCREEN_CYTTSP5 config TOUCHSCREEN_CYTTSP5
tristate "Cypress TrueTouch Gen5 Touchscreen Driver" tristate "Cypress TrueTouch Gen5 Touchscreen Driver"
depends on I2C depends on I2C
...@@ -626,18 +596,6 @@ config TOUCHSCREEN_MAX11801 ...@@ -626,18 +596,6 @@ config TOUCHSCREEN_MAX11801
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 max11801_ts. module will be called max11801_ts.
config TOUCHSCREEN_MCS5000
tristate "MELFAS MCS-5000 touchscreen"
depends on I2C
help
Say Y here if you have the MELFAS MCS-5000 touchscreen controller
chip in your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mcs5000_ts.
config TOUCHSCREEN_MMS114 config TOUCHSCREEN_MMS114
tristate "MELFAS MMS114 touchscreen" tristate "MELFAS MMS114 touchscreen"
depends on I2C depends on I2C
......
...@@ -25,11 +25,8 @@ obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8505) += chipone_icn8505.o ...@@ -25,11 +25,8 @@ obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8505) += chipone_icn8505.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMA140) += cy8ctma140.o obj-$(CONFIG_TOUCHSCREEN_CY8CTMA140) += cy8ctma140.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_CORE) += cyttsp4_core.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_I2C) += cyttsp4_i2c.o cyttsp_i2c_common.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI) += cyttsp4_spi.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP5) += cyttsp5.o obj-$(CONFIG_TOUCHSCREEN_CYTTSP5) += cyttsp5.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
...@@ -63,7 +60,6 @@ obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o ...@@ -63,7 +60,6 @@ obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o
obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MIP4) += melfas_mip4.o obj-$(CONFIG_TOUCHSCREEN_MELFAS_MIP4) += melfas_mip4.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
obj-$(CONFIG_TOUCHSCREEN_MMS114) += mms114.o obj-$(CONFIG_TOUCHSCREEN_MMS114) += mms114.o
......
...@@ -239,14 +239,10 @@ static void vf50_ts_close(struct input_dev *dev_input) ...@@ -239,14 +239,10 @@ static void vf50_ts_close(struct input_dev *dev_input)
static int vf50_ts_get_gpiod(struct device *dev, struct gpio_desc **gpio_d, static int vf50_ts_get_gpiod(struct device *dev, struct gpio_desc **gpio_d,
const char *con_id, enum gpiod_flags flags) const char *con_id, enum gpiod_flags flags)
{ {
int error;
*gpio_d = devm_gpiod_get(dev, con_id, flags); *gpio_d = devm_gpiod_get(dev, con_id, flags);
if (IS_ERR(*gpio_d)) { if (IS_ERR(*gpio_d))
error = PTR_ERR(*gpio_d); return dev_err_probe(dev, PTR_ERR(*gpio_d),
dev_err(dev, "Could not get gpio_%s %d\n", con_id, error); "Could not get gpio_%s\n", con_id);
return error;
}
return 0; return 0;
} }
......
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* cyttsp_i2c.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
* For use with Cypress Txx4xx parts.
* Supported parts include:
* TMA4XX
* TMA1036
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*/
#include "cyttsp4_core.h"
#include <linux/i2c.h>
#include <linux/input.h>
#define CYTTSP4_I2C_DATA_SIZE (3 * 256)
static const struct cyttsp4_bus_ops cyttsp4_i2c_bus_ops = {
.bustype = BUS_I2C,
.write = cyttsp_i2c_write_block_data,
.read = cyttsp_i2c_read_block_data,
};
static int cyttsp4_i2c_probe(struct i2c_client *client)
{
struct cyttsp4 *ts;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "I2C functionality not Supported\n");
return -EIO;
}
ts = cyttsp4_probe(&cyttsp4_i2c_bus_ops, &client->dev, client->irq,
CYTTSP4_I2C_DATA_SIZE);
return PTR_ERR_OR_ZERO(ts);
}
static void cyttsp4_i2c_remove(struct i2c_client *client)
{
struct cyttsp4 *ts = i2c_get_clientdata(client);
cyttsp4_remove(ts);
}
static const struct i2c_device_id cyttsp4_i2c_id[] = {
{ CYTTSP4_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id);
static struct i2c_driver cyttsp4_i2c_driver = {
.driver = {
.name = CYTTSP4_I2C_NAME,
.pm = pm_ptr(&cyttsp4_pm_ops),
},
.probe = cyttsp4_i2c_probe,
.remove = cyttsp4_i2c_remove,
.id_table = cyttsp4_i2c_id,
};
module_i2c_driver(cyttsp4_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
MODULE_AUTHOR("Cypress");
// SPDX-License-Identifier: GPL-2.0-only
/*
* Source for:
* Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
* For use with Cypress Txx4xx parts.
* Supported parts include:
* TMA4XX
* TMA1036
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*/
#include "cyttsp4_core.h"
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/spi/spi.h>
#define CY_SPI_WR_OP 0x00 /* r/~w */
#define CY_SPI_RD_OP 0x01
#define CY_SPI_BITS_PER_WORD 8
#define CY_SPI_A8_BIT 0x02
#define CY_SPI_WR_HEADER_BYTES 2
#define CY_SPI_RD_HEADER_BYTES 1
#define CY_SPI_CMD_BYTES 2
#define CY_SPI_SYNC_BYTE 0
#define CY_SPI_SYNC_ACK 0x62 /* from TRM *A protocol */
#define CY_SPI_DATA_SIZE (2 * 256)
#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
u8 op, u16 reg, u8 *buf, int length)
{
struct spi_device *spi = to_spi_device(dev);
struct spi_message msg;
struct spi_transfer xfer[2];
u8 *wr_buf = &xfer_buf[0];
u8 rd_buf[CY_SPI_CMD_BYTES];
int retval;
int i;
if (length > CY_SPI_DATA_SIZE) {
dev_err(dev, "%s: length %d is too big.\n",
__func__, length);
return -EINVAL;
}
memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
memset(rd_buf, 0, CY_SPI_CMD_BYTES);
wr_buf[0] = op + (((reg >> 8) & 0x1) ? CY_SPI_A8_BIT : 0);
if (op == CY_SPI_WR_OP) {
wr_buf[1] = reg & 0xFF;
if (length > 0)
memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
}
memset(xfer, 0, sizeof(xfer));
spi_message_init(&msg);
/*
We set both TX and RX buffers because Cypress TTSP
requires full duplex operation.
*/
xfer[0].tx_buf = wr_buf;
xfer[0].rx_buf = rd_buf;
switch (op) {
case CY_SPI_WR_OP:
xfer[0].len = length + CY_SPI_CMD_BYTES;
spi_message_add_tail(&xfer[0], &msg);
break;
case CY_SPI_RD_OP:
xfer[0].len = CY_SPI_RD_HEADER_BYTES;
spi_message_add_tail(&xfer[0], &msg);
xfer[1].rx_buf = buf;
xfer[1].len = length;
spi_message_add_tail(&xfer[1], &msg);
break;
default:
dev_err(dev, "%s: bad operation code=%d\n", __func__, op);
return -EINVAL;
}
retval = spi_sync(spi, &msg);
if (retval < 0) {
dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
__func__, retval, xfer[1].len, op);
/*
* do not return here since was a bad ACK sequence
* let the following ACK check handle any errors and
* allow silent retries
*/
}
if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) {
dev_dbg(dev, "%s: operation %d failed\n", __func__, op);
for (i = 0; i < CY_SPI_CMD_BYTES; i++)
dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n",
__func__, i, rd_buf[i]);
for (i = 0; i < length; i++)
dev_dbg(dev, "%s: test buf[%d]:0x%02x\n",
__func__, i, buf[i]);
return -EIO;
}
return 0;
}
static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
u16 addr, u8 length, void *data)
{
int rc;
rc = cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, NULL, 0);
if (rc)
return rc;
else
return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
length);
}
static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
u16 addr, u8 length, const void *data)
{
return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
length);
}
static const struct cyttsp4_bus_ops cyttsp_spi_bus_ops = {
.bustype = BUS_SPI,
.write = cyttsp_spi_write_block_data,
.read = cyttsp_spi_read_block_data,
};
static int cyttsp4_spi_probe(struct spi_device *spi)
{
struct cyttsp4 *ts;
int error;
/* Set up SPI*/
spi->bits_per_word = CY_SPI_BITS_PER_WORD;
spi->mode = SPI_MODE_0;
error = spi_setup(spi);
if (error < 0) {
dev_err(&spi->dev, "%s: SPI setup error %d\n",
__func__, error);
return error;
}
ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
CY_SPI_DATA_BUF_SIZE);
return PTR_ERR_OR_ZERO(ts);
}
static void cyttsp4_spi_remove(struct spi_device *spi)
{
struct cyttsp4 *ts = spi_get_drvdata(spi);
cyttsp4_remove(ts);
}
static struct spi_driver cyttsp4_spi_driver = {
.driver = {
.name = CYTTSP4_SPI_NAME,
.pm = pm_ptr(&cyttsp4_pm_ops),
},
.probe = cyttsp4_spi_probe,
.remove = cyttsp4_spi_remove,
};
module_spi_driver(cyttsp4_spi_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
MODULE_AUTHOR("Cypress");
MODULE_ALIAS("spi:cyttsp4");
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/input/touchscreen.h> #include <linux/input/touchscreen.h>
#include <linux/gpio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/property.h> #include <linux/property.h>
...@@ -615,17 +614,14 @@ static int cyttsp_parse_properties(struct cyttsp *ts) ...@@ -615,17 +614,14 @@ static int cyttsp_parse_properties(struct cyttsp *ts)
return 0; return 0;
} }
static void cyttsp_disable_regulators(void *_ts)
{
struct cyttsp *ts = _ts;
regulator_bulk_disable(ARRAY_SIZE(ts->regulators),
ts->regulators);
}
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size) struct device *dev, int irq, size_t xfer_buf_size)
{ {
/*
* VCPIN is the analog voltage supply
* VDD is the digital voltage supply
*/
static const char * const supplies[] = { "vcpin", "vdd" };
struct cyttsp *ts; struct cyttsp *ts;
struct input_dev *input_dev; struct input_dev *input_dev;
int error; int error;
...@@ -643,29 +639,10 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, ...@@ -643,29 +639,10 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
ts->bus_ops = bus_ops; ts->bus_ops = bus_ops;
ts->irq = irq; ts->irq = irq;
/* error = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(supplies),
* VCPIN is the analog voltage supply supplies);
* VDD is the digital voltage supply
*/
ts->regulators[0].supply = "vcpin";
ts->regulators[1].supply = "vdd";
error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators),
ts->regulators);
if (error) {
dev_err(dev, "Failed to get regulators: %d\n", error);
return ERR_PTR(error);
}
error = regulator_bulk_enable(ARRAY_SIZE(ts->regulators),
ts->regulators);
if (error) {
dev_err(dev, "Cannot enable regulators: %d\n", error);
return ERR_PTR(error);
}
error = devm_add_action_or_reset(dev, cyttsp_disable_regulators, ts);
if (error) { if (error) {
dev_err(dev, "failed to install chip disable handler\n"); dev_err(dev, "Failed to enable regulators: %d\n", error);
return ERR_PTR(error); return ERR_PTR(error);
} }
......
...@@ -122,7 +122,6 @@ struct cyttsp { ...@@ -122,7 +122,6 @@ struct cyttsp {
enum cyttsp_state state; enum cyttsp_state state;
bool suspended; bool suspended;
struct regulator_bulk_data regulators[2];
struct gpio_desc *reset_gpio; struct gpio_desc *reset_gpio;
bool use_hndshk; bool use_hndshk;
u8 act_dist; u8 act_dist;
...@@ -137,10 +136,6 @@ struct cyttsp { ...@@ -137,10 +136,6 @@ struct cyttsp {
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops, struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size); struct device *dev, int irq, size_t xfer_buf_size);
int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
u8 length, const void *values);
int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
u8 length, void *values);
extern const struct dev_pm_ops cyttsp_pm_ops; extern const struct dev_pm_ops cyttsp_pm_ops;
#endif /* __CYTTSP_CORE_H__ */ #endif /* __CYTTSP_CORE_H__ */
This diff is collapsed.
This diff is collapsed.
...@@ -20,5 +20,6 @@ int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id, ...@@ -20,5 +20,6 @@ int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
struct regmap *regmap); struct regmap *regmap);
extern const struct dev_pm_ops goodix_berlin_pm_ops; extern const struct dev_pm_ops goodix_berlin_pm_ops;
extern const struct attribute_group *goodix_berlin_groups[];
#endif #endif
...@@ -64,6 +64,7 @@ static struct i2c_driver goodix_berlin_i2c_driver = { ...@@ -64,6 +64,7 @@ static struct i2c_driver goodix_berlin_i2c_driver = {
.name = "goodix-berlin-i2c", .name = "goodix-berlin-i2c",
.of_match_table = goodix_berlin_i2c_of_match, .of_match_table = goodix_berlin_i2c_of_match,
.pm = pm_sleep_ptr(&goodix_berlin_pm_ops), .pm = pm_sleep_ptr(&goodix_berlin_pm_ops),
.dev_groups = goodix_berlin_groups,
}, },
.probe = goodix_berlin_i2c_probe, .probe = goodix_berlin_i2c_probe,
.id_table = goodix_berlin_i2c_id, .id_table = goodix_berlin_i2c_id,
......
...@@ -169,6 +169,7 @@ static struct spi_driver goodix_berlin_spi_driver = { ...@@ -169,6 +169,7 @@ static struct spi_driver goodix_berlin_spi_driver = {
.name = "goodix-berlin-spi", .name = "goodix-berlin-spi",
.of_match_table = goodix_berlin_spi_of_match, .of_match_table = goodix_berlin_spi_of_match,
.pm = pm_sleep_ptr(&goodix_berlin_pm_ops), .pm = pm_sleep_ptr(&goodix_berlin_pm_ops),
.dev_groups = goodix_berlin_groups,
}, },
.probe = goodix_berlin_spi_probe, .probe = goodix_berlin_spi_probe,
.id_table = goodix_berlin_spi_ids, .id_table = goodix_berlin_spi_ids,
......
...@@ -470,7 +470,7 @@ static const struct hynitron_ts_chip_data cst3xx_data = { ...@@ -470,7 +470,7 @@ static const struct hynitron_ts_chip_data cst3xx_data = {
}; };
static const struct i2c_device_id hyn_tpd_id[] = { static const struct i2c_device_id hyn_tpd_id[] = {
{ .name = "hynitron_ts", 0 }, { .name = "hynitron_ts" },
{ /* sentinel */ }, { /* sentinel */ },
}; };
MODULE_DEVICE_TABLE(i2c, hyn_tpd_id); MODULE_DEVICE_TABLE(i2c, hyn_tpd_id);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment