Merge 5472d60c12 ("Merge tag 'trace-v6.18-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace") into android-mainline
Steps on the way to v6.18-rc1 Change-Id: I15e6b0829a5a7e0cea05d47fd6dd8abe60d919af Signed-off-by: Carlos Llamas <cmllamas@google.com>
This commit is contained in:
commit
b2de6741be
509 files changed
+21076
-8436
No files matched your search
@@ -23,3 +23,9 @@ Contact: Longfang Liu <liulongfang@huawei.com>
|
||||
Description: Read the live migration status of the vfio device.
|
||||
The contents of the state file reflects the migration state
|
||||
relative to those defined in the vfio_device_mig_state enum
|
||||
|
||||
What: /sys/kernel/debug/vfio/<device>/migration/features
|
||||
Date: Oct 2025
|
||||
KernelVersion: 6.18
|
||||
Contact: Cédric Le Goater <clg@redhat.com>
|
||||
Description: Read the migration features of the vfio device.
|
||||
@@ -103,6 +103,28 @@ properties:
|
||||
- compatible
|
||||
- "#pwm-cells"
|
||||
|
||||
touchscreen:
|
||||
type: object
|
||||
$ref: /schemas/input/touchscreen/touchscreen.yaml#
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: raspberrypi,firmware-ts
|
||||
|
||||
firmware:
|
||||
deprecated: true
|
||||
description: Phandle to RPi's firmware device node.
|
||||
|
||||
touchscreen-size-x: true
|
||||
touchscreen-size-y: true
|
||||
touchscreen-inverted-x: true
|
||||
touchscreen-inverted-y: true
|
||||
touchscreen-swapped-x-y: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- mboxes
|
||||
@@ -135,5 +157,11 @@ examples:
|
||||
compatible = "raspberrypi,firmware-poe-pwm";
|
||||
#pwm-cells = <2>;
|
||||
};
|
||||
|
||||
ts: touchscreen {
|
||||
compatible = "raspberrypi,firmware-ts";
|
||||
touchscreen-size-x = <800>;
|
||||
touchscreen-size-y = <480>;
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -16,6 +16,7 @@ description: |
|
||||
|
||||
allOf:
|
||||
- $ref: input.yaml#
|
||||
- $ref: touchscreen/touchscreen.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@@ -95,7 +96,7 @@ required:
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/awinic,aw86927.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Awinic AW86927 LRA Haptic IC
|
||||
|
||||
maintainers:
|
||||
- Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: awinic,aw86927
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reset-gpios
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
vibrator@5a {
|
||||
compatible = "awinic,aw86927";
|
||||
reg = <0x5a>;
|
||||
interrupts-extended = <&tlmm 101 IRQ_TYPE_EDGE_FALLING>;
|
||||
reset-gpios = <&tlmm 100 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
NXP LPC32xx Key Scan Interface
|
||||
|
||||
This binding is based on the matrix-keymap binding with the following
|
||||
changes:
|
||||
|
||||
Required Properties:
|
||||
- compatible: Should be "nxp,lpc3220-key"
|
||||
- reg: Physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: The interrupt number to the cpu.
|
||||
- clocks: phandle to clock controller plus clock-specifier pair
|
||||
- nxp,debounce-delay-ms: Debounce delay in ms
|
||||
- nxp,scan-delay-ms: Repeated scan period in ms
|
||||
- linux,keymap: the key-code to be reported when the key is pressed
|
||||
and released, see also
|
||||
Documentation/devicetree/bindings/input/matrix-keymap.txt
|
||||
|
||||
Note: keypad,num-rows and keypad,num-columns are required, and must be equal
|
||||
since LPC32xx only supports square matrices
|
||||
|
||||
Example:
|
||||
|
||||
key@40050000 {
|
||||
compatible = "nxp,lpc3220-key";
|
||||
reg = <0x40050000 0x1000>;
|
||||
clocks = <&clk LPC32XX_CLK_KEY>;
|
||||
interrupt-parent = <&sic1>;
|
||||
interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
|
||||
keypad,num-rows = <1>;
|
||||
keypad,num-columns = <1>;
|
||||
nxp,debounce-delay-ms = <3>;
|
||||
nxp,scan-delay-ms = <34>;
|
||||
linux,keymap = <0x00000002>;
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/nxp,lpc3220-key.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP LPC32xx Key Scan Interface
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nxp,lpc3220-key
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
nxp,debounce-delay-ms:
|
||||
description: Debounce delay in ms
|
||||
|
||||
nxp,scan-delay-ms:
|
||||
description: Repeated scan period in ms
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- nxp,debounce-delay-ms
|
||||
- nxp,scan-delay-ms
|
||||
- linux,keymap
|
||||
|
||||
allOf:
|
||||
- $ref: matrix-keymap.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/lpc32xx-clock.h>
|
||||
|
||||
key@40050000 {
|
||||
compatible = "nxp,lpc3220-key";
|
||||
reg = <0x40050000 0x1000>;
|
||||
clocks = <&clk LPC32XX_CLK_KEY>;
|
||||
interrupt-parent = <&sic1>;
|
||||
interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
|
||||
keypad,num-rows = <1>;
|
||||
keypad,num-columns = <1>;
|
||||
nxp,debounce-delay-ms = <3>;
|
||||
nxp,scan-delay-ms = <34>;
|
||||
linux,keymap = <0x00000002>;
|
||||
};
|
||||
@@ -10,9 +10,6 @@ maintainers:
|
||||
- Courtney Cavin <courtney.cavin@sonymobile.com>
|
||||
- Vinod Koul <vkoul@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: input.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
@@ -25,23 +22,40 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
debounce:
|
||||
description: |
|
||||
Time in microseconds that key must be pressed or
|
||||
released for state change interrupt to trigger.
|
||||
description:
|
||||
Time in microseconds that key must be pressed or released for state
|
||||
change interrupt to trigger.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
bias-pull-up:
|
||||
description: |
|
||||
Presence of this property indicates that the KPDPWR_N
|
||||
pin should be configured for pull up.
|
||||
description:
|
||||
Presence of this property indicates that the KPDPWR_N pin should be
|
||||
configured for pull up.
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
||||
wakeup-source:
|
||||
description:
|
||||
Button can wake-up the system. Only applicable for 'resin', 'pwrkey'
|
||||
always wakes the system by default.
|
||||
|
||||
linux,code:
|
||||
description: |
|
||||
The input key-code associated with the power key.
|
||||
Use the linux event codes defined in
|
||||
include/dt-bindings/input/linux-event-codes.h
|
||||
When property is omitted KEY_POWER is assumed.
|
||||
description:
|
||||
The input key-code associated with the power key. Use the linux event
|
||||
codes defined in include/dt-bindings/input/linux-event-codes.h.
|
||||
When property is omitted KEY_POWER is assumed.
|
||||
|
||||
allOf:
|
||||
- $ref: input.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,pm8941-pwrkey
|
||||
- qcom,pmk8350-pwrkey
|
||||
then:
|
||||
properties:
|
||||
wakeup-source: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
This binding is based on the matrix-keymap binding with the following
|
||||
changes:
|
||||
|
||||
keypad,num-rows and keypad,num-columns are required.
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,tca8418"
|
||||
- reg: the I2C address
|
||||
- interrupts: IRQ line number, should trigger on falling edge
|
||||
- linux,keymap: Keys definitions, see keypad-matrix.
|
||||
@@ -0,0 +1,61 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/ti,tca8418.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: TI TCA8418 I2C/SMBus keypad scanner
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,tca8418
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- $ref: matrix-keymap.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
keypad@34 {
|
||||
compatible = "ti,tca8418";
|
||||
reg = <0x34>;
|
||||
interrupt-parent = <&gpio5>;
|
||||
interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
|
||||
keypad,num-rows = <4>;
|
||||
keypad,num-columns = <4>;
|
||||
linux,keymap = < MATRIX_KEY(0x00, 0x01, BTN_0)
|
||||
MATRIX_KEY(0x00, 0x00, BTN_1)
|
||||
MATRIX_KEY(0x01, 0x01, BTN_2)
|
||||
MATRIX_KEY(0x01, 0x00, BTN_3)
|
||||
MATRIX_KEY(0x02, 0x00, BTN_4)
|
||||
MATRIX_KEY(0x00, 0x03, BTN_5)
|
||||
MATRIX_KEY(0x00, 0x02, BTN_6)
|
||||
MATRIX_KEY(0x01, 0x03, BTN_7)
|
||||
MATRIX_KEY(0x01, 0x02, BTN_8)
|
||||
MATRIX_KEY(0x02, 0x02, BTN_9)
|
||||
>;
|
||||
};
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
* Rohm BU21013 Touch Screen
|
||||
|
||||
Required properties:
|
||||
- compatible : "rohm,bu21013_tp"
|
||||
- reg : I2C device address
|
||||
- reset-gpios : GPIO pin enabling (selecting) chip (CS)
|
||||
- interrupt-parent : the phandle for the gpio controller
|
||||
- interrupts : (gpio) interrupt to which the chip is connected
|
||||
|
||||
Optional properties:
|
||||
- touch-gpios : GPIO pin registering a touch event
|
||||
- <supply_name>-supply : Phandle to a regulator supply
|
||||
- touchscreen-size-x : General touchscreen binding, see [1].
|
||||
- touchscreen-size-y : 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:
|
||||
- rohm,touch-max-x : Maximum outward permitted limit in the X axis
|
||||
- rohm,touch-max-y : Maximum outward permitted limit in the Y axis
|
||||
- rohm,flip-x : Flip touch coordinates on the X axis
|
||||
- rohm,flip-y : Flip touch coordinates on the Y axis
|
||||
|
||||
Example:
|
||||
|
||||
i2c@80110000 {
|
||||
bu21013_tp@5c {
|
||||
compatible = "rohm,bu21013_tp";
|
||||
reg = <0x5c>;
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts <&20 IRQ_TYPE_LEVEL_LOW>;
|
||||
touch-gpio = <&gpio2 20 GPIO_ACTIVE_LOW>;
|
||||
avdd-supply = <&ab8500_ldo_aux1_reg>;
|
||||
|
||||
touchscreen-size-x = <384>;
|
||||
touchscreen-size-y = <704>;
|
||||
touchscreen-inverted-y;
|
||||
};
|
||||
};
|
||||
@@ -9,27 +9,35 @@ title: EETI EXC3000 series touchscreen controller
|
||||
maintainers:
|
||||
- Dmitry Torokhov <dmitry.torokhov@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: eeti,exc3000
|
||||
- const: eeti,exc80h60
|
||||
- const: eeti,exc80h84
|
||||
- const: eeti,egalax_ts # Do NOT use for new binding
|
||||
- const: eeti,exc3000-i2c
|
||||
deprecated: true
|
||||
- items:
|
||||
- enum:
|
||||
- eeti,exc81w32
|
||||
- const: eeti,exc80h84
|
||||
reg:
|
||||
const: 0x2a
|
||||
enum: [0x4, 0xa, 0x2a]
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
wakeup-gpios:
|
||||
maxItems: 1
|
||||
vdd-supply:
|
||||
description: Power supply regulator for the chip
|
||||
attn-gpios:
|
||||
deprecated: true
|
||||
maxItems: 1
|
||||
description: Phandle to a GPIO to check whether interrupt is still
|
||||
latched. This is necessary for platforms that lack
|
||||
support for level-triggered IRQs.
|
||||
touchscreen-size-x: true
|
||||
touchscreen-size-y: true
|
||||
touchscreen-inverted-x: true
|
||||
@@ -40,11 +48,33 @@ required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- touchscreen-size-x
|
||||
- touchscreen-size-y
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
not:
|
||||
contains:
|
||||
enum:
|
||||
- eeti,egalax_ts
|
||||
- eeti,exc3000-i2c
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
const: 0x2a
|
||||
|
||||
wakeup-gpios: false
|
||||
|
||||
attn-gpios: false
|
||||
|
||||
required:
|
||||
- touchscreen-size-x
|
||||
- touchscreen-size-y
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include "dt-bindings/interrupt-controller/irq.h"
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
Bindings for EETI touchscreen controller
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "eeti,exc3000-i2c"
|
||||
- reg: I2C address of the chip. Should be set to <0xa>
|
||||
- interrupts: interrupt to which the chip is connected
|
||||
|
||||
Optional properties:
|
||||
- attn-gpios: A handle to a GPIO to check whether interrupt is still
|
||||
latched. This is necessary for platforms that lack
|
||||
support for level-triggered IRQs.
|
||||
|
||||
The following optional properties described in touchscreen.txt are
|
||||
also supported:
|
||||
|
||||
- touchscreen-inverted-x
|
||||
- touchscreen-inverted-y
|
||||
- touchscreen-swapped-x-y
|
||||
|
||||
Example:
|
||||
|
||||
i2c-master {
|
||||
touchscreen@a {
|
||||
compatible = "eeti,exc3000-i2c";
|
||||
reg = <0xa>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <123 IRQ_TYPE_EDGE_RISING>;
|
||||
attn-gpios = <&gpio 123 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
* EETI eGalax Multiple Touch Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "eeti,egalax_ts"
|
||||
- reg: i2c slave address
|
||||
- interrupts: touch controller interrupt
|
||||
- wakeup-gpios: the gpio pin to be used for waking up the controller
|
||||
and also used as irq pin
|
||||
|
||||
Example:
|
||||
|
||||
touchscreen@4 {
|
||||
compatible = "eeti,egalax_ts";
|
||||
reg = <0x04>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
|
||||
wakeup-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
@@ -62,6 +62,20 @@ properties:
|
||||
description: Number of data samples which are averaged for each read.
|
||||
enum: [ 1, 4, 8, 16, 32 ]
|
||||
|
||||
debounce-delay-us:
|
||||
description: |
|
||||
Minimum duration in microseconds a signal must remain stable
|
||||
to be considered valid.
|
||||
|
||||
Drivers must convert this value to IPG clock cycles and map
|
||||
it to one of the four discrete thresholds exposed by the
|
||||
TSC_DEBUG_MODE2 register:
|
||||
|
||||
0: 8191 IPG cycles
|
||||
1: 4095 IPG cycles
|
||||
2: 2047 IPG cycles
|
||||
3: 1023 IPG cycles
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -62,7 +62,6 @@ additionalProperties: false
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/himax,hx852es.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Himax HX852x(ES) touch panel controller
|
||||
|
||||
maintainers:
|
||||
- Stephan Gerhold <stephan@gerhold.net>
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- himax,hx8525e
|
||||
- himax,hx8526e
|
||||
- himax,hx8527e
|
||||
- const: himax,hx852es
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description: Touch Screen Interrupt (TSIX), active low
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
description: External Reset (XRES), active low
|
||||
|
||||
vcca-supply:
|
||||
description: Analog power supply (VCCA)
|
||||
|
||||
vccd-supply:
|
||||
description: Digital power supply (VCCD)
|
||||
|
||||
touchscreen-inverted-x: true
|
||||
touchscreen-inverted-y: true
|
||||
touchscreen-size-x: true
|
||||
touchscreen-size-y: true
|
||||
touchscreen-swapped-x-y: true
|
||||
|
||||
linux,keycodes:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- reset-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
touchscreen@48 {
|
||||
compatible = "himax,hx8527e", "himax,hx852es";
|
||||
reg = <0x48>;
|
||||
interrupt-parent = <&tlmm>;
|
||||
interrupts = <13 IRQ_TYPE_LEVEL_LOW>;
|
||||
reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>;
|
||||
vcca-supply = <®_ts_vcca>;
|
||||
vccd-supply = <&pm8916_l6>;
|
||||
linux,keycodes = <KEY_BACK KEY_HOMEPAGE KEY_APPSELECT>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -0,0 +1,65 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/hynitron,cst816x.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Hynitron CST816x Series Capacitive Touch controller
|
||||
|
||||
maintainers:
|
||||
- Oleh Kuzhylnyi <kuzhylol@gmail.com>
|
||||
|
||||
description: |
|
||||
Bindings for CST816x high performance self-capacitance touch chip series
|
||||
with single point gesture and real two-point operation.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- hynitron,cst816s
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
linux,keycodes:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: Slide up gesture
|
||||
- description: Slide down gesture
|
||||
- description: Slide left gesture
|
||||
- description: Slide right gesture
|
||||
- description: Long press gesture
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/linux-event-codes.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
touchscreen@15 {
|
||||
compatible = "hynitron,cst816s";
|
||||
reg = <0x15>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <4 IRQ_TYPE_EDGE_RISING>;
|
||||
reset-gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
|
||||
linux,keycodes = <KEY_UP>, <KEY_DOWN>, <KEY_LEFT>, <KEY_RIGHT>,
|
||||
<BTN_TOOL_TRIPLETAP>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -35,6 +35,7 @@ properties:
|
||||
|
||||
linux,keycodes:
|
||||
description: Keycodes for the touch keys
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
|
||||
touchscreen-size-x: true
|
||||
@@ -87,5 +88,22 @@ examples:
|
||||
touchscreen-inverted-y;
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/input/linux-event-codes.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
touchscreen@50 {
|
||||
compatible = "imagis,ist3032c";
|
||||
reg = <0x50>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <72 IRQ_TYPE_EDGE_FALLING>;
|
||||
vdd-supply = <&ldo2>;
|
||||
touchscreen-size-x = <480>;
|
||||
touchscreen-size-y = <800>;
|
||||
linux,keycodes = <KEY_APPSELECT>, <KEY_BACK>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -1,17 +0,0 @@
|
||||
* MAXI MAX11801 Resistive touch screen controller with i2c interface
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "maxim,max11801"
|
||||
- reg: i2c slave address
|
||||
- interrupts: touch controller interrupt
|
||||
|
||||
Example:
|
||||
|
||||
&i2c1 {
|
||||
max11801: touchscreen@48 {
|
||||
compatible = "maxim,max11801";
|
||||
reg = <0x48>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/maxim,max11801.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MAXI MAX11801 Resistive touch screen controller with i2c interface
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: maxim,max11801
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
touchscreen@48 {
|
||||
compatible = "maxim,max11801";
|
||||
reg = <0x48>;
|
||||
interrupt-parent = <&gpio3>;
|
||||
interrupts = <31 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
Raspberry Pi firmware based 7" touchscreen
|
||||
=====================================
|
||||
|
||||
Required properties:
|
||||
- compatible: "raspberrypi,firmware-ts"
|
||||
|
||||
Optional properties:
|
||||
- firmware: Reference to RPi's firmware device node
|
||||
- touchscreen-size-x: See touchscreen.txt
|
||||
- touchscreen-size-y: See touchscreen.txt
|
||||
- touchscreen-inverted-x: See touchscreen.txt
|
||||
- touchscreen-inverted-y: See touchscreen.txt
|
||||
- touchscreen-swapped-x-y: See touchscreen.txt
|
||||
|
||||
Example:
|
||||
|
||||
firmware: firmware-rpi {
|
||||
compatible = "raspberrypi,bcm2835-firmware";
|
||||
mboxes = <&mailbox>;
|
||||
|
||||
ts: touchscreen {
|
||||
compatible = "raspberrypi,firmware-ts";
|
||||
touchscreen-size-x = <800>;
|
||||
touchscreen-size-y = <480>;
|
||||
};
|
||||
};
|
||||
@@ -55,7 +55,7 @@ properties:
|
||||
touchscreen-min-pressure: true
|
||||
touchscreen-x-plate-ohms: true
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/rohm,bu21013.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rohm BU21013 touchscreen
|
||||
|
||||
description:
|
||||
Rohm BU21013 I2C driven touchscreen controller.
|
||||
|
||||
maintainers:
|
||||
- Dario Binacchi <dario.binacchi@amarulasolutions.com>
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rohm,bu21013_tp
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
touch-gpios:
|
||||
maxItems: 1
|
||||
description: GPIO registering a touch event.
|
||||
|
||||
avdd-supply:
|
||||
description: Analogic power supply
|
||||
|
||||
rohm,touch-max-x:
|
||||
deprecated: true
|
||||
description: Maximum value on the X axis.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
rohm,touch-max-y:
|
||||
deprecated: true
|
||||
description: Maximum value on the Y axis.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
rohm,flip-x:
|
||||
deprecated: true
|
||||
description: Flip touch coordinates on the X axis
|
||||
type: boolean
|
||||
|
||||
rohm,flip-y:
|
||||
deprecated: true
|
||||
description: Flip touch coordinates on the Y axis
|
||||
type: boolean
|
||||
|
||||
touchscreen-inverted-x: true
|
||||
touchscreen-inverted-y: true
|
||||
touchscreen-size-x: true
|
||||
touchscreen-size-y: true
|
||||
touchscreen-swapped-x-y: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reset-gpios
|
||||
- interrupts
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
touchscreen@5c {
|
||||
compatible = "rohm,bu21013_tp";
|
||||
reg = <0x5c>;
|
||||
|
||||
interrupt-parent = <&gpio2>;
|
||||
interrupts = <0x20 IRQ_TYPE_LEVEL_LOW>;
|
||||
reset-gpios = <&gpio2 19 GPIO_ACTIVE_LOW>;
|
||||
touch-gpios = <&gpio2 20 GPIO_ACTIVE_LOW>;
|
||||
avdd-supply = <&ab8500_ldo_aux1_reg>;
|
||||
|
||||
touchscreen-size-x = <384>;
|
||||
touchscreen-size-y = <704>;
|
||||
touchscreen-inverted-y;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/semtech,sx8654.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Semtech SX8654 I2C Touchscreen Controller
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- semtech,sx8650
|
||||
- semtech,sx8654
|
||||
- semtech,sx8655
|
||||
- semtech,sx8656
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
touchscreen@48 {
|
||||
compatible = "semtech,sx8654";
|
||||
reg = <0x48>;
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
|
||||
reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
@@ -1,23 +0,0 @@
|
||||
* Semtech SX8654 I2C Touchscreen Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: must be one of the following, depending on the model:
|
||||
"semtech,sx8650"
|
||||
"semtech,sx8654"
|
||||
"semtech,sx8655"
|
||||
"semtech,sx8656"
|
||||
- reg: i2c slave address
|
||||
- interrupts: touch controller interrupt
|
||||
|
||||
Optional properties:
|
||||
- reset-gpios: GPIO specification for the NRST input
|
||||
|
||||
Example:
|
||||
|
||||
sx8654@48 {
|
||||
compatible = "semtech,sx8654";
|
||||
reg = <0x48>;
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
|
||||
reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
+3
-1
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/ti.tsc2007.yaml#
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/ti,tsc2007.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments tsc2007 touchscreen controller
|
||||
@@ -26,6 +26,8 @@ properties:
|
||||
|
||||
pendown-gpio: true
|
||||
|
||||
wakeup-source: true
|
||||
|
||||
ti,max-rt:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: maximum pressure.
|
||||
@@ -1 +0,0 @@
|
||||
See touchscreen.yaml
|
||||
@@ -206,6 +206,10 @@ properties:
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
debounce-delay-us:
|
||||
description: Minimum duration in microseconds a signal must remain stable
|
||||
to be considered valid.
|
||||
|
||||
dependencies:
|
||||
touchscreen-size-x: [ touchscreen-size-y ]
|
||||
touchscreen-size-y: [ touchscreen-size-x ]
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/zeitec,zet6223.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Zeitec ZET6223 touchscreen controller
|
||||
|
||||
description:
|
||||
Zeitec ZET6223 I2C driven touchscreen controller.
|
||||
|
||||
maintainers:
|
||||
- Dario Binacchi <dario.binacchi@amarulasolutions.com>
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- zeitec,zet6223
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
vio-supply:
|
||||
description: 1.8V or 3.3V VIO supply.
|
||||
|
||||
vcc-supply:
|
||||
description: 3.3V VCC supply.
|
||||
|
||||
touchscreen-inverted-x: true
|
||||
touchscreen-inverted-y: true
|
||||
touchscreen-size-x: true
|
||||
touchscreen-size-y: true
|
||||
touchscreen-swapped-x-y: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
touchscreen@76 {
|
||||
compatible = "zeitec,zet6223";
|
||||
reg = <0x76>;
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>;
|
||||
};
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
Zeitec ZET6223 I2C touchscreen controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "zeitec,zet6223"
|
||||
- reg : I2C slave address of the chip (0x76)
|
||||
- interrupts : interrupt specification for the zet6223 interrupt
|
||||
|
||||
Optional properties:
|
||||
|
||||
- vio-supply : Specification for VIO supply (1.8V or 3.3V,
|
||||
depending on system interface needs).
|
||||
- vcc-supply : Specification for 3.3V VCC supply.
|
||||
- touchscreen-size-x : See touchscreen.txt
|
||||
- touchscreen-size-y : See touchscreen.txt
|
||||
- touchscreen-inverted-x : See touchscreen.txt
|
||||
- touchscreen-inverted-y : See touchscreen.txt
|
||||
- touchscreen-swapped-x-y : See touchscreen.txt
|
||||
|
||||
Example:
|
||||
|
||||
i2c@00000000 {
|
||||
|
||||
zet6223: touchscreen@76 {
|
||||
compatible = "zeitec,zet6223";
|
||||
reg = <0x76>;
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,64 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mailbox/mediatek,mt8196-gpueb-mbox.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek MFlexGraphics GPUEB Mailbox Controller
|
||||
|
||||
maintainers:
|
||||
- Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt8196-gpueb-mbox
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: mailbox data registers
|
||||
- description: mailbox control registers
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: data
|
||||
- const: ctl
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: main clock of the GPUEB MCU
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: fires when a new message is received
|
||||
|
||||
"#mbox-cells":
|
||||
const: 1
|
||||
description:
|
||||
The number of the mailbox channel.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- clocks
|
||||
- interrupts
|
||||
- "#mbox-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/mediatek,mt8196-clock.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
mailbox@4b09fd80 {
|
||||
compatible = "mediatek,mt8196-gpueb-mbox";
|
||||
reg = <0x4b09fd80 0x280>,
|
||||
<0x4b170000 0x7c>;
|
||||
reg-names = "data", "ctl";
|
||||
clocks = <&topckgen CLK_TOP_MFG_EB>;
|
||||
interrupts = <GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH 0>;
|
||||
#mbox-cells = <1>;
|
||||
};
|
||||
@@ -15,8 +15,13 @@ description:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: qcom,x1e80100-cpucp-mbox
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,glymur-cpucp-mbox
|
||||
- const: qcom,x1e80100-cpucp-mbox
|
||||
- enum:
|
||||
- qcom,x1e80100-cpucp-mbox
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
||||
+8
-2
@@ -924,7 +924,7 @@ R: Pali Rohár <pali@kernel.org>
|
||||
F: drivers/input/mouse/alps.*
|
||||
|
||||
ALTERA MAILBOX DRIVER
|
||||
M: Mun Yew Tham <mun.yew.tham@intel.com>
|
||||
M: Tien Sung Ang <tiensung.ang@altera.com>
|
||||
S: Maintained
|
||||
F: drivers/mailbox/mailbox-altera.c
|
||||
|
||||
@@ -11168,6 +11168,13 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/input/touchscreen/himax,hx83112b.yaml
|
||||
F: drivers/input/touchscreen/himax_hx83112b.c
|
||||
|
||||
HIMAX HX852X TOUCHSCREEN DRIVER
|
||||
M: Stephan Gerhold <stephan@gerhold.net>
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/input/touchscreen/himax,hx852es.yaml
|
||||
F: drivers/input/touchscreen/himax_hx852x.c
|
||||
|
||||
HIPPI
|
||||
M: Jes Sorensen <jes@trained-monkey.org>
|
||||
S: Maintained
|
||||
@@ -20131,7 +20138,6 @@ R: Alexander Shishkin <alexander.shishkin@linux.intel.com>
|
||||
R: Jiri Olsa <jolsa@kernel.org>
|
||||
R: Ian Rogers <irogers@google.com>
|
||||
R: Adrian Hunter <adrian.hunter@intel.com>
|
||||
R: "Liang, Kan" <kan.liang@linux.intel.com>
|
||||
L: linux-perf-users@vger.kernel.org
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
|
||||
@@ -25,6 +25,7 @@ endif
|
||||
KBUILD_CFLAGS_DECOMPRESSOR := $(CLANG_FLAGS) -m64 -O2 -mpacked-stack -std=gnu11
|
||||
KBUILD_CFLAGS_DECOMPRESSOR += -DDISABLE_BRANCH_PROFILING -D__NO_FORTIFY
|
||||
KBUILD_CFLAGS_DECOMPRESSOR += -D__DECOMPRESSOR
|
||||
KBUILD_CFLAGS_DECOMPRESSOR += -Wno-pointer-sign
|
||||
KBUILD_CFLAGS_DECOMPRESSOR += -fno-delete-null-pointer-checks -msoft-float -mbackchain
|
||||
KBUILD_CFLAGS_DECOMPRESSOR += -fno-asynchronous-unwind-tables
|
||||
KBUILD_CFLAGS_DECOMPRESSOR += -ffreestanding
|
||||
|
||||
@@ -27,7 +27,7 @@ static inline unsigned long __hypfs_sprp_diag304(void *data, unsigned long cmd)
|
||||
{
|
||||
union register_pair r1 = { .even = virt_to_phys(data), };
|
||||
|
||||
asm volatile("diag %[r1],%[r3],0x304\n"
|
||||
asm volatile("diag %[r1],%[r3],0x304"
|
||||
: [r1] "+&d" (r1.pair)
|
||||
: [r3] "d" (cmd)
|
||||
: "memory");
|
||||
|
||||
@@ -143,7 +143,7 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid,
|
||||
" lghi 2,0\n" /* 0 into gr2 */
|
||||
" .insn rre,0xb2af0000,0,0\n" /* PQAP(TAPQ) */
|
||||
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
|
||||
" lgr %[reg2],2\n" /* gr2 into reg2 */
|
||||
" lgr %[reg2],2" /* gr2 into reg2 */
|
||||
: [reg1] "=&d" (reg1.value), [reg2] "=&d" (reg2)
|
||||
: [qid] "d" (qid)
|
||||
: "cc", "0", "1", "2");
|
||||
@@ -186,7 +186,7 @@ static inline struct ap_queue_status ap_rapq(ap_qid_t qid, int fbit)
|
||||
asm volatile(
|
||||
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
|
||||
" .insn rre,0xb2af0000,0,0\n" /* PQAP(RAPQ) */
|
||||
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
|
||||
" lgr %[reg1],1" /* gr1 (status) into reg1 */
|
||||
: [reg1] "=&d" (reg1.value)
|
||||
: [reg0] "d" (reg0)
|
||||
: "cc", "0", "1");
|
||||
@@ -211,7 +211,7 @@ static inline struct ap_queue_status ap_zapq(ap_qid_t qid, int fbit)
|
||||
asm volatile(
|
||||
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
|
||||
" .insn rre,0xb2af0000,0,0\n" /* PQAP(ZAPQ) */
|
||||
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
|
||||
" lgr %[reg1],1" /* gr1 (status) into reg1 */
|
||||
: [reg1] "=&d" (reg1.value)
|
||||
: [reg0] "d" (reg0)
|
||||
: "cc", "0", "1");
|
||||
@@ -315,7 +315,7 @@ static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
|
||||
" lgr 1,%[reg1]\n" /* irq ctrl into gr1 */
|
||||
" lgr 2,%[reg2]\n" /* ni addr into gr2 */
|
||||
" .insn rre,0xb2af0000,0,0\n" /* PQAP(AQIC) */
|
||||
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
|
||||
" lgr %[reg1],1" /* gr1 (status) into reg1 */
|
||||
: [reg1] "+&d" (reg1.value)
|
||||
: [reg0] "d" (reg0), [reg2] "d" (reg2)
|
||||
: "cc", "memory", "0", "1", "2");
|
||||
@@ -363,7 +363,7 @@ static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
|
||||
" lgr 1,%[reg1]\n" /* qact in info into gr1 */
|
||||
" .insn rre,0xb2af0000,0,0\n" /* PQAP(QACT) */
|
||||
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
|
||||
" lgr %[reg2],2\n" /* qact out info into reg2 */
|
||||
" lgr %[reg2],2" /* qact out info into reg2 */
|
||||
: [reg1] "+&d" (reg1.value), [reg2] "=&d" (reg2)
|
||||
: [reg0] "d" (reg0)
|
||||
: "cc", "0", "1", "2");
|
||||
@@ -388,7 +388,7 @@ static inline struct ap_queue_status ap_bapq(ap_qid_t qid)
|
||||
asm volatile(
|
||||
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
|
||||
" .insn rre,0xb2af0000,0,0\n" /* PQAP(BAPQ) */
|
||||
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
|
||||
" lgr %[reg1],1" /* gr1 (status) into reg1 */
|
||||
: [reg1] "=&d" (reg1.value)
|
||||
: [reg0] "d" (reg0)
|
||||
: "cc", "0", "1");
|
||||
@@ -416,7 +416,7 @@ static inline struct ap_queue_status ap_aapq(ap_qid_t qid, unsigned int sec_idx)
|
||||
" lgr 0,%[reg0]\n" /* qid arg into gr0 */
|
||||
" lgr 2,%[reg2]\n" /* secret index into gr2 */
|
||||
" .insn rre,0xb2af0000,0,0\n" /* PQAP(AAPQ) */
|
||||
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
|
||||
" lgr %[reg1],1" /* gr1 (status) into reg1 */
|
||||
: [reg1] "=&d" (reg1.value)
|
||||
: [reg0] "d" (reg0), [reg2] "d" (reg2)
|
||||
: "cc", "0", "1", "2");
|
||||
@@ -453,7 +453,7 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
|
||||
" lgr 0,%[reg0]\n" /* qid param in gr0 */
|
||||
"0: .insn rre,0xb2ad0000,%[nqap_r1],%[nqap_r2]\n"
|
||||
" brc 2,0b\n" /* handle partial completion */
|
||||
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
|
||||
" lgr %[reg1],1" /* gr1 (status) into reg1 */
|
||||
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value),
|
||||
[nqap_r2] "+&d" (nqap_r2.pair)
|
||||
: [nqap_r1] "d" (nqap_r1.pair)
|
||||
@@ -518,7 +518,7 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
|
||||
" brc 6,0b\n" /* handle partial complete */
|
||||
"2: lgr %[reg0],0\n" /* gr0 (qid + info) into reg0 */
|
||||
" lgr %[reg1],1\n" /* gr1 (status) into reg1 */
|
||||
" lgr %[reg2],2\n" /* gr2 (res length) into reg2 */
|
||||
" lgr %[reg2],2" /* gr2 (res length) into reg2 */
|
||||
: [reg0] "+&d" (reg0), [reg1] "=&d" (reg1.value),
|
||||
[reg2] "=&d" (reg2), [rp1] "+&d" (rp1.pair),
|
||||
[rp2] "+&d" (rp2.pair)
|
||||
|
||||
@@ -17,7 +17,7 @@ static __always_inline int __atomic_read(const int *ptr)
|
||||
int val;
|
||||
|
||||
asm volatile(
|
||||
" l %[val],%[ptr]\n"
|
||||
" l %[val],%[ptr]"
|
||||
: [val] "=d" (val) : [ptr] "R" (*ptr));
|
||||
return val;
|
||||
}
|
||||
@@ -26,11 +26,11 @@ static __always_inline void __atomic_set(int *ptr, int val)
|
||||
{
|
||||
if (__builtin_constant_p(val) && val >= S16_MIN && val <= S16_MAX) {
|
||||
asm volatile(
|
||||
" mvhi %[ptr],%[val]\n"
|
||||
" mvhi %[ptr],%[val]"
|
||||
: [ptr] "=Q" (*ptr) : [val] "K" (val));
|
||||
} else {
|
||||
asm volatile(
|
||||
" st %[val],%[ptr]\n"
|
||||
" st %[val],%[ptr]"
|
||||
: [ptr] "=R" (*ptr) : [val] "d" (val));
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ static __always_inline long __atomic64_read(const long *ptr)
|
||||
long val;
|
||||
|
||||
asm volatile(
|
||||
" lg %[val],%[ptr]\n"
|
||||
" lg %[val],%[ptr]"
|
||||
: [val] "=d" (val) : [ptr] "RT" (*ptr));
|
||||
return val;
|
||||
}
|
||||
@@ -49,11 +49,11 @@ static __always_inline void __atomic64_set(long *ptr, long val)
|
||||
{
|
||||
if (__builtin_constant_p(val) && val >= S16_MIN && val <= S16_MAX) {
|
||||
asm volatile(
|
||||
" mvghi %[ptr],%[val]\n"
|
||||
" mvghi %[ptr],%[val]"
|
||||
: [ptr] "=Q" (*ptr) : [val] "K" (val));
|
||||
} else {
|
||||
asm volatile(
|
||||
" stg %[val],%[ptr]\n"
|
||||
" stg %[val],%[ptr]"
|
||||
: [ptr] "=RT" (*ptr) : [val] "d" (val));
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ static __always_inline op_type op_name(op_type val, op_type *ptr) \
|
||||
op_type old; \
|
||||
\
|
||||
asm volatile( \
|
||||
op_string " %[old],%[val],%[ptr]\n" \
|
||||
op_string " %[old],%[val],%[ptr]" \
|
||||
op_barrier \
|
||||
: [old] "=d" (old), [ptr] "+QS" (*ptr) \
|
||||
: [val] "d" (val) : "cc", "memory"); \
|
||||
@@ -75,7 +75,7 @@ static __always_inline op_type op_name(op_type val, op_type *ptr) \
|
||||
|
||||
#define __ATOMIC_OPS(op_name, op_type, op_string) \
|
||||
__ATOMIC_OP(op_name, op_type, op_string, "") \
|
||||
__ATOMIC_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n")
|
||||
__ATOMIC_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0")
|
||||
|
||||
__ATOMIC_OPS(__atomic_add, int, "laa")
|
||||
__ATOMIC_OPS(__atomic_and, int, "lan")
|
||||
@@ -94,14 +94,14 @@ __ATOMIC_OPS(__atomic64_xor, long, "laxg")
|
||||
static __always_inline void op_name(op_type val, op_type *ptr) \
|
||||
{ \
|
||||
asm volatile( \
|
||||
op_string " %[ptr],%[val]\n" \
|
||||
op_string " %[ptr],%[val]" \
|
||||
op_barrier \
|
||||
: [ptr] "+QS" (*ptr) : [val] "i" (val) : "cc", "memory");\
|
||||
}
|
||||
|
||||
#define __ATOMIC_CONST_OPS(op_name, op_type, op_string) \
|
||||
__ATOMIC_CONST_OP(op_name, op_type, op_string, "") \
|
||||
__ATOMIC_CONST_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n")
|
||||
__ATOMIC_CONST_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0")
|
||||
|
||||
__ATOMIC_CONST_OPS(__atomic_add_const, int, "asi")
|
||||
__ATOMIC_CONST_OPS(__atomic64_add_const, long, "agsi")
|
||||
@@ -179,7 +179,7 @@ static __always_inline bool op_name(op_type val, op_type *ptr) \
|
||||
int cc; \
|
||||
\
|
||||
asm volatile( \
|
||||
op_string " %[tmp],%[val],%[ptr]\n" \
|
||||
op_string " %[tmp],%[val],%[ptr]" \
|
||||
op_barrier \
|
||||
: "=@cc" (cc), [tmp] "=d" (tmp), [ptr] "+QS" (*ptr) \
|
||||
: [val] "d" (val) \
|
||||
@@ -189,7 +189,7 @@ static __always_inline bool op_name(op_type val, op_type *ptr) \
|
||||
|
||||
#define __ATOMIC_TEST_OPS(op_name, op_type, op_string) \
|
||||
__ATOMIC_TEST_OP(op_name, op_type, op_string, "") \
|
||||
__ATOMIC_TEST_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n")
|
||||
__ATOMIC_TEST_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0")
|
||||
|
||||
__ATOMIC_TEST_OPS(__atomic_add_and_test, int, "laal")
|
||||
__ATOMIC_TEST_OPS(__atomic64_add_and_test, long, "laalg")
|
||||
@@ -203,7 +203,7 @@ static __always_inline bool op_name(op_type val, op_type *ptr) \
|
||||
int cc; \
|
||||
\
|
||||
asm volatile( \
|
||||
op_string " %[ptr],%[val]\n" \
|
||||
op_string " %[ptr],%[val]" \
|
||||
op_barrier \
|
||||
: "=@cc" (cc), [ptr] "+QS" (*ptr) \
|
||||
: [val] "i" (val) \
|
||||
@@ -213,7 +213,7 @@ static __always_inline bool op_name(op_type val, op_type *ptr) \
|
||||
|
||||
#define __ATOMIC_CONST_TEST_OPS(op_name, op_type, op_string) \
|
||||
__ATOMIC_CONST_TEST_OP(op_name, op_type, op_string, "") \
|
||||
__ATOMIC_CONST_TEST_OP(op_name##_barrier, op_type, op_string, "bcr 14,0\n")
|
||||
__ATOMIC_CONST_TEST_OP(op_name##_barrier, op_type, op_string, "\nbcr 14,0")
|
||||
|
||||
__ATOMIC_CONST_TEST_OPS(__atomic_add_const_and_test, int, "alsi")
|
||||
__ATOMIC_CONST_TEST_OPS(__atomic64_add_const_and_test, long, "algsi")
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
#ifdef MARCH_HAS_Z196_FEATURES
|
||||
/* Fast-BCR without checkpoint synchronization */
|
||||
#define __ASM_BCR_SERIALIZE "bcr 14,0\n"
|
||||
#define __ASM_BCR_SERIALIZE "bcr 14,0"
|
||||
#else
|
||||
#define __ASM_BCR_SERIALIZE "bcr 15,0\n"
|
||||
#define __ASM_BCR_SERIALIZE "bcr 15,0"
|
||||
#endif
|
||||
|
||||
static __always_inline void bcr_serialize(void)
|
||||
@@ -69,12 +69,12 @@ static inline unsigned long array_index_mask_nospec(unsigned long index,
|
||||
|
||||
if (__builtin_constant_p(size) && size > 0) {
|
||||
asm(" clgr %2,%1\n"
|
||||
" slbgr %0,%0\n"
|
||||
" slbgr %0,%0"
|
||||
:"=d" (mask) : "d" (size-1), "d" (index) :"cc");
|
||||
return mask;
|
||||
}
|
||||
asm(" clgr %1,%2\n"
|
||||
" slbgr %0,%0\n"
|
||||
" slbgr %0,%0"
|
||||
:"=d" (mask) : "d" (size), "d" (index) :"cc");
|
||||
return ~mask;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ static __always_inline bool arch_test_bit(unsigned long nr, const volatile unsig
|
||||
addr += (nr ^ (BITS_PER_LONG - BITS_PER_BYTE)) / BITS_PER_BYTE;
|
||||
mask = 1UL << (nr & (BITS_PER_BYTE - 1));
|
||||
asm volatile(
|
||||
" tm %[addr],%[mask]\n"
|
||||
" tm %[addr],%[mask]"
|
||||
: "=@cc" (cc)
|
||||
: [addr] "Q" (*addr), [mask] "I" (mask)
|
||||
);
|
||||
|
||||
@@ -27,7 +27,7 @@ static inline __wsum cksm(const void *buff, int len, __wsum sum)
|
||||
kmsan_check_memory(buff, len);
|
||||
asm volatile(
|
||||
"0: cksm %[sum],%[rp]\n"
|
||||
" jo 0b\n"
|
||||
" jo 0b"
|
||||
: [sum] "+&d" (sum), [rp] "+&d" (rp.pair) : : "cc", "memory");
|
||||
return sum;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ void __cmpxchg_called_with_bad_pointer(void);
|
||||
static __always_inline u32 __cs_asm(u64 ptr, u32 old, u32 new)
|
||||
{
|
||||
asm volatile(
|
||||
" cs %[old],%[new],%[ptr]\n"
|
||||
" cs %[old],%[new],%[ptr]"
|
||||
: [old] "+d" (old), [ptr] "+Q" (*(u32 *)ptr)
|
||||
: [new] "d" (new)
|
||||
: "memory", "cc");
|
||||
@@ -28,7 +28,7 @@ static __always_inline u32 __cs_asm(u64 ptr, u32 old, u32 new)
|
||||
static __always_inline u64 __csg_asm(u64 ptr, u64 old, u64 new)
|
||||
{
|
||||
asm volatile(
|
||||
" csg %[old],%[new],%[ptr]\n"
|
||||
" csg %[old],%[new],%[ptr]"
|
||||
: [old] "+d" (old), [ptr] "+QS" (*(u64 *)ptr)
|
||||
: [new] "d" (new)
|
||||
: "memory", "cc");
|
||||
@@ -126,7 +126,7 @@ static __always_inline u64 __arch_cmpxchg(u64 ptr, u64 old, u64 new, int size)
|
||||
} \
|
||||
case 4: { \
|
||||
asm volatile( \
|
||||
" cs %[__old],%[__new],%[__ptr]\n" \
|
||||
" cs %[__old],%[__new],%[__ptr]" \
|
||||
: [__old] "+d" (*__oldp), \
|
||||
[__ptr] "+Q" (*(ptr)), \
|
||||
"=@cc" (__cc) \
|
||||
@@ -136,7 +136,7 @@ static __always_inline u64 __arch_cmpxchg(u64 ptr, u64 old, u64 new, int size)
|
||||
} \
|
||||
case 8: { \
|
||||
asm volatile( \
|
||||
" csg %[__old],%[__new],%[__ptr]\n" \
|
||||
" csg %[__old],%[__new],%[__ptr]" \
|
||||
: [__old] "+d" (*__oldp), \
|
||||
[__ptr] "+QS" (*(ptr)), \
|
||||
"=@cc" (__cc) \
|
||||
@@ -241,7 +241,7 @@ static __always_inline u64 __arch_xchg(u64 ptr, u64 x, int size)
|
||||
static __always_inline u128 arch_cmpxchg128(volatile u128 *ptr, u128 old, u128 new)
|
||||
{
|
||||
asm volatile(
|
||||
" cdsg %[old],%[new],%[ptr]\n"
|
||||
" cdsg %[old],%[new],%[ptr]"
|
||||
: [old] "+d" (old), [ptr] "+QS" (*ptr)
|
||||
: [new] "d" (new)
|
||||
: "memory", "cc");
|
||||
@@ -258,7 +258,7 @@ static __always_inline bool arch_try_cmpxchg128(volatile u128 *ptr, u128 *oldp,
|
||||
int cc;
|
||||
|
||||
asm volatile(
|
||||
" cdsg %[old],%[new],%[ptr]\n"
|
||||
" cdsg %[old],%[new],%[ptr]"
|
||||
: [old] "+d" (*oldp), [ptr] "+QS" (*ptr), "=@cc" (cc)
|
||||
: [new] "d" (new)
|
||||
: "memory");
|
||||
|
||||
@@ -229,7 +229,7 @@ static __always_inline void __cpacf_query_rre(u32 opc, u8 r1, u8 r2,
|
||||
asm volatile(
|
||||
" la %%r1,%[pb]\n"
|
||||
" lghi %%r0,%[fc]\n"
|
||||
" .insn rre,%[opc] << 16,%[r1],%[r2]\n"
|
||||
" .insn rre,%[opc] << 16,%[r1],%[r2]"
|
||||
: [pb] "=R" (*pb)
|
||||
: [opc] "i" (opc), [fc] "i" (fc),
|
||||
[r1] "i" (r1), [r2] "i" (r2)
|
||||
@@ -242,7 +242,7 @@ static __always_inline void __cpacf_query_rrf(u32 opc, u8 r1, u8 r2, u8 r3,
|
||||
asm volatile(
|
||||
" la %%r1,%[pb]\n"
|
||||
" lghi %%r0,%[fc]\n"
|
||||
" .insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],%[m4]\n"
|
||||
" .insn rrf,%[opc] << 16,%[r1],%[r2],%[r3],%[m4]"
|
||||
: [pb] "=R" (*pb)
|
||||
: [opc] "i" (opc), [fc] "i" (fc), [r1] "i" (r1),
|
||||
[r2] "i" (r2), [r3] "i" (r3), [m4] "i" (m4)
|
||||
@@ -416,7 +416,7 @@ static inline int cpacf_km(unsigned long func, void *param,
|
||||
" lgr 0,%[fc]\n"
|
||||
" lgr 1,%[pba]\n"
|
||||
"0: .insn rre,%[opc] << 16,%[dst],%[src]\n"
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
" brc 1,0b" /* handle partial completion */
|
||||
: [src] "+&d" (s.pair), [dst] "+&d" (d.pair)
|
||||
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
|
||||
[opc] "i" (CPACF_KM)
|
||||
@@ -448,7 +448,7 @@ static inline int cpacf_kmc(unsigned long func, void *param,
|
||||
" lgr 0,%[fc]\n"
|
||||
" lgr 1,%[pba]\n"
|
||||
"0: .insn rre,%[opc] << 16,%[dst],%[src]\n"
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
" brc 1,0b" /* handle partial completion */
|
||||
: [src] "+&d" (s.pair), [dst] "+&d" (d.pair)
|
||||
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
|
||||
[opc] "i" (CPACF_KMC)
|
||||
@@ -476,7 +476,7 @@ static inline void cpacf_kimd(unsigned long func, void *param,
|
||||
" lgr 0,%[fc]\n"
|
||||
" lgr 1,%[pba]\n"
|
||||
"0: .insn rrf,%[opc] << 16,0,%[src],8,0\n"
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
" brc 1,0b" /* handle partial completion */
|
||||
: [src] "+&d" (s.pair)
|
||||
: [fc] "d" (func), [pba] "d" ((unsigned long)(param)),
|
||||
[opc] "i" (CPACF_KIMD)
|
||||
@@ -501,7 +501,7 @@ static inline void cpacf_klmd(unsigned long func, void *param,
|
||||
" lgr 0,%[fc]\n"
|
||||
" lgr 1,%[pba]\n"
|
||||
"0: .insn rrf,%[opc] << 16,0,%[src],8,0\n"
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
" brc 1,0b" /* handle partial completion */
|
||||
: [src] "+&d" (s.pair)
|
||||
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
|
||||
[opc] "i" (CPACF_KLMD)
|
||||
@@ -530,7 +530,7 @@ static inline int _cpacf_kmac(unsigned long *gr0, void *param,
|
||||
" lgr 1,%[pba]\n"
|
||||
"0: .insn rre,%[opc] << 16,0,%[src]\n"
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
" lgr %[r0],0\n"
|
||||
" lgr %[r0],0"
|
||||
: [r0] "+d" (*gr0), [src] "+&d" (s.pair)
|
||||
: [pba] "d" ((unsigned long)param),
|
||||
[opc] "i" (CPACF_KMAC)
|
||||
@@ -580,7 +580,7 @@ static inline int cpacf_kmctr(unsigned long func, void *param, u8 *dest,
|
||||
" lgr 0,%[fc]\n"
|
||||
" lgr 1,%[pba]\n"
|
||||
"0: .insn rrf,%[opc] << 16,%[dst],%[src],%[ctr],0\n"
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
" brc 1,0b" /* handle partial completion */
|
||||
: [src] "+&d" (s.pair), [dst] "+&d" (d.pair),
|
||||
[ctr] "+&d" (c.pair)
|
||||
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
|
||||
@@ -614,7 +614,7 @@ static inline void cpacf_prno(unsigned long func, void *param,
|
||||
" lgr 0,%[fc]\n"
|
||||
" lgr 1,%[pba]\n"
|
||||
"0: .insn rre,%[opc] << 16,%[dst],%[seed]\n"
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
" brc 1,0b" /* handle partial completion */
|
||||
: [dst] "+&d" (d.pair)
|
||||
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
|
||||
[seed] "d" (s.pair), [opc] "i" (CPACF_PRNO)
|
||||
@@ -640,7 +640,7 @@ static inline void cpacf_trng(u8 *ucbuf, unsigned long ucbuf_len,
|
||||
asm volatile (
|
||||
" lghi 0,%[fc]\n"
|
||||
"0: .insn rre,%[opc] << 16,%[ucbuf],%[cbuf]\n"
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
" brc 1,0b" /* handle partial completion */
|
||||
: [ucbuf] "+&d" (u.pair), [cbuf] "+&d" (c.pair)
|
||||
: [fc] "K" (CPACF_PRNO_TRNG), [opc] "i" (CPACF_PRNO)
|
||||
: "cc", "memory", "0");
|
||||
@@ -692,7 +692,7 @@ static inline void cpacf_pckmo(long func, void *param)
|
||||
asm volatile(
|
||||
" lgr 0,%[fc]\n"
|
||||
" lgr 1,%[pba]\n"
|
||||
" .insn rre,%[opc] << 16,0,0\n" /* PCKMO opcode */
|
||||
" .insn rre,%[opc] << 16,0,0" /* PCKMO opcode */
|
||||
:
|
||||
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
|
||||
[opc] "i" (CPACF_PCKMO)
|
||||
@@ -725,7 +725,7 @@ static inline void cpacf_kma(unsigned long func, void *param, u8 *dest,
|
||||
" lgr 0,%[fc]\n"
|
||||
" lgr 1,%[pba]\n"
|
||||
"0: .insn rrf,%[opc] << 16,%[dst],%[src],%[aad],0\n"
|
||||
" brc 1,0b\n" /* handle partial completion */
|
||||
" brc 1,0b" /* handle partial completion */
|
||||
: [dst] "+&d" (d.pair), [src] "+&d" (s.pair),
|
||||
[aad] "+&d" (a.pair)
|
||||
: [fc] "d" (func), [pba] "d" ((unsigned long)param),
|
||||
|
||||
@@ -100,7 +100,7 @@ struct ctlreg {
|
||||
BUILD_BUG_ON(sizeof(struct addrtype) != _esize); \
|
||||
typecheck(struct ctlreg, array[0]); \
|
||||
asm volatile( \
|
||||
" lctlg %[_low],%[_high],%[_arr]\n" \
|
||||
" lctlg %[_low],%[_high],%[_arr]" \
|
||||
: \
|
||||
: [_arr] "Q" (*(struct addrtype *)(&array)), \
|
||||
[_low] "i" (low), [_high] "i" (high) \
|
||||
@@ -119,7 +119,7 @@ struct ctlreg {
|
||||
BUILD_BUG_ON(sizeof(struct addrtype) != _esize); \
|
||||
typecheck(struct ctlreg, array[0]); \
|
||||
asm volatile( \
|
||||
" stctg %[_low],%[_high],%[_arr]\n" \
|
||||
" stctg %[_low],%[_high],%[_arr]" \
|
||||
: [_arr] "=Q" (*(struct addrtype *)(&array)) \
|
||||
: [_low] "i" (low), [_high] "i" (high)); \
|
||||
} while (0)
|
||||
@@ -127,7 +127,7 @@ struct ctlreg {
|
||||
static __always_inline void local_ctl_load(unsigned int cr, struct ctlreg *reg)
|
||||
{
|
||||
asm volatile(
|
||||
" lctlg %[cr],%[cr],%[reg]\n"
|
||||
" lctlg %[cr],%[cr],%[reg]"
|
||||
:
|
||||
: [reg] "Q" (*reg), [cr] "i" (cr)
|
||||
: "memory");
|
||||
@@ -136,7 +136,7 @@ static __always_inline void local_ctl_load(unsigned int cr, struct ctlreg *reg)
|
||||
static __always_inline void local_ctl_store(unsigned int cr, struct ctlreg *reg)
|
||||
{
|
||||
asm volatile(
|
||||
" stctg %[cr],%[cr],%[reg]\n"
|
||||
" stctg %[cr],%[cr],%[reg]"
|
||||
: [reg] "=Q" (*reg)
|
||||
: [cr] "i" (cr));
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ asm(".include \"asm/fpu-insn-asm.h\"\n");
|
||||
|
||||
static __always_inline void fpu_cefbr(u8 f1, s32 val)
|
||||
{
|
||||
asm volatile("cefbr %[f1],%[val]\n"
|
||||
asm volatile("cefbr %[f1],%[val]"
|
||||
:
|
||||
: [f1] "I" (f1), [val] "d" (val)
|
||||
: "memory");
|
||||
@@ -48,7 +48,7 @@ static __always_inline unsigned long fpu_cgebr(u8 f2, u8 mode)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
asm volatile("cgebr %[val],%[mode],%[f2]\n"
|
||||
asm volatile("cgebr %[val],%[mode],%[f2]"
|
||||
: [val] "=d" (val)
|
||||
: [f2] "I" (f2), [mode] "I" (mode)
|
||||
: "memory");
|
||||
@@ -57,7 +57,7 @@ static __always_inline unsigned long fpu_cgebr(u8 f2, u8 mode)
|
||||
|
||||
static __always_inline void fpu_debr(u8 f1, u8 f2)
|
||||
{
|
||||
asm volatile("debr %[f1],%[f2]\n"
|
||||
asm volatile("debr %[f1],%[f2]"
|
||||
:
|
||||
: [f1] "I" (f1), [f2] "I" (f2)
|
||||
: "memory");
|
||||
@@ -66,7 +66,7 @@ static __always_inline void fpu_debr(u8 f1, u8 f2)
|
||||
static __always_inline void fpu_ld(unsigned short fpr, freg_t *reg)
|
||||
{
|
||||
instrument_read(reg, sizeof(*reg));
|
||||
asm volatile("ld %[fpr],%[reg]\n"
|
||||
asm volatile("ld %[fpr],%[reg]"
|
||||
:
|
||||
: [fpr] "I" (fpr), [reg] "Q" (reg->ui)
|
||||
: "memory");
|
||||
@@ -74,7 +74,7 @@ static __always_inline void fpu_ld(unsigned short fpr, freg_t *reg)
|
||||
|
||||
static __always_inline void fpu_ldgr(u8 f1, u32 val)
|
||||
{
|
||||
asm volatile("ldgr %[f1],%[val]\n"
|
||||
asm volatile("ldgr %[f1],%[val]"
|
||||
:
|
||||
: [f1] "I" (f1), [val] "d" (val)
|
||||
: "memory");
|
||||
@@ -113,7 +113,7 @@ static inline void fpu_lfpc_safe(unsigned int *fpc)
|
||||
static __always_inline void fpu_std(unsigned short fpr, freg_t *reg)
|
||||
{
|
||||
instrument_write(reg, sizeof(*reg));
|
||||
asm volatile("std %[fpr],%[reg]\n"
|
||||
asm volatile("std %[fpr],%[reg]"
|
||||
: [reg] "=Q" (reg->ui)
|
||||
: [fpr] "I" (fpr)
|
||||
: "memory");
|
||||
@@ -181,7 +181,7 @@ static __always_inline void fpu_vgfmg(u8 v1, u8 v2, u8 v3)
|
||||
static __always_inline void fpu_vl(u8 v1, const void *vxr)
|
||||
{
|
||||
instrument_read(vxr, sizeof(__vector128));
|
||||
asm volatile("VL %[v1],%O[vxr],,%R[vxr]\n"
|
||||
asm volatile("VL %[v1],%O[vxr],,%R[vxr]"
|
||||
:
|
||||
: [vxr] "Q" (*(__vector128 *)vxr),
|
||||
[v1] "I" (v1)
|
||||
@@ -195,7 +195,7 @@ static __always_inline void fpu_vl(u8 v1, const void *vxr)
|
||||
instrument_read(vxr, sizeof(__vector128));
|
||||
asm volatile(
|
||||
" la 1,%[vxr]\n"
|
||||
" VL %[v1],0,,1\n"
|
||||
" VL %[v1],0,,1"
|
||||
:
|
||||
: [vxr] "R" (*(__vector128 *)vxr),
|
||||
[v1] "I" (v1)
|
||||
@@ -239,7 +239,7 @@ static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr)
|
||||
|
||||
size = min(index + 1, sizeof(__vector128));
|
||||
instrument_read(vxr, size);
|
||||
asm volatile("VLL %[v1],%[index],%O[vxr],%R[vxr]\n"
|
||||
asm volatile("VLL %[v1],%[index],%O[vxr],%R[vxr]"
|
||||
:
|
||||
: [vxr] "Q" (*(u8 *)vxr),
|
||||
[index] "d" (index),
|
||||
@@ -257,7 +257,7 @@ static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr)
|
||||
instrument_read(vxr, size);
|
||||
asm volatile(
|
||||
" la 1,%[vxr]\n"
|
||||
" VLL %[v1],%[index],0,1\n"
|
||||
" VLL %[v1],%[index],0,1"
|
||||
:
|
||||
: [vxr] "R" (*(u8 *)vxr),
|
||||
[index] "d" (index),
|
||||
@@ -277,7 +277,7 @@ static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr)
|
||||
} *_v = (void *)(_vxrs); \
|
||||
\
|
||||
instrument_read(_v, size); \
|
||||
asm volatile("VLM %[v1],%[v3],%O[vxrs],%R[vxrs]\n" \
|
||||
asm volatile("VLM %[v1],%[v3],%O[vxrs],%R[vxrs]" \
|
||||
: \
|
||||
: [vxrs] "Q" (*_v), \
|
||||
[v1] "I" (_v1), [v3] "I" (_v3) \
|
||||
@@ -297,7 +297,7 @@ static __always_inline void fpu_vll(u8 v1, u32 index, const void *vxr)
|
||||
instrument_read(_v, size); \
|
||||
asm volatile( \
|
||||
" la 1,%[vxrs]\n" \
|
||||
" VLM %[v1],%[v3],0,1\n" \
|
||||
" VLM %[v1],%[v3],0,1" \
|
||||
: \
|
||||
: [vxrs] "R" (*_v), \
|
||||
[v1] "I" (_v1), [v3] "I" (_v3) \
|
||||
@@ -360,7 +360,7 @@ static __always_inline void fpu_vsrlb(u8 v1, u8 v2, u8 v3)
|
||||
static __always_inline void fpu_vst(u8 v1, const void *vxr)
|
||||
{
|
||||
instrument_write(vxr, sizeof(__vector128));
|
||||
asm volatile("VST %[v1],%O[vxr],,%R[vxr]\n"
|
||||
asm volatile("VST %[v1],%O[vxr],,%R[vxr]"
|
||||
: [vxr] "=Q" (*(__vector128 *)vxr)
|
||||
: [v1] "I" (v1)
|
||||
: "memory");
|
||||
@@ -373,7 +373,7 @@ static __always_inline void fpu_vst(u8 v1, const void *vxr)
|
||||
instrument_write(vxr, sizeof(__vector128));
|
||||
asm volatile(
|
||||
" la 1,%[vxr]\n"
|
||||
" VST %[v1],0,,1\n"
|
||||
" VST %[v1],0,,1"
|
||||
: [vxr] "=R" (*(__vector128 *)vxr)
|
||||
: [v1] "I" (v1)
|
||||
: "memory", "1");
|
||||
@@ -389,7 +389,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)
|
||||
|
||||
size = min(index + 1, sizeof(__vector128));
|
||||
instrument_write(vxr, size);
|
||||
asm volatile("VSTL %[v1],%[index],%O[vxr],%R[vxr]\n"
|
||||
asm volatile("VSTL %[v1],%[index],%O[vxr],%R[vxr]"
|
||||
: [vxr] "=Q" (*(u8 *)vxr)
|
||||
: [index] "d" (index), [v1] "I" (v1)
|
||||
: "memory");
|
||||
@@ -405,7 +405,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)
|
||||
instrument_write(vxr, size);
|
||||
asm volatile(
|
||||
" la 1,%[vxr]\n"
|
||||
" VSTL %[v1],%[index],0,1\n"
|
||||
" VSTL %[v1],%[index],0,1"
|
||||
: [vxr] "=R" (*(u8 *)vxr)
|
||||
: [index] "d" (index), [v1] "I" (v1)
|
||||
: "memory", "1");
|
||||
@@ -423,7 +423,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)
|
||||
} *_v = (void *)(_vxrs); \
|
||||
\
|
||||
instrument_write(_v, size); \
|
||||
asm volatile("VSTM %[v1],%[v3],%O[vxrs],%R[vxrs]\n" \
|
||||
asm volatile("VSTM %[v1],%[v3],%O[vxrs],%R[vxrs]" \
|
||||
: [vxrs] "=Q" (*_v) \
|
||||
: [v1] "I" (_v1), [v3] "I" (_v3) \
|
||||
: "memory"); \
|
||||
@@ -442,7 +442,7 @@ static __always_inline void fpu_vstl(u8 v1, u32 index, const void *vxr)
|
||||
instrument_write(_v, size); \
|
||||
asm volatile( \
|
||||
" la 1,%[vxrs]\n" \
|
||||
" VSTM %[v1],%[v3],0,1\n" \
|
||||
" VSTM %[v1],%[v3],0,1" \
|
||||
: [vxrs] "=R" (*_v) \
|
||||
: [v1] "I" (_v1), [v3] "I" (_v3) \
|
||||
: "memory", "1"); \
|
||||
|
||||
@@ -76,7 +76,7 @@ long __kvm_hypercall##args(unsigned long nr HYPERCALL_PARM_##args) \
|
||||
HYPERCALL_REGS_##args; \
|
||||
\
|
||||
asm volatile ( \
|
||||
" diag 2,4,0x500\n" \
|
||||
" diag 2,4,0x500" \
|
||||
: "=d" (__rc) \
|
||||
: "d" (__nr) HYPERCALL_FMT_##args \
|
||||
: "memory", "cc"); \
|
||||
|
||||
@@ -246,6 +246,16 @@ int clp_refresh_fh(u32 fid, u32 *fh);
|
||||
/* UID */
|
||||
void update_uid_checking(bool new);
|
||||
|
||||
/* Firmware Sysfs */
|
||||
int __init __zpci_fw_sysfs_init(void);
|
||||
|
||||
static inline int __init zpci_fw_sysfs_init(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_SYSFS))
|
||||
return __zpci_fw_sysfs_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* IOMMU Interface */
|
||||
int zpci_init_iommu(struct zpci_dev *zdev);
|
||||
void zpci_destroy_iommu(struct zpci_dev *zdev);
|
||||
|
||||
@@ -73,13 +73,13 @@
|
||||
if (__builtin_constant_p(val__) && \
|
||||
((szcast)val__ > -129) && ((szcast)val__ < 128)) { \
|
||||
asm volatile( \
|
||||
op2 " %[ptr__],%[val__]\n" \
|
||||
op2 " %[ptr__],%[val__]" \
|
||||
: [ptr__] "+Q" (*ptr__) \
|
||||
: [val__] "i" ((szcast)val__) \
|
||||
: "cc"); \
|
||||
} else { \
|
||||
asm volatile( \
|
||||
op1 " %[old__],%[val__],%[ptr__]\n" \
|
||||
op1 " %[old__],%[val__],%[ptr__]" \
|
||||
: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__) \
|
||||
: [val__] "d" (val__) \
|
||||
: "cc"); \
|
||||
@@ -98,7 +98,7 @@
|
||||
preempt_disable_notrace(); \
|
||||
ptr__ = raw_cpu_ptr(&(pcp)); \
|
||||
asm volatile( \
|
||||
op " %[old__],%[val__],%[ptr__]\n" \
|
||||
op " %[old__],%[val__],%[ptr__]" \
|
||||
: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__) \
|
||||
: [val__] "d" (val__) \
|
||||
: "cc"); \
|
||||
@@ -117,7 +117,7 @@
|
||||
preempt_disable_notrace(); \
|
||||
ptr__ = raw_cpu_ptr(&(pcp)); \
|
||||
asm volatile( \
|
||||
op " %[old__],%[val__],%[ptr__]\n" \
|
||||
op " %[old__],%[val__],%[ptr__]" \
|
||||
: [old__] "=d" (old__), [ptr__] "+Q" (*ptr__) \
|
||||
: [val__] "d" (val__) \
|
||||
: "cc"); \
|
||||
|
||||
@@ -163,7 +163,7 @@ static __always_inline void __stackleak_poison(unsigned long erase_low,
|
||||
"2: stg %[poison],0(%[addr])\n"
|
||||
" j 4f\n"
|
||||
"3: mvc 8(1,%[addr]),0(%[addr])\n"
|
||||
"4:\n"
|
||||
"4:"
|
||||
: [addr] "+&a" (erase_low), [count] "+&d" (count), [tmp] "=&a" (tmp)
|
||||
: [poison] "d" (poison)
|
||||
: "memory", "cc"
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
\
|
||||
BUILD_BUG_ON(sizeof(x) != 16); \
|
||||
asm volatile( \
|
||||
" lpq %[val],%[_x]\n" \
|
||||
" lpq %[val],%[_x]" \
|
||||
: [val] "=d" (__u.val) \
|
||||
: [_x] "QS" (x) \
|
||||
: "memory"); \
|
||||
|
||||
@@ -98,7 +98,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp)
|
||||
kcsan_release();
|
||||
asm_inline volatile(
|
||||
ALTERNATIVE("nop", ".insn rre,0xb2fa0000,7,0", ALT_FACILITY(49)) /* NIAI 7 */
|
||||
" mvhhi %[lock],0\n"
|
||||
" mvhhi %[lock],0"
|
||||
: [lock] "=Q" (((unsigned short *)&lp->lock)[1])
|
||||
:
|
||||
: "memory");
|
||||
|
||||
@@ -199,7 +199,7 @@ static __always_inline unsigned long get_stack_pointer(struct task_struct *task,
|
||||
" lg 15,%[_stack]\n" \
|
||||
" stg %[_frame],%[_bc](15)\n" \
|
||||
" brasl 14,%[_fn]\n" \
|
||||
" lgr 15,%[_prev]\n" \
|
||||
" lgr 15,%[_prev]" \
|
||||
: [_prev] "=&d" (prev), CALL_FMT_##nr \
|
||||
: [_stack] "R" (__stack), \
|
||||
[_bc] "i" (offsetof(struct stack_frame, back_chain)), \
|
||||
@@ -250,7 +250,7 @@ static __always_inline unsigned long get_stack_pointer(struct task_struct *task,
|
||||
" lra 14,0(1)\n" \
|
||||
" lpswe %[psw_enter]\n" \
|
||||
"0: lpswe 0(7)\n" \
|
||||
"1:\n" \
|
||||
"1:" \
|
||||
: CALL_FMT_##nr, [psw_leave] "=Q" (psw_leave) \
|
||||
: [psw_enter] "Q" (psw_enter) \
|
||||
: "7", CALL_CLOBBER_##nr); \
|
||||
|
||||
@@ -125,7 +125,7 @@ static inline void *memscan(void *s, int c, size_t n)
|
||||
asm volatile(
|
||||
" lgr 0,%[c]\n"
|
||||
"0: srst %[ret],%[s]\n"
|
||||
" jo 0b\n"
|
||||
" jo 0b"
|
||||
: [ret] "+&a" (ret), [s] "+&a" (s)
|
||||
: [c] "d" (c)
|
||||
: "cc", "memory", "0");
|
||||
|
||||
@@ -155,7 +155,7 @@ long syscall##nr(unsigned long syscall SYSCALL_PARM_##nr) \
|
||||
SYSCALL_REGS_##nr; \
|
||||
\
|
||||
asm volatile ( \
|
||||
" svc 0\n" \
|
||||
" svc 0" \
|
||||
: "=d" (rc) \
|
||||
: "d" (r1) SYSCALL_FMT_##nr \
|
||||
: "memory"); \
|
||||
|
||||
@@ -81,7 +81,7 @@ static inline void set_tod_programmable_field(u16 val)
|
||||
{
|
||||
asm volatile(
|
||||
" lgr 0,%[val]\n"
|
||||
" sckpf\n"
|
||||
" sckpf"
|
||||
:
|
||||
: [val] "d" ((unsigned long)val)
|
||||
: "0");
|
||||
|
||||
@@ -66,7 +66,7 @@ static inline unsigned long diag310(unsigned long subcode, unsigned long size, v
|
||||
union register_pair rp = { .even = (unsigned long)addr, .odd = size };
|
||||
|
||||
diag_stat_inc(DIAG_STAT_X310);
|
||||
asm volatile("diag %[rp],%[subcode],0x310\n"
|
||||
asm volatile("diag %[rp],%[subcode],0x310"
|
||||
: [rp] "+d" (rp.pair)
|
||||
: [subcode] "d" (subcode)
|
||||
: "memory");
|
||||
|
||||
@@ -101,7 +101,7 @@ static unsigned long diag324(unsigned long subcode, void *addr)
|
||||
union register_pair rp = { .even = (unsigned long)addr };
|
||||
|
||||
diag_stat_inc(DIAG_STAT_X324);
|
||||
asm volatile("diag %[rp],%[subcode],0x324\n"
|
||||
asm volatile("diag %[rp],%[subcode],0x324"
|
||||
: [rp] "+d" (rp.pair)
|
||||
: [subcode] "d" (subcode)
|
||||
: "memory");
|
||||
|
||||
@@ -80,6 +80,15 @@ static int paicrypt_root_alloc(void)
|
||||
/* Release the PMU if event is the last perf event */
|
||||
static DEFINE_MUTEX(pai_reserve_mutex);
|
||||
|
||||
/* Free all memory allocated for event counting/sampling setup */
|
||||
static void paicrypt_free(struct paicrypt_mapptr *mp)
|
||||
{
|
||||
free_page((unsigned long)mp->mapptr->page);
|
||||
kvfree(mp->mapptr->save);
|
||||
kfree(mp->mapptr);
|
||||
mp->mapptr = NULL;
|
||||
}
|
||||
|
||||
/* Adjust usage counters and remove allocated memory when all users are
|
||||
* gone.
|
||||
*/
|
||||
@@ -93,15 +102,8 @@ static void paicrypt_event_destroy_cpu(struct perf_event *event, int cpu)
|
||||
"refcnt %u\n", __func__, event->attr.config,
|
||||
event->cpu, cpump->active_events,
|
||||
refcount_read(&cpump->refcnt));
|
||||
if (refcount_dec_and_test(&cpump->refcnt)) {
|
||||
debug_sprintf_event(cfm_dbg, 4, "%s page %#lx save %p\n",
|
||||
__func__, (unsigned long)cpump->page,
|
||||
cpump->save);
|
||||
free_page((unsigned long)cpump->page);
|
||||
kvfree(cpump->save);
|
||||
kfree(cpump);
|
||||
mp->mapptr = NULL;
|
||||
}
|
||||
if (refcount_dec_and_test(&cpump->refcnt))
|
||||
paicrypt_free(mp);
|
||||
paicrypt_root_free();
|
||||
mutex_unlock(&pai_reserve_mutex);
|
||||
}
|
||||
@@ -175,14 +177,13 @@ static u64 paicrypt_getall(struct perf_event *event)
|
||||
*
|
||||
* Allocate the memory for the event.
|
||||
*/
|
||||
static struct paicrypt_map *paicrypt_busy(struct perf_event *event, int cpu)
|
||||
static int paicrypt_alloc_cpu(struct perf_event *event, int cpu)
|
||||
{
|
||||
struct paicrypt_map *cpump = NULL;
|
||||
struct paicrypt_mapptr *mp;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&pai_reserve_mutex);
|
||||
|
||||
/* Allocate root node */
|
||||
rc = paicrypt_root_alloc();
|
||||
if (rc)
|
||||
@@ -192,58 +193,44 @@ static struct paicrypt_map *paicrypt_busy(struct perf_event *event, int cpu)
|
||||
mp = per_cpu_ptr(paicrypt_root.mapptr, cpu);
|
||||
cpump = mp->mapptr;
|
||||
if (!cpump) { /* Paicrypt_map allocated? */
|
||||
rc = -ENOMEM;
|
||||
cpump = kzalloc(sizeof(*cpump), GFP_KERNEL);
|
||||
if (!cpump) {
|
||||
rc = -ENOMEM;
|
||||
goto free_root;
|
||||
if (!cpump)
|
||||
goto undo;
|
||||
/* Allocate memory for counter page and counter extraction.
|
||||
* Only the first counting event has to allocate a page.
|
||||
*/
|
||||
mp->mapptr = cpump;
|
||||
cpump->page = (unsigned long *)get_zeroed_page(GFP_KERNEL);
|
||||
cpump->save = kvmalloc_array(paicrypt_cnt + 1,
|
||||
sizeof(struct pai_userdata),
|
||||
GFP_KERNEL);
|
||||
if (!cpump->page || !cpump->save) {
|
||||
paicrypt_free(mp);
|
||||
goto undo;
|
||||
}
|
||||
INIT_LIST_HEAD(&cpump->syswide_list);
|
||||
}
|
||||
|
||||
/* Allocate memory for counter page and counter extraction.
|
||||
* Only the first counting event has to allocate a page.
|
||||
*/
|
||||
if (cpump->page) {
|
||||
refcount_set(&cpump->refcnt, 1);
|
||||
rc = 0;
|
||||
} else {
|
||||
refcount_inc(&cpump->refcnt);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
rc = -ENOMEM;
|
||||
cpump->page = (unsigned long *)get_zeroed_page(GFP_KERNEL);
|
||||
if (!cpump->page)
|
||||
goto free_paicrypt_map;
|
||||
cpump->save = kvmalloc_array(paicrypt_cnt + 1,
|
||||
sizeof(struct pai_userdata), GFP_KERNEL);
|
||||
if (!cpump->save) {
|
||||
free_page((unsigned long)cpump->page);
|
||||
cpump->page = NULL;
|
||||
goto free_paicrypt_map;
|
||||
undo:
|
||||
if (rc) {
|
||||
/* Error in allocation of event, decrement anchor. Since
|
||||
* the event in not created, its destroy() function is never
|
||||
* invoked. Adjust the reference counter for the anchor.
|
||||
*/
|
||||
paicrypt_root_free();
|
||||
}
|
||||
|
||||
/* Set mode and reference count */
|
||||
rc = 0;
|
||||
refcount_set(&cpump->refcnt, 1);
|
||||
mp->mapptr = cpump;
|
||||
debug_sprintf_event(cfm_dbg, 5, "%s users %d refcnt %u page %#lx "
|
||||
"save %p rc %d\n", __func__, cpump->active_events,
|
||||
refcount_read(&cpump->refcnt),
|
||||
(unsigned long)cpump->page, cpump->save, rc);
|
||||
goto unlock;
|
||||
|
||||
free_paicrypt_map:
|
||||
/* Undo memory allocation */
|
||||
kfree(cpump);
|
||||
mp->mapptr = NULL;
|
||||
free_root:
|
||||
paicrypt_root_free();
|
||||
unlock:
|
||||
mutex_unlock(&pai_reserve_mutex);
|
||||
return rc ? ERR_PTR(rc) : cpump;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int paicrypt_event_init_all(struct perf_event *event)
|
||||
static int paicrypt_alloc(struct perf_event *event)
|
||||
{
|
||||
struct paicrypt_map *cpump;
|
||||
struct cpumask *maskptr;
|
||||
int cpu, rc = -ENOMEM;
|
||||
|
||||
@@ -252,12 +239,11 @@ static int paicrypt_event_init_all(struct perf_event *event)
|
||||
goto out;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
cpump = paicrypt_busy(event, cpu);
|
||||
if (IS_ERR(cpump)) {
|
||||
rc = paicrypt_alloc_cpu(event, cpu);
|
||||
if (rc) {
|
||||
for_each_cpu(cpu, maskptr)
|
||||
paicrypt_event_destroy_cpu(event, cpu);
|
||||
kfree(maskptr);
|
||||
rc = PTR_ERR(cpump);
|
||||
goto out;
|
||||
}
|
||||
cpumask_set_cpu(cpu, maskptr);
|
||||
@@ -279,7 +265,6 @@ out:
|
||||
static int paicrypt_event_init(struct perf_event *event)
|
||||
{
|
||||
struct perf_event_attr *a = &event->attr;
|
||||
struct paicrypt_map *cpump;
|
||||
int rc = 0;
|
||||
|
||||
/* PAI crypto PMU registered as PERF_TYPE_RAW, check event type */
|
||||
@@ -301,13 +286,10 @@ static int paicrypt_event_init(struct perf_event *event)
|
||||
}
|
||||
}
|
||||
|
||||
if (event->cpu >= 0) {
|
||||
cpump = paicrypt_busy(event, event->cpu);
|
||||
if (IS_ERR(cpump))
|
||||
rc = PTR_ERR(cpump);
|
||||
} else {
|
||||
rc = paicrypt_event_init_all(event);
|
||||
}
|
||||
if (event->cpu >= 0)
|
||||
rc = paicrypt_alloc_cpu(event, event->cpu);
|
||||
else
|
||||
rc = paicrypt_alloc(event);
|
||||
if (rc) {
|
||||
free_page(PAI_SAVE_AREA(event));
|
||||
goto out;
|
||||
|
||||
@@ -839,7 +839,7 @@ static void __init setup_control_program_code(void)
|
||||
return;
|
||||
|
||||
diag_stat_inc(DIAG_STAT_X318);
|
||||
asm volatile("diag %0,0,0x318\n" : : "d" (diag318_info.val));
|
||||
asm volatile("diag %0,0,0x318" : : "d" (diag318_info.val));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -11,7 +11,7 @@ static inline unsigned long load_real_address(unsigned long address)
|
||||
unsigned long real;
|
||||
|
||||
asm volatile(
|
||||
" lra %[real],0(%[address])\n"
|
||||
" lra %[real],0(%[address])"
|
||||
: [real] "=d" (real)
|
||||
: [address] "a" (address)
|
||||
: "cc");
|
||||
|
||||
@@ -340,7 +340,7 @@ static void pcpu_delegate(struct pcpu *pcpu, int cpu,
|
||||
"0: sigp 0,%0,%2 # sigp restart to target cpu\n"
|
||||
" brc 2,0b # busy, try again\n"
|
||||
"1: sigp 0,%1,%3 # sigp stop to current cpu\n"
|
||||
" brc 2,1b # busy, try again\n"
|
||||
" brc 2,1b # busy, try again"
|
||||
: : "d" (pcpu->address), "d" (source_cpu),
|
||||
"K" (SIGP_RESTART), "K" (SIGP_STOP)
|
||||
: "0", "1", "cc");
|
||||
|
||||
@@ -866,8 +866,8 @@ static int find_secret_in_page(const u8 secret_id[UV_SECRET_ID_LEN],
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the actual search for `uv_get_secret_metadata`.
|
||||
/**
|
||||
* uv_find_secret() - search secret metadata for a given secret id.
|
||||
* @secret_id: search pattern.
|
||||
* @list: ephemeral buffer space
|
||||
* @secret: output data, containing the secret's metadata.
|
||||
|
||||
@@ -356,7 +356,7 @@ static __always_inline void pfcr_query(u8 (*query)[16])
|
||||
{
|
||||
asm volatile(
|
||||
" lghi 0,0\n"
|
||||
" .insn rsy,0xeb0000000016,0,0,%[query]\n"
|
||||
" .insn rsy,0xeb0000000016,0,0,%[query]"
|
||||
: [query] "=QS" (*query)
|
||||
:
|
||||
: "cc", "0");
|
||||
@@ -368,7 +368,7 @@ static __always_inline void __sortl_query(u8 (*query)[32])
|
||||
" lghi 0,0\n"
|
||||
" la 1,%[query]\n"
|
||||
/* Parameter registers are ignored */
|
||||
" .insn rre,0xb9380000,2,4\n"
|
||||
" .insn rre,0xb9380000,2,4"
|
||||
: [query] "=R" (*query)
|
||||
:
|
||||
: "cc", "0", "1");
|
||||
@@ -380,7 +380,7 @@ static __always_inline void __dfltcc_query(u8 (*query)[32])
|
||||
" lghi 0,0\n"
|
||||
" la 1,%[query]\n"
|
||||
/* Parameter registers are ignored */
|
||||
" .insn rrf,0xb9390000,2,4,6,0\n"
|
||||
" .insn rrf,0xb9390000,2,4,6,0"
|
||||
: [query] "=R" (*query)
|
||||
:
|
||||
: "cc", "0", "1");
|
||||
|
||||
@@ -96,7 +96,7 @@ static inline int arch_load_niai4(int *lock)
|
||||
|
||||
asm_inline volatile(
|
||||
ALTERNATIVE("nop", ".insn rre,0xb2fa0000,4,0", ALT_FACILITY(49)) /* NIAI 4 */
|
||||
" l %[owner],%[lock]\n"
|
||||
" l %[owner],%[lock]"
|
||||
: [owner] "=d" (owner) : [lock] "R" (*lock) : "memory");
|
||||
return owner;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ static inline int arch_try_cmpxchg_niai8(int *lock, int old, int new)
|
||||
|
||||
asm_inline volatile(
|
||||
ALTERNATIVE("nop", ".insn rre,0xb2fa0000,8,0", ALT_FACILITY(49)) /* NIAI 8 */
|
||||
" cs %[old],%[new],%[lock]\n"
|
||||
" cs %[old],%[new],%[lock]"
|
||||
: [old] "+d" (old), [lock] "+Q" (*lock), "=@cc" (cc)
|
||||
: [new] "d" (new)
|
||||
: "memory");
|
||||
@@ -124,7 +124,7 @@ static inline int arch_try_cmpxchg_niai8(int *lock, int old, int new)
|
||||
|
||||
asm_inline volatile(
|
||||
ALTERNATIVE("nop", ".insn rre,0xb2fa0000,8,0", ALT_FACILITY(49)) /* NIAI 8 */
|
||||
" cs %[old],%[new],%[lock]\n"
|
||||
" cs %[old],%[new],%[lock]"
|
||||
: [old] "+d" (old), [lock] "+Q" (*lock)
|
||||
: [new] "d" (new)
|
||||
: "cc", "memory");
|
||||
|
||||
@@ -27,7 +27,7 @@ static inline char *__strend(const char *s)
|
||||
asm volatile(
|
||||
" lghi 0,0\n"
|
||||
"0: srst %[e],%[s]\n"
|
||||
" jo 0b\n"
|
||||
" jo 0b"
|
||||
: [e] "+&a" (e), [s] "+&a" (s)
|
||||
:
|
||||
: "cc", "memory", "0");
|
||||
@@ -41,7 +41,7 @@ static inline char *__strnend(const char *s, size_t n)
|
||||
asm volatile(
|
||||
" lghi 0,0\n"
|
||||
"0: srst %[p],%[s]\n"
|
||||
" jo 0b\n"
|
||||
" jo 0b"
|
||||
: [p] "+&d" (p), [s] "+&a" (s)
|
||||
:
|
||||
: "cc", "memory", "0");
|
||||
@@ -95,7 +95,7 @@ char *strcat(char *dest, const char *src)
|
||||
"0: srst %[dummy],%[dest]\n"
|
||||
" jo 0b\n"
|
||||
"1: mvst %[dummy],%[src]\n"
|
||||
" jo 1b\n"
|
||||
" jo 1b"
|
||||
: [dummy] "+&a" (dummy), [dest] "+&a" (dest), [src] "+&a" (src)
|
||||
:
|
||||
: "cc", "memory", "0");
|
||||
@@ -291,7 +291,7 @@ void *memscan(void *s, int c, size_t n)
|
||||
asm volatile(
|
||||
" lgr 0,%[c]\n"
|
||||
"0: srst %[ret],%[s]\n"
|
||||
" jo 0b\n"
|
||||
" jo 0b"
|
||||
: [ret] "+&a" (ret), [s] "+&a" (s)
|
||||
: [c] "d" (c)
|
||||
: "cc", "memory", "0");
|
||||
|
||||
@@ -150,7 +150,7 @@ static __always_inline struct pt_regs fake_pt_regs(void)
|
||||
regs.gprs[15] = current_stack_pointer;
|
||||
|
||||
asm volatile(
|
||||
"basr %[psw_addr],0\n"
|
||||
"basr %[psw_addr],0"
|
||||
: [psw_addr] "=d" (regs.psw.addr));
|
||||
return regs;
|
||||
}
|
||||
@@ -232,7 +232,7 @@ static noinline void test_unwind_kprobed_func(void)
|
||||
asm volatile(
|
||||
" nopr %%r7\n"
|
||||
"test_unwind_kprobed_insn:\n"
|
||||
" nopr %%r7\n"
|
||||
" nopr %%r7"
|
||||
:);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -27,7 +27,7 @@ static void xor_xc_2(unsigned long bytes, unsigned long * __restrict p1,
|
||||
"1: exrl %0,2f\n"
|
||||
" j 3f\n"
|
||||
"2: xc 0(1,%1),0(%2)\n"
|
||||
"3:\n"
|
||||
"3:"
|
||||
: : "d" (bytes), "a" (p1), "a" (p2)
|
||||
: "0", "cc", "memory");
|
||||
}
|
||||
@@ -53,7 +53,7 @@ static void xor_xc_3(unsigned long bytes, unsigned long * __restrict p1,
|
||||
" j 4f\n"
|
||||
"2: xc 0(1,%1),0(%2)\n"
|
||||
"3: xc 0(1,%1),0(%3)\n"
|
||||
"4:\n"
|
||||
"4:"
|
||||
: "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3)
|
||||
: : "0", "cc", "memory");
|
||||
}
|
||||
@@ -84,7 +84,7 @@ static void xor_xc_4(unsigned long bytes, unsigned long * __restrict p1,
|
||||
"2: xc 0(1,%1),0(%2)\n"
|
||||
"3: xc 0(1,%1),0(%3)\n"
|
||||
"4: xc 0(1,%1),0(%4)\n"
|
||||
"5:\n"
|
||||
"5:"
|
||||
: "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4)
|
||||
: : "0", "cc", "memory");
|
||||
}
|
||||
@@ -121,7 +121,7 @@ static void xor_xc_5(unsigned long bytes, unsigned long * __restrict p1,
|
||||
"3: xc 0(1,%1),0(%3)\n"
|
||||
"4: xc 0(1,%1),0(%4)\n"
|
||||
"5: xc 0(1,%1),0(%5)\n"
|
||||
"6:\n"
|
||||
"6:"
|
||||
: "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4),
|
||||
"+a" (p5)
|
||||
: : "0", "cc", "memory");
|
||||
|
||||
@@ -41,7 +41,7 @@ static notrace long s390_kernel_write_odd(void *dst, const void *src, size_t siz
|
||||
" ex %1,0(1)\n"
|
||||
" lg %1,0(%3)\n"
|
||||
" lra %0,0(%0)\n"
|
||||
" sturg %1,%0\n"
|
||||
" sturg %1,%0"
|
||||
: "+&a" (aligned), "+&a" (count), "=m" (tmp)
|
||||
: "a" (&tmp), "a" (&tmp[offset]), "a" (src)
|
||||
: "cc", "memory", "1");
|
||||
|
||||
@@ -245,7 +245,7 @@ static inline unsigned long base_lra(unsigned long address)
|
||||
unsigned long real;
|
||||
|
||||
asm volatile(
|
||||
" lra %0,0(%1)\n"
|
||||
" lra %0,0(%1)"
|
||||
: "=d" (real) : "a" (address) : "cc");
|
||||
return real;
|
||||
}
|
||||
|
||||
@@ -1188,6 +1188,10 @@ static int __init pci_base_init(void)
|
||||
if (rc)
|
||||
goto out_find;
|
||||
|
||||
rc = zpci_fw_sysfs_init();
|
||||
if (rc)
|
||||
goto out_find;
|
||||
|
||||
s390_pci_initialized = 1;
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ int zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib)
|
||||
return -EIO;
|
||||
|
||||
asm volatile(
|
||||
".insn rsy,0xeb00000000d1,%[ctl],%[isc],%[iib]\n"
|
||||
".insn rsy,0xeb00000000d1,%[ctl],%[isc],%[iib]"
|
||||
: : [ctl] "d" (ctl), [isc] "d" (isc << 27), [iib] "Q" (*iib));
|
||||
|
||||
return 0;
|
||||
@@ -442,7 +442,7 @@ EXPORT_SYMBOL_GPL(zpci_write_block);
|
||||
|
||||
static inline void __pciwb_mio(void)
|
||||
{
|
||||
asm volatile (".insn rre,0xb9d50000,0,0\n");
|
||||
asm volatile (".insn rre,0xb9d50000,0,0");
|
||||
}
|
||||
|
||||
void zpci_barrier(void)
|
||||
|
||||
@@ -41,6 +41,9 @@ zpci_attr(segment1, "0x%02x\n", pfip[1]);
|
||||
zpci_attr(segment2, "0x%02x\n", pfip[2]);
|
||||
zpci_attr(segment3, "0x%02x\n", pfip[3]);
|
||||
|
||||
#define ZPCI_FW_ATTR_RO(_name) \
|
||||
static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
|
||||
|
||||
static ssize_t mio_enabled_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -164,6 +167,13 @@ static ssize_t uid_is_unique_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(uid_is_unique);
|
||||
|
||||
static ssize_t uid_checking_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%d\n", zpci_unique_uid ? 1 : 0);
|
||||
}
|
||||
ZPCI_FW_ATTR_RO(uid_checking);
|
||||
|
||||
/* analogous to smbios index */
|
||||
static ssize_t index_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
@@ -233,3 +243,18 @@ const struct attribute_group pfip_attr_group = {
|
||||
.name = "pfip",
|
||||
.attrs = pfip_attrs,
|
||||
};
|
||||
|
||||
static struct attribute *clp_fw_attrs[] = {
|
||||
&uid_checking_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group clp_fw_attr_group = {
|
||||
.name = "clp",
|
||||
.attrs = clp_fw_attrs,
|
||||
};
|
||||
|
||||
int __init __zpci_fw_sysfs_init(void)
|
||||
{
|
||||
return sysfs_create_group(firmware_kobj, &clp_fw_attr_group);
|
||||
}
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/sprintf.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include "input-compat.h"
|
||||
|
||||
@@ -94,6 +95,28 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int input_bits_to_string(char *buf, int buf_size, unsigned long bits,
|
||||
bool skip_empty)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
if (in_compat_syscall()) {
|
||||
u32 dword = bits >> 32;
|
||||
if (dword || !skip_empty)
|
||||
len += snprintf(buf, buf_size, "%x ", dword);
|
||||
|
||||
dword = bits & 0xffffffffUL;
|
||||
if (dword || !skip_empty || len)
|
||||
len += snprintf(buf + len, max(buf_size - len, 0),
|
||||
"%x", dword);
|
||||
} else {
|
||||
if (bits || !skip_empty)
|
||||
len += snprintf(buf, buf_size, "%lx", bits);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int input_event_from_user(const char __user *buffer,
|
||||
@@ -126,6 +149,13 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int input_bits_to_string(char *buf, int buf_size, unsigned long bits,
|
||||
bool skip_empty)
|
||||
{
|
||||
return bits || !skip_empty ?
|
||||
snprintf(buf, buf_size, "%lx", bits) : 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_COMPAT */
|
||||
|
||||
EXPORT_SYMBOL_GPL(input_event_from_user);
|
||||
|
||||
@@ -75,4 +75,7 @@ int input_event_to_user(char __user *buffer,
|
||||
int input_ff_effect_from_user(const char __user *buffer, size_t size,
|
||||
struct ff_effect *effect);
|
||||
|
||||
int input_bits_to_string(char *buf, int buf_size, unsigned long bits,
|
||||
bool skip_empty);
|
||||
|
||||
#endif /* _INPUT_COMPAT_H */
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
+1
-35
@@ -8,6 +8,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/idr.h>
|
||||
@@ -998,41 +999,6 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
||||
static int input_bits_to_string(char *buf, int buf_size,
|
||||
unsigned long bits, bool skip_empty)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
if (in_compat_syscall()) {
|
||||
u32 dword = bits >> 32;
|
||||
if (dword || !skip_empty)
|
||||
len += snprintf(buf, buf_size, "%x ", dword);
|
||||
|
||||
dword = bits & 0xffffffffUL;
|
||||
if (dword || !skip_empty || len)
|
||||
len += snprintf(buf + len, max(buf_size - len, 0),
|
||||
"%x", dword);
|
||||
} else {
|
||||
if (bits || !skip_empty)
|
||||
len += snprintf(buf, buf_size, "%lx", bits);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_COMPAT */
|
||||
|
||||
static int input_bits_to_string(char *buf, int buf_size,
|
||||
unsigned long bits, bool skip_empty)
|
||||
{
|
||||
return bits || !skip_empty ?
|
||||
snprintf(buf, buf_size, "%lx", bits) : 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
static struct proc_dir_entry *proc_bus_input_dir;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* USB/RS232 I-Force joysticks and wheels.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include "iforce.h"
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* USB/RS232 I-Force joysticks and wheels.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include "iforce.h"
|
||||
|
||||
|
||||
@@ -344,7 +344,11 @@ static int psxpad_spi_probe(struct spi_device *spi)
|
||||
/* (PlayStation 1/2 joypad might be possible works 250kHz/500kHz) */
|
||||
spi->controller->min_speed_hz = 125000;
|
||||
spi->controller->max_speed_hz = 125000;
|
||||
spi_setup(spi);
|
||||
err = spi_setup(spi);
|
||||
if (err) {
|
||||
dev_err(&spi->dev, "failed to set up SPI: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* pad settings */
|
||||
psxpad_set_motor_level(pad, 0, 0);
|
||||
|
||||
@@ -262,24 +262,6 @@ config KEYBOARD_GPIO_POLLED
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gpio_keys_polled.
|
||||
|
||||
config KEYBOARD_TCA6416
|
||||
tristate "TCA6416/TCA6408A Keypad Support"
|
||||
depends on I2C
|
||||
help
|
||||
This driver implements basic keypad functionality
|
||||
for keys connected through TCA6416/TCA6408A IO expanders.
|
||||
|
||||
Say Y here if your device has keys connected to
|
||||
TCA6416/TCA6408A IO expander. Your board-specific setup logic
|
||||
must also provide pin-mask details(of which TCA6416 pins
|
||||
are used for keypad).
|
||||
|
||||
If enabled the entire TCA6416 device will be managed through
|
||||
this driver.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tca6416_keypad.
|
||||
|
||||
config KEYBOARD_TCA8418
|
||||
tristate "TCA8418 Keypad Support"
|
||||
depends on I2C
|
||||
|
||||
@@ -23,7 +23,6 @@ obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o
|
||||
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
|
||||
obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o
|
||||
obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
|
||||
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
* on some suggestions by Nicolas Pitre <nico@fluxnic.net>.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
@@ -20,124 +21,148 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <linux/platform_data/keypad-pxa27x.h>
|
||||
/*
|
||||
* Keypad Controller registers
|
||||
*/
|
||||
#define KPC 0x0000 /* Keypad Control register */
|
||||
#define KPDK 0x0008 /* Keypad Direct Key register */
|
||||
#define KPREC 0x0010 /* Keypad Rotary Encoder register */
|
||||
#define KPMK 0x0018 /* Keypad Matrix Key register */
|
||||
#define KPAS 0x0020 /* Keypad Automatic Scan register */
|
||||
#define KPC 0x0000 /* Keypad Control register */
|
||||
#define KPDK 0x0008 /* Keypad Direct Key register */
|
||||
#define KPREC 0x0010 /* Keypad Rotary Encoder register */
|
||||
#define KPMK 0x0018 /* Keypad Matrix Key register */
|
||||
#define KPAS 0x0020 /* Keypad Automatic Scan register */
|
||||
|
||||
/* Keypad Automatic Scan Multiple Key Presser register 0-3 */
|
||||
#define KPASMKP0 0x0028
|
||||
#define KPASMKP1 0x0030
|
||||
#define KPASMKP2 0x0038
|
||||
#define KPASMKP3 0x0040
|
||||
#define KPKDI 0x0048
|
||||
#define KPASMKP0 0x0028
|
||||
#define KPASMKP1 0x0030
|
||||
#define KPASMKP2 0x0038
|
||||
#define KPASMKP3 0x0040
|
||||
#define KPKDI 0x0048
|
||||
|
||||
/* bit definitions */
|
||||
#define KPC_MKRN(n) ((((n) - 1) & 0x7) << 26) /* matrix key row number */
|
||||
#define KPC_MKCN(n) ((((n) - 1) & 0x7) << 23) /* matrix key column number */
|
||||
#define KPC_DKN(n) ((((n) - 1) & 0x7) << 6) /* direct key number */
|
||||
#define KPC_MKRN_MASK GENMASK(28, 26)
|
||||
#define KPC_MKCN_MASK GENMASK(25, 23)
|
||||
#define KPC_DKN_MASK GENMASK(8, 6)
|
||||
#define KPC_MKRN(n) FIELD_PREP(KPC_MKRN_MASK, (n) - 1)
|
||||
#define KPC_MKCN(n) FIELD_PREP(KPC_MKCN_MASK, (n) - 1)
|
||||
#define KPC_DKN(n) FIELD_PREP(KPC_DKN_MASK, (n) - 1)
|
||||
|
||||
#define KPC_AS (0x1 << 30) /* Automatic Scan bit */
|
||||
#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */
|
||||
#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */
|
||||
#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */
|
||||
#define KPC_AS BIT(30) /* Automatic Scan bit */
|
||||
#define KPC_ASACT BIT(29) /* Automatic Scan on Activity */
|
||||
#define KPC_MI BIT(22) /* Matrix interrupt bit */
|
||||
#define KPC_IMKP BIT(21) /* Ignore Multiple Key Press */
|
||||
|
||||
#define KPC_MS(n) (0x1 << (13 + (n))) /* Matrix scan line 'n' */
|
||||
#define KPC_MS_ALL (0xff << 13)
|
||||
#define KPC_MS(n) BIT(13 + (n)) /* Matrix scan line 'n' */
|
||||
#define KPC_MS_ALL GENMASK(20, 13)
|
||||
|
||||
#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */
|
||||
#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */
|
||||
#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */
|
||||
#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */
|
||||
#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */
|
||||
#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */
|
||||
#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */
|
||||
#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */
|
||||
#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */
|
||||
#define KPC_ME BIT(12) /* Matrix Keypad Enable */
|
||||
#define KPC_MIE BIT(11) /* Matrix Interrupt Enable */
|
||||
#define KPC_DK_DEB_SEL BIT(9) /* Direct Keypad Debounce Select */
|
||||
#define KPC_DI BIT(5) /* Direct key interrupt bit */
|
||||
#define KPC_RE_ZERO_DEB BIT(4) /* Rotary Encoder Zero Debounce */
|
||||
#define KPC_REE1 BIT(3) /* Rotary Encoder1 Enable */
|
||||
#define KPC_REE0 BIT(2) /* Rotary Encoder0 Enable */
|
||||
#define KPC_DE BIT(1) /* Direct Keypad Enable */
|
||||
#define KPC_DIE BIT(0) /* Direct Keypad interrupt Enable */
|
||||
|
||||
#define KPDK_DKP (0x1 << 31)
|
||||
#define KPDK_DK(n) ((n) & 0xff)
|
||||
#define KPDK_DKP BIT(31)
|
||||
#define KPDK_DK_MASK GENMASK(7, 0)
|
||||
#define KPDK_DK(n) FIELD_GET(KPDK_DK_MASK, n)
|
||||
|
||||
#define KPREC_OF1 (0x1 << 31)
|
||||
#define kPREC_UF1 (0x1 << 30)
|
||||
#define KPREC_OF0 (0x1 << 15)
|
||||
#define KPREC_UF0 (0x1 << 14)
|
||||
#define KPREC_OF1 BIT(31)
|
||||
#define KPREC_UF1 BIT(30)
|
||||
#define KPREC_OF0 BIT(15)
|
||||
#define KPREC_UF0 BIT(14)
|
||||
|
||||
#define KPREC_RECOUNT0(n) ((n) & 0xff)
|
||||
#define KPREC_RECOUNT1(n) (((n) >> 16) & 0xff)
|
||||
#define KPREC_RECOUNT0_MASK GENMASK(7, 0)
|
||||
#define KPREC_RECOUNT1_MASK GENMASK(23, 16)
|
||||
#define KPREC_RECOUNT0(n) FIELD_GET(KPREC_RECOUNT0_MASK, n)
|
||||
#define KPREC_RECOUNT1(n) FIELD_GET(KPREC_RECOUNT1_MASK, n)
|
||||
|
||||
#define KPMK_MKP (0x1 << 31)
|
||||
#define KPAS_SO (0x1 << 31)
|
||||
#define KPASMKPx_SO (0x1 << 31)
|
||||
#define KPMK_MKP BIT(31)
|
||||
#define KPAS_SO BIT(31)
|
||||
#define KPASMKPx_SO BIT(31)
|
||||
|
||||
#define KPAS_MUKP(n) (((n) >> 26) & 0x1f)
|
||||
#define KPAS_RP(n) (((n) >> 4) & 0xf)
|
||||
#define KPAS_CP(n) ((n) & 0xf)
|
||||
#define KPAS_MUKP_MASK GENMASK(30, 26)
|
||||
#define KPAS_RP_MASK GENMASK(7, 4)
|
||||
#define KPAS_CP_MASK GENMASK(3, 0)
|
||||
#define KPAS_MUKP(n) FIELD_GET(KPAS_MUKP_MASK, n)
|
||||
#define KPAS_RP(n) FIELD_GET(KPAS_RP_MASK, n)
|
||||
#define KPAS_CP(n) FIELD_GET(KPAS_CP_MASK, n)
|
||||
|
||||
#define KPASMKP_MKC_MASK (0xff)
|
||||
#define KPASMKP_MKC_MASK GENMASK(7, 0)
|
||||
|
||||
#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off))
|
||||
#define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off))
|
||||
|
||||
#define MAX_MATRIX_KEY_ROWS 8
|
||||
#define MAX_MATRIX_KEY_COLS 8
|
||||
#define MAX_DIRECT_KEY_NUM 8
|
||||
#define MAX_ROTARY_ENCODERS 2
|
||||
|
||||
#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS)
|
||||
#define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM)
|
||||
|
||||
struct pxa27x_keypad {
|
||||
const struct pxa27x_keypad_platform_data *pdata;
|
||||
struct pxa27x_keypad_rotary {
|
||||
unsigned short *key_codes;
|
||||
int rel_code;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct pxa27x_keypad {
|
||||
struct clk *clk;
|
||||
struct input_dev *input_dev;
|
||||
void __iomem *mmio_base;
|
||||
|
||||
int irq;
|
||||
|
||||
unsigned short keycodes[MAX_KEYPAD_KEYS];
|
||||
int rotary_rel_code[2];
|
||||
|
||||
unsigned int matrix_key_rows;
|
||||
unsigned int matrix_key_cols;
|
||||
unsigned int row_shift;
|
||||
|
||||
/* state row bits of each column scan */
|
||||
uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
|
||||
uint32_t direct_key_state;
|
||||
|
||||
unsigned int direct_key_num;
|
||||
unsigned int direct_key_mask;
|
||||
bool direct_key_low_active;
|
||||
|
||||
/* key debounce interval */
|
||||
unsigned int debounce_interval;
|
||||
|
||||
unsigned short keycodes[MAX_KEYPAD_KEYS];
|
||||
|
||||
/* state row bits of each column scan */
|
||||
u32 matrix_key_state[MAX_MATRIX_KEY_COLS];
|
||||
u32 direct_key_state;
|
||||
|
||||
struct pxa27x_keypad_rotary rotary[MAX_ROTARY_ENCODERS];
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad,
|
||||
struct pxa27x_keypad_platform_data *pdata)
|
||||
static int pxa27x_keypad_matrix_key_parse(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
struct device *dev = input_dev->dev.parent;
|
||||
u32 rows, cols;
|
||||
int error;
|
||||
|
||||
error = matrix_keypad_parse_properties(dev, &rows, &cols);
|
||||
error = matrix_keypad_parse_properties(dev, &keypad->matrix_key_rows,
|
||||
&keypad->matrix_key_cols);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (rows > MAX_MATRIX_KEY_ROWS || cols > MAX_MATRIX_KEY_COLS) {
|
||||
if (keypad->matrix_key_rows > MAX_MATRIX_KEY_ROWS ||
|
||||
keypad->matrix_key_cols > MAX_MATRIX_KEY_COLS) {
|
||||
dev_err(dev, "rows or cols exceeds maximum value\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pdata->matrix_key_rows = rows;
|
||||
pdata->matrix_key_cols = cols;
|
||||
keypad->row_shift = get_count_order(keypad->matrix_key_cols);
|
||||
|
||||
error = matrix_keypad_build_keymap(NULL, NULL,
|
||||
pdata->matrix_key_rows,
|
||||
pdata->matrix_key_cols,
|
||||
keypad->matrix_key_rows,
|
||||
keypad->matrix_key_cols,
|
||||
keypad->keycodes, input_dev);
|
||||
if (error)
|
||||
return error;
|
||||
@@ -145,20 +170,17 @@ static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad,
|
||||
struct pxa27x_keypad_platform_data *pdata)
|
||||
static int pxa27x_keypad_direct_key_parse(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
struct device *dev = input_dev->dev.parent;
|
||||
struct device_node *np = dev->of_node;
|
||||
const __be16 *prop;
|
||||
unsigned short code;
|
||||
unsigned int proplen, size;
|
||||
int count;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
error = of_property_read_u32(np, "marvell,direct-key-count",
|
||||
&pdata->direct_key_num);
|
||||
error = device_property_read_u32(dev, "marvell,direct-key-count",
|
||||
&keypad->direct_key_num);
|
||||
if (error) {
|
||||
/*
|
||||
* If do not have marvel,direct-key-count defined,
|
||||
@@ -167,151 +189,121 @@ static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad,
|
||||
return error == -EINVAL ? 0 : error;
|
||||
}
|
||||
|
||||
error = of_property_read_u32(np, "marvell,direct-key-mask",
|
||||
&pdata->direct_key_mask);
|
||||
error = device_property_read_u32(dev, "marvell,direct-key-mask",
|
||||
&keypad->direct_key_mask);
|
||||
if (error) {
|
||||
if (error != -EINVAL)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* If marvell,direct-key-mask is not defined, driver will use
|
||||
* default value. Default value is set when configure the keypad.
|
||||
* a default value based on number of direct keys set up.
|
||||
* The default value is calculated in pxa27x_keypad_config().
|
||||
*/
|
||||
pdata->direct_key_mask = 0;
|
||||
keypad->direct_key_mask = 0;
|
||||
}
|
||||
|
||||
pdata->direct_key_low_active = of_property_read_bool(np,
|
||||
"marvell,direct-key-low-active");
|
||||
keypad->direct_key_low_active =
|
||||
device_property_read_bool(dev, "marvell,direct-key-low-active");
|
||||
|
||||
prop = of_get_property(np, "marvell,direct-key-map", &proplen);
|
||||
if (!prop)
|
||||
count = device_property_count_u16(dev, "marvell,direct-key-map");
|
||||
if (count <= 0 || count > MAX_DIRECT_KEY_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
if (proplen % sizeof(u16))
|
||||
return -EINVAL;
|
||||
error = device_property_read_u16_array(dev, "marvell,direct-key-map",
|
||||
&keypad->keycodes[MAX_MATRIX_KEY_NUM],
|
||||
count);
|
||||
|
||||
size = proplen / sizeof(u16);
|
||||
|
||||
/* Only MAX_DIRECT_KEY_NUM is accepted.*/
|
||||
if (size > MAX_DIRECT_KEY_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
code = be16_to_cpup(prop + i);
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = code;
|
||||
for (i = 0; i < count; i++) {
|
||||
code = keypad->keycodes[MAX_MATRIX_KEY_NUM + i];
|
||||
__set_bit(code, input_dev->keybit);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa27x_keypad_rotary_parse_dt(struct pxa27x_keypad *keypad,
|
||||
struct pxa27x_keypad_platform_data *pdata)
|
||||
static int pxa27x_keypad_rotary_parse(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
const __be32 *prop;
|
||||
int i, relkey_ret;
|
||||
unsigned int code, proplen;
|
||||
const char *rotaryname[2] = {
|
||||
"marvell,rotary0", "marvell,rotary1"};
|
||||
const char relkeyname[] = {"marvell,rotary-rel-key"};
|
||||
static const char * const rotaryname[] = { "marvell,rotary0", "marvell,rotary1" };
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
struct device *dev = input_dev->dev.parent;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct pxa27x_keypad_rotary *encoder;
|
||||
unsigned int code;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
relkey_ret = of_property_read_u32(np, relkeyname, &code);
|
||||
/* if can read correct rotary key-code, we do not need this. */
|
||||
if (relkey_ret == 0) {
|
||||
unsigned short relcode;
|
||||
error = device_property_read_u32(dev, "marvell,rotary-rel-key", &code);
|
||||
if (!error) {
|
||||
for (i = 0; i < MAX_ROTARY_ENCODERS; i++, code >>= 16) {
|
||||
encoder = &keypad->rotary[i];
|
||||
encoder->enabled = true;
|
||||
encoder->rel_code = code & 0xffff;
|
||||
input_set_capability(input_dev, EV_REL, encoder->rel_code);
|
||||
}
|
||||
|
||||
/* rotary0 taks lower half, rotary1 taks upper half. */
|
||||
relcode = code & 0xffff;
|
||||
pdata->rotary0_rel_code = (code & 0xffff);
|
||||
__set_bit(relcode, input_dev->relbit);
|
||||
|
||||
relcode = code >> 16;
|
||||
pdata->rotary1_rel_code = relcode;
|
||||
__set_bit(relcode, input_dev->relbit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
prop = of_get_property(np, rotaryname[i], &proplen);
|
||||
for (i = 0; i < MAX_ROTARY_ENCODERS; i++) {
|
||||
encoder = &keypad->rotary[i];
|
||||
|
||||
/*
|
||||
* If the prop is not set, it means keypad does not need
|
||||
* initialize the rotaryX.
|
||||
*/
|
||||
if (!prop)
|
||||
if (!device_property_present(dev, rotaryname[i]))
|
||||
continue;
|
||||
|
||||
code = be32_to_cpup(prop);
|
||||
error = device_property_read_u32(dev, rotaryname[i], &code);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* Not all up/down key code are valid.
|
||||
* Now we depends on direct-rel-code.
|
||||
*/
|
||||
if ((!(code & 0xffff) || !(code >> 16)) && relkey_ret) {
|
||||
return relkey_ret;
|
||||
} else {
|
||||
unsigned int n = MAX_MATRIX_KEY_NUM + (i << 1);
|
||||
unsigned short keycode;
|
||||
if (!(code & 0xffff) || !(code >> 16))
|
||||
return -EINVAL;
|
||||
|
||||
keycode = code & 0xffff;
|
||||
keypad->keycodes[n] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
encoder->enabled = true;
|
||||
encoder->rel_code = -1;
|
||||
encoder->key_codes = &keypad->keycodes[MAX_MATRIX_KEY_NUM + i * 2];
|
||||
encoder->key_codes[0] = code & 0xffff;
|
||||
encoder->key_codes[1] = code >> 16;
|
||||
|
||||
keycode = code >> 16;
|
||||
keypad->keycodes[n + 1] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
|
||||
if (i == 0)
|
||||
pdata->rotary0_rel_code = -1;
|
||||
else
|
||||
pdata->rotary1_rel_code = -1;
|
||||
}
|
||||
if (i == 0)
|
||||
pdata->enable_rotary0 = 1;
|
||||
else
|
||||
pdata->enable_rotary1 = 1;
|
||||
input_set_capability(input_dev, EV_KEY, encoder->key_codes[0]);
|
||||
input_set_capability(input_dev, EV_KEY, encoder->key_codes[1]);
|
||||
}
|
||||
|
||||
keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
|
||||
keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
|
||||
static int pxa27x_keypad_parse_properties(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
struct device *dev = input_dev->dev.parent;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct pxa27x_keypad_platform_data *pdata;
|
||||
int error;
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
dev_err(dev, "failed to allocate memory for pdata\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
error = pxa27x_keypad_matrix_key_parse_dt(keypad, pdata);
|
||||
error = pxa27x_keypad_matrix_key_parse(keypad);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to parse matrix key\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = pxa27x_keypad_direct_key_parse_dt(keypad, pdata);
|
||||
error = pxa27x_keypad_direct_key_parse(keypad);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to parse direct key\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = pxa27x_keypad_rotary_parse_dt(keypad, pdata);
|
||||
error = pxa27x_keypad_rotary_parse(keypad);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to parse rotary key\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = of_property_read_u32(np, "marvell,debounce-interval",
|
||||
&pdata->debounce_interval);
|
||||
error = device_property_read_u32(dev, "marvell,debounce-interval",
|
||||
&keypad->debounce_interval);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to parse debounce-interval\n");
|
||||
return error;
|
||||
@@ -323,95 +315,15 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
|
||||
*/
|
||||
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
|
||||
|
||||
keypad->pdata = pdata;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
dev_info(keypad->input_dev->dev.parent, "missing platform data\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
unsigned short keycode;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
error = matrix_keypad_build_keymap(pdata->matrix_keymap_data, NULL,
|
||||
pdata->matrix_key_rows,
|
||||
pdata->matrix_key_cols,
|
||||
keypad->keycodes, input_dev);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/*
|
||||
* The keycodes may not only include matrix keys but also the direct
|
||||
* or rotary keys.
|
||||
*/
|
||||
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
|
||||
|
||||
/* For direct keys. */
|
||||
for (i = 0; i < pdata->direct_key_num; i++) {
|
||||
keycode = pdata->direct_key_map[i];
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
}
|
||||
|
||||
if (pdata->enable_rotary0) {
|
||||
if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
|
||||
keycode = pdata->rotary0_up_key;
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + 0] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
|
||||
keycode = pdata->rotary0_down_key;
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + 1] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
|
||||
keypad->rotary_rel_code[0] = -1;
|
||||
} else {
|
||||
keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
|
||||
__set_bit(pdata->rotary0_rel_code, input_dev->relbit);
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->enable_rotary1) {
|
||||
if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
|
||||
keycode = pdata->rotary1_up_key;
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + 2] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
|
||||
keycode = pdata->rotary1_down_key;
|
||||
keypad->keycodes[MAX_MATRIX_KEY_NUM + 3] = keycode;
|
||||
__set_bit(keycode, input_dev->keybit);
|
||||
|
||||
keypad->rotary_rel_code[1] = -1;
|
||||
} else {
|
||||
keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
|
||||
__set_bit(pdata->rotary1_rel_code, input_dev->relbit);
|
||||
}
|
||||
}
|
||||
|
||||
__clear_bit(KEY_RESERVED, input_dev->keybit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
int row, col, num_keys_pressed = 0;
|
||||
uint32_t new_state[MAX_MATRIX_KEY_COLS];
|
||||
uint32_t kpas = keypad_readl(KPAS);
|
||||
u32 new_state[MAX_MATRIX_KEY_COLS];
|
||||
u32 kpas = keypad_readl(KPAS);
|
||||
|
||||
num_keys_pressed = KPAS_MUKP(kpas);
|
||||
|
||||
@@ -425,19 +337,19 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
|
||||
row = KPAS_RP(kpas);
|
||||
|
||||
/* if invalid row/col, treat as no key pressed */
|
||||
if (col >= pdata->matrix_key_cols ||
|
||||
row >= pdata->matrix_key_rows)
|
||||
if (col >= keypad->matrix_key_cols ||
|
||||
row >= keypad->matrix_key_rows)
|
||||
goto scan;
|
||||
|
||||
new_state[col] = (1 << row);
|
||||
new_state[col] = BIT(row);
|
||||
goto scan;
|
||||
}
|
||||
|
||||
if (num_keys_pressed > 1) {
|
||||
uint32_t kpasmkp0 = keypad_readl(KPASMKP0);
|
||||
uint32_t kpasmkp1 = keypad_readl(KPASMKP1);
|
||||
uint32_t kpasmkp2 = keypad_readl(KPASMKP2);
|
||||
uint32_t kpasmkp3 = keypad_readl(KPASMKP3);
|
||||
u32 kpasmkp0 = keypad_readl(KPASMKP0);
|
||||
u32 kpasmkp1 = keypad_readl(KPASMKP1);
|
||||
u32 kpasmkp2 = keypad_readl(KPASMKP2);
|
||||
u32 kpasmkp3 = keypad_readl(KPASMKP3);
|
||||
|
||||
new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK;
|
||||
new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK;
|
||||
@@ -449,23 +361,23 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
|
||||
new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK;
|
||||
}
|
||||
scan:
|
||||
for (col = 0; col < pdata->matrix_key_cols; col++) {
|
||||
uint32_t bits_changed;
|
||||
for (col = 0; col < keypad->matrix_key_cols; col++) {
|
||||
u32 bits_changed;
|
||||
int code;
|
||||
|
||||
bits_changed = keypad->matrix_key_state[col] ^ new_state[col];
|
||||
if (bits_changed == 0)
|
||||
continue;
|
||||
|
||||
for (row = 0; row < pdata->matrix_key_rows; row++) {
|
||||
if ((bits_changed & (1 << row)) == 0)
|
||||
for (row = 0; row < keypad->matrix_key_rows; row++) {
|
||||
if ((bits_changed & BIT(row)) == 0)
|
||||
continue;
|
||||
|
||||
code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
|
||||
|
||||
input_event(input_dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(input_dev, keypad->keycodes[code],
|
||||
new_state[col] & (1 << row));
|
||||
new_state[col] & BIT(row));
|
||||
}
|
||||
}
|
||||
input_sync(input_dev);
|
||||
@@ -474,7 +386,7 @@ scan:
|
||||
|
||||
#define DEFAULT_KPREC (0x007f007f)
|
||||
|
||||
static inline int rotary_delta(uint32_t kprec)
|
||||
static inline int rotary_delta(u32 kprec)
|
||||
{
|
||||
if (kprec & KPREC_OF0)
|
||||
return (kprec & 0xff) + 0x7f;
|
||||
@@ -486,14 +398,16 @@ static inline int rotary_delta(uint32_t kprec)
|
||||
|
||||
static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
|
||||
{
|
||||
struct pxa27x_keypad_rotary *encoder = &keypad->rotary[r];
|
||||
struct input_dev *dev = keypad->input_dev;
|
||||
|
||||
if (delta == 0)
|
||||
if (!encoder->enabled || delta == 0)
|
||||
return;
|
||||
|
||||
if (keypad->rotary_rel_code[r] == -1) {
|
||||
int code = MAX_MATRIX_KEY_NUM + 2 * r + (delta > 0 ? 0 : 1);
|
||||
unsigned char keycode = keypad->keycodes[code];
|
||||
if (encoder->rel_code == -1) {
|
||||
int idx = delta > 0 ? 0 : 1;
|
||||
int code = MAX_MATRIX_KEY_NUM + 2 * r + idx;
|
||||
unsigned char keycode = encoder->key_codes[idx];
|
||||
|
||||
/* simulate a press-n-release */
|
||||
input_event(dev, EV_MSC, MSC_SCAN, code);
|
||||
@@ -503,45 +417,43 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
|
||||
input_report_key(dev, keycode, 0);
|
||||
input_sync(dev);
|
||||
} else {
|
||||
input_report_rel(dev, keypad->rotary_rel_code[r], delta);
|
||||
input_report_rel(dev, encoder->rel_code, delta);
|
||||
input_sync(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
||||
uint32_t kprec;
|
||||
u32 kprec;
|
||||
int i;
|
||||
|
||||
/* read and reset to default count value */
|
||||
kprec = keypad_readl(KPREC);
|
||||
keypad_writel(KPREC, DEFAULT_KPREC);
|
||||
|
||||
if (pdata->enable_rotary0)
|
||||
for (i = 0; i < MAX_ROTARY_ENCODERS; i++) {
|
||||
report_rotary_event(keypad, 0, rotary_delta(kprec));
|
||||
|
||||
if (pdata->enable_rotary1)
|
||||
report_rotary_event(keypad, 1, rotary_delta(kprec >> 16));
|
||||
kprec >>= 16;
|
||||
}
|
||||
}
|
||||
|
||||
static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
||||
struct input_dev *input_dev = keypad->input_dev;
|
||||
unsigned int new_state;
|
||||
uint32_t kpdk, bits_changed;
|
||||
u32 kpdk, bits_changed;
|
||||
int i;
|
||||
|
||||
kpdk = keypad_readl(KPDK);
|
||||
|
||||
if (pdata->enable_rotary0 || pdata->enable_rotary1)
|
||||
if (keypad->rotary[0].enabled || keypad->rotary[1].enabled)
|
||||
pxa27x_keypad_scan_rotary(keypad);
|
||||
|
||||
/*
|
||||
* The KPDR_DK only output the key pin level, so it relates to board,
|
||||
* and low level may be active.
|
||||
*/
|
||||
if (pdata->direct_key_low_active)
|
||||
if (keypad->direct_key_low_active)
|
||||
new_state = ~KPDK_DK(kpdk) & keypad->direct_key_mask;
|
||||
else
|
||||
new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
|
||||
@@ -551,34 +463,24 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
|
||||
if (bits_changed == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < pdata->direct_key_num; i++) {
|
||||
if (bits_changed & (1 << i)) {
|
||||
for (i = 0; i < keypad->direct_key_num; i++) {
|
||||
if (bits_changed & BIT(i)) {
|
||||
int code = MAX_MATRIX_KEY_NUM + i;
|
||||
|
||||
input_event(input_dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(input_dev, keypad->keycodes[code],
|
||||
new_state & (1 << i));
|
||||
new_state & BIT(i));
|
||||
}
|
||||
}
|
||||
input_sync(input_dev);
|
||||
keypad->direct_key_state = new_state;
|
||||
}
|
||||
|
||||
static void clear_wakeup_event(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
||||
|
||||
if (pdata->clear_wakeup_event)
|
||||
(pdata->clear_wakeup_event)();
|
||||
}
|
||||
|
||||
static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct pxa27x_keypad *keypad = dev_id;
|
||||
unsigned long kpc = keypad_readl(KPC);
|
||||
|
||||
clear_wakeup_event(keypad);
|
||||
|
||||
if (kpc & KPC_DI)
|
||||
pxa27x_keypad_scan_direct(keypad);
|
||||
|
||||
@@ -590,7 +492,6 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
|
||||
|
||||
static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
|
||||
{
|
||||
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
|
||||
unsigned int mask = 0, direct_key_num = 0;
|
||||
unsigned long kpc = 0;
|
||||
|
||||
@@ -598,36 +499,34 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
|
||||
keypad_readl(KPC);
|
||||
|
||||
/* enable matrix keys with automatic scan */
|
||||
if (pdata->matrix_key_rows && pdata->matrix_key_cols) {
|
||||
if (keypad->matrix_key_rows && keypad->matrix_key_cols) {
|
||||
kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL;
|
||||
kpc |= KPC_MKRN(pdata->matrix_key_rows) |
|
||||
KPC_MKCN(pdata->matrix_key_cols);
|
||||
kpc |= KPC_MKRN(keypad->matrix_key_rows) |
|
||||
KPC_MKCN(keypad->matrix_key_cols);
|
||||
}
|
||||
|
||||
/* enable rotary key, debounce interval same as direct keys */
|
||||
if (pdata->enable_rotary0) {
|
||||
if (keypad->rotary[0].enabled) {
|
||||
mask |= 0x03;
|
||||
direct_key_num = 2;
|
||||
kpc |= KPC_REE0;
|
||||
}
|
||||
|
||||
if (pdata->enable_rotary1) {
|
||||
if (keypad->rotary[1].enabled) {
|
||||
mask |= 0x0c;
|
||||
direct_key_num = 4;
|
||||
kpc |= KPC_REE1;
|
||||
}
|
||||
|
||||
if (pdata->direct_key_num > direct_key_num)
|
||||
direct_key_num = pdata->direct_key_num;
|
||||
if (keypad->direct_key_num > direct_key_num)
|
||||
direct_key_num = keypad->direct_key_num;
|
||||
|
||||
/*
|
||||
* Direct keys usage may not start from KP_DKIN0, check the platfrom
|
||||
* mask data to config the specific.
|
||||
*/
|
||||
if (pdata->direct_key_mask)
|
||||
keypad->direct_key_mask = pdata->direct_key_mask;
|
||||
else
|
||||
keypad->direct_key_mask = ((1 << direct_key_num) - 1) & ~mask;
|
||||
if (!keypad->direct_key_mask)
|
||||
keypad->direct_key_mask = GENMASK(direct_key_num - 1, 0) & ~mask;
|
||||
|
||||
/* enable direct key */
|
||||
if (direct_key_num)
|
||||
@@ -635,7 +534,7 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
|
||||
|
||||
keypad_writel(KPC, kpc | KPC_RE_ZERO_DEB);
|
||||
keypad_writel(KPREC, DEFAULT_KPREC);
|
||||
keypad_writel(KPKDI, pdata->debounce_interval);
|
||||
keypad_writel(KPKDI, keypad->debounce_interval);
|
||||
}
|
||||
|
||||
static int pxa27x_keypad_open(struct input_dev *dev)
|
||||
@@ -709,19 +608,12 @@ static int pxa27x_keypad_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(pxa27x_keypad_pm_ops,
|
||||
pxa27x_keypad_suspend, pxa27x_keypad_resume);
|
||||
|
||||
|
||||
static int pxa27x_keypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct pxa27x_keypad_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct pxa27x_keypad *keypad;
|
||||
struct input_dev *input_dev;
|
||||
int irq, error;
|
||||
|
||||
/* Driver need build keycode from device tree or pdata */
|
||||
if (!np && !pdata)
|
||||
return -EINVAL;
|
||||
int irq;
|
||||
int error;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
@@ -736,7 +628,6 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
keypad->pdata = pdata;
|
||||
keypad->input_dev = input_dev;
|
||||
keypad->irq = irq;
|
||||
|
||||
@@ -765,29 +656,12 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
if (pdata) {
|
||||
error = pxa27x_keypad_build_keycode(keypad);
|
||||
} else {
|
||||
error = pxa27x_keypad_build_keycode_from_dt(keypad);
|
||||
/*
|
||||
* Data that we get from DT resides in dynamically
|
||||
* allocated memory so we need to update our pdata
|
||||
* pointer.
|
||||
*/
|
||||
pdata = keypad->pdata;
|
||||
}
|
||||
error = pxa27x_keypad_parse_properties(keypad);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to build keycode\n");
|
||||
dev_err(&pdev->dev, "failed to parse keypad properties\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
keypad->row_shift = get_count_order(pdata->matrix_key_cols);
|
||||
|
||||
if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) ||
|
||||
(pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {
|
||||
input_dev->evbit[0] |= BIT_MASK(EV_REL);
|
||||
}
|
||||
|
||||
error = devm_request_irq(&pdev->dev, irq, pxa27x_keypad_irq_handler,
|
||||
0, pdev->name, keypad);
|
||||
if (error) {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -22,7 +23,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_data/keyboard-spear.h>
|
||||
|
||||
/* Keyboard Registers */
|
||||
#define MODE_CTL_REG 0x00
|
||||
@@ -56,13 +56,12 @@ struct spear_kbd {
|
||||
void __iomem *io_base;
|
||||
struct clk *clk;
|
||||
unsigned int irq;
|
||||
unsigned int mode;
|
||||
unsigned int suspended_rate;
|
||||
u32 mode;
|
||||
u32 suspended_rate;
|
||||
u32 mode_ctl_reg;
|
||||
unsigned short last_key;
|
||||
unsigned short keycodes[NUM_ROWS * NUM_COLS];
|
||||
bool rep;
|
||||
bool irq_wake_enabled;
|
||||
u32 mode_ctl_reg;
|
||||
};
|
||||
|
||||
static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
|
||||
@@ -143,46 +142,8 @@ static void spear_kbd_close(struct input_dev *dev)
|
||||
kbd->last_key = KEY_RESERVED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int spear_kbd_parse_dt(struct platform_device *pdev,
|
||||
struct spear_kbd *kbd)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int error;
|
||||
u32 val, suspended_rate;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "Missing DT data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(np, "autorepeat"))
|
||||
kbd->rep = true;
|
||||
|
||||
if (of_property_read_u32(np, "suspended_rate", &suspended_rate))
|
||||
kbd->suspended_rate = suspended_rate;
|
||||
|
||||
error = of_property_read_u32(np, "st,mode", &val);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "DT: Invalid or missing mode\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
kbd->mode = val;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int spear_kbd_parse_dt(struct platform_device *pdev,
|
||||
struct spear_kbd *kbd)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int spear_kbd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct kbd_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL;
|
||||
struct spear_kbd *kbd;
|
||||
struct input_dev *input_dev;
|
||||
int irq;
|
||||
@@ -198,6 +159,14 @@ static int spear_kbd_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
error = device_property_read_u32(&pdev->dev, "st,mode", &kbd->mode);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "Invalid or missing mode\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
device_property_read_u32(&pdev->dev, "suspended_rate", &kbd->suspended_rate);
|
||||
|
||||
input_dev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input_dev) {
|
||||
dev_err(&pdev->dev, "unable to allocate input device\n");
|
||||
@@ -207,16 +176,6 @@ static int spear_kbd_probe(struct platform_device *pdev)
|
||||
kbd->input = input_dev;
|
||||
kbd->irq = irq;
|
||||
|
||||
if (!pdata) {
|
||||
error = spear_kbd_parse_dt(pdev, kbd);
|
||||
if (error)
|
||||
return error;
|
||||
} else {
|
||||
kbd->mode = pdata->mode;
|
||||
kbd->rep = pdata->rep;
|
||||
kbd->suspended_rate = pdata->suspended_rate;
|
||||
}
|
||||
|
||||
kbd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||
if (IS_ERR(kbd->io_base))
|
||||
return PTR_ERR(kbd->io_base);
|
||||
@@ -234,21 +193,21 @@ static int spear_kbd_probe(struct platform_device *pdev)
|
||||
input_dev->open = spear_kbd_open;
|
||||
input_dev->close = spear_kbd_close;
|
||||
|
||||
error = matrix_keypad_build_keymap(keymap, NULL, NUM_ROWS, NUM_COLS,
|
||||
error = matrix_keypad_build_keymap(NULL, NULL, NUM_ROWS, NUM_COLS,
|
||||
kbd->keycodes, input_dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "Failed to build keymap\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
if (kbd->rep)
|
||||
if (device_property_read_bool(&pdev->dev, "autorepeat"))
|
||||
__set_bit(EV_REP, input_dev->evbit);
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
|
||||
input_set_drvdata(input_dev, kbd);
|
||||
|
||||
error = devm_request_irq(&pdev->dev, irq, spear_kbd_interrupt, 0,
|
||||
"keyboard", kbd);
|
||||
"keyboard", kbd);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "request_irq failed\n");
|
||||
return error;
|
||||
|
||||
@@ -1,305 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Driver for keys on TCA6416 I2C IO expander
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments
|
||||
*
|
||||
* Author : Sriramakrishnan.A.G. <srk@ti.com>
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/tca6416_keypad.h>
|
||||
|
||||
#define TCA6416_INPUT 0
|
||||
#define TCA6416_OUTPUT 1
|
||||
#define TCA6416_INVERT 2
|
||||
#define TCA6416_DIRECTION 3
|
||||
|
||||
#define TCA6416_POLL_INTERVAL 100 /* msec */
|
||||
|
||||
static const struct i2c_device_id tca6416_id[] = {
|
||||
{ "tca6416-keys", 16, },
|
||||
{ "tca6408-keys", 8, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tca6416_id);
|
||||
|
||||
struct tca6416_keypad_chip {
|
||||
uint16_t reg_output;
|
||||
uint16_t reg_direction;
|
||||
uint16_t reg_input;
|
||||
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input;
|
||||
int io_size;
|
||||
u16 pinmask;
|
||||
bool use_polling;
|
||||
struct tca6416_button buttons[];
|
||||
};
|
||||
|
||||
static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = chip->io_size > 8 ?
|
||||
i2c_smbus_write_word_data(chip->client, reg << 1, val) :
|
||||
i2c_smbus_write_byte_data(chip->client, reg, val);
|
||||
if (error < 0) {
|
||||
dev_err(&chip->client->dev,
|
||||
"%s failed, reg: %d, val: %d, error: %d\n",
|
||||
__func__, reg, val, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = chip->io_size > 8 ?
|
||||
i2c_smbus_read_word_data(chip->client, reg << 1) :
|
||||
i2c_smbus_read_byte_data(chip->client, reg);
|
||||
if (retval < 0) {
|
||||
dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n",
|
||||
__func__, reg, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
*val = (u16)retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tca6416_keys_scan(struct input_dev *input)
|
||||
{
|
||||
struct tca6416_keypad_chip *chip = input_get_drvdata(input);
|
||||
u16 reg_val, val;
|
||||
int error, i, pin_index;
|
||||
|
||||
error = tca6416_read_reg(chip, TCA6416_INPUT, ®_val);
|
||||
if (error)
|
||||
return;
|
||||
|
||||
reg_val &= chip->pinmask;
|
||||
|
||||
/* Figure out which lines have changed */
|
||||
val = reg_val ^ chip->reg_input;
|
||||
chip->reg_input = reg_val;
|
||||
|
||||
for (i = 0, pin_index = 0; i < 16; i++) {
|
||||
if (val & (1 << i)) {
|
||||
struct tca6416_button *button = &chip->buttons[pin_index];
|
||||
unsigned int type = button->type ?: EV_KEY;
|
||||
int state = ((reg_val & (1 << i)) ? 1 : 0)
|
||||
^ button->active_low;
|
||||
|
||||
input_event(input, type, button->code, !!state);
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
if (chip->pinmask & (1 << i))
|
||||
pin_index++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is threaded IRQ handler and this can (and will) sleep.
|
||||
*/
|
||||
static irqreturn_t tca6416_keys_isr(int irq, void *dev_id)
|
||||
{
|
||||
tca6416_keys_scan(dev_id);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tca6416_keys_open(struct input_dev *dev)
|
||||
{
|
||||
struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
|
||||
|
||||
if (!chip->use_polling) {
|
||||
/* Get initial device state in case it has switches */
|
||||
tca6416_keys_scan(dev);
|
||||
enable_irq(chip->client->irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tca6416_keys_close(struct input_dev *dev)
|
||||
{
|
||||
struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
|
||||
|
||||
if (!chip->use_polling)
|
||||
disable_irq(chip->client->irq);
|
||||
}
|
||||
|
||||
static int tca6416_setup_registers(struct tca6416_keypad_chip *chip)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = tca6416_read_reg(chip, TCA6416_OUTPUT, &chip->reg_output);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* ensure that keypad pins are set to input */
|
||||
error = tca6416_write_reg(chip, TCA6416_DIRECTION,
|
||||
chip->reg_direction | chip->pinmask);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = tca6416_read_reg(chip, TCA6416_INPUT, &chip->reg_input);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
chip->reg_input &= chip->pinmask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tca6416_keypad_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct i2c_device_id *id = i2c_client_get_device_id(client);
|
||||
struct tca6416_keys_platform_data *pdata;
|
||||
struct tca6416_keypad_chip *chip;
|
||||
struct input_dev *input;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
/* Check functionality */
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
|
||||
dev_err(&client->dev, "%s adapter not supported\n",
|
||||
dev_driver_string(&client->adapter->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata = dev_get_platdata(&client->dev);
|
||||
if (!pdata) {
|
||||
dev_dbg(&client->dev, "no platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip = devm_kzalloc(&client->dev,
|
||||
struct_size(chip, buttons, pdata->nbuttons),
|
||||
GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
input = devm_input_allocate_device(&client->dev);
|
||||
if (!input)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->client = client;
|
||||
chip->input = input;
|
||||
chip->io_size = id->driver_data;
|
||||
chip->pinmask = pdata->pinmask;
|
||||
chip->use_polling = pdata->use_polling;
|
||||
|
||||
input->phys = "tca6416-keys/input0";
|
||||
input->name = client->name;
|
||||
|
||||
input->open = tca6416_keys_open;
|
||||
input->close = tca6416_keys_close;
|
||||
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->id.vendor = 0x0001;
|
||||
input->id.product = 0x0001;
|
||||
input->id.version = 0x0100;
|
||||
|
||||
/* Enable auto repeat feature of Linux input subsystem */
|
||||
if (pdata->rep)
|
||||
__set_bit(EV_REP, input->evbit);
|
||||
|
||||
for (i = 0; i < pdata->nbuttons; i++) {
|
||||
unsigned int type;
|
||||
|
||||
chip->buttons[i] = pdata->buttons[i];
|
||||
type = (pdata->buttons[i].type) ?: EV_KEY;
|
||||
input_set_capability(input, type, pdata->buttons[i].code);
|
||||
}
|
||||
|
||||
input_set_drvdata(input, chip);
|
||||
|
||||
/*
|
||||
* Initialize cached registers from their original values.
|
||||
* we can't share this chip with another i2c master.
|
||||
*/
|
||||
error = tca6416_setup_registers(chip);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (chip->use_polling) {
|
||||
error = input_setup_polling(input, tca6416_keys_scan);
|
||||
if (error) {
|
||||
dev_err(&client->dev, "Failed to setup polling\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
input_set_poll_interval(input, TCA6416_POLL_INTERVAL);
|
||||
} else {
|
||||
error = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, tca6416_keys_isr,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_ONESHOT |
|
||||
IRQF_NO_AUTOEN,
|
||||
"tca6416-keypad", input);
|
||||
if (error) {
|
||||
dev_dbg(&client->dev,
|
||||
"Unable to claim irq %d; error %d\n",
|
||||
client->irq, error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
dev_dbg(&client->dev,
|
||||
"Unable to register input device, error: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver tca6416_keypad_driver = {
|
||||
.driver = {
|
||||
.name = "tca6416-keypad",
|
||||
},
|
||||
.probe = tca6416_keypad_probe,
|
||||
.id_table = tca6416_id,
|
||||
};
|
||||
|
||||
static int __init tca6416_keypad_init(void)
|
||||
{
|
||||
return i2c_add_driver(&tca6416_keypad_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(tca6416_keypad_init);
|
||||
|
||||
static void __exit tca6416_keypad_exit(void)
|
||||
{
|
||||
i2c_del_driver(&tca6416_keypad_driver);
|
||||
}
|
||||
module_exit(tca6416_keypad_exit);
|
||||
|
||||
MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>");
|
||||
MODULE_DESCRIPTION("Keypad driver over tca6416 IO expander");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -373,18 +373,7 @@ static struct i2c_driver tca8418_keypad_driver = {
|
||||
.probe = tca8418_keypad_probe,
|
||||
.id_table = tca8418_id,
|
||||
};
|
||||
|
||||
static int __init tca8418_keypad_init(void)
|
||||
{
|
||||
return i2c_add_driver(&tca8418_keypad_driver);
|
||||
}
|
||||
subsys_initcall(tca8418_keypad_init);
|
||||
|
||||
static void __exit tca8418_keypad_exit(void)
|
||||
{
|
||||
i2c_del_driver(&tca8418_keypad_driver);
|
||||
}
|
||||
module_exit(tca8418_keypad_exit);
|
||||
module_i2c_driver(tca8418_keypad_driver);
|
||||
|
||||
MODULE_AUTHOR("Kyle Manna <kyle.manna@fuel7.com>");
|
||||
MODULE_DESCRIPTION("Keypad driver for TCA8418");
|
||||
|
||||
@@ -28,10 +28,6 @@
|
||||
* an internal state machine that decodes pressed keys, including
|
||||
* multi-key combinations.
|
||||
*
|
||||
* This driver lets boards define what keycodes they wish to report for
|
||||
* which scancodes, as part of the "struct twl4030_keypad_data" used in
|
||||
* the probe() routine.
|
||||
*
|
||||
* See the TPS65950 documentation; that's the general availability
|
||||
* version of the TWL5030 second generation part.
|
||||
*/
|
||||
@@ -47,7 +43,6 @@
|
||||
struct twl4030_keypad {
|
||||
unsigned short keymap[TWL4030_KEYMAP_SIZE];
|
||||
u16 kp_state[TWL4030_MAX_ROWS];
|
||||
bool autorepeat;
|
||||
unsigned int n_rows;
|
||||
unsigned int n_cols;
|
||||
int irq;
|
||||
@@ -322,8 +317,6 @@ static int twl4030_kp_program(struct twl4030_keypad *kp)
|
||||
*/
|
||||
static int twl4030_kp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_keypad_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
const struct matrix_keymap_data *keymap_data = NULL;
|
||||
struct twl4030_keypad *kp;
|
||||
struct input_dev *input;
|
||||
u8 reg;
|
||||
@@ -350,24 +343,10 @@ static int twl4030_kp_probe(struct platform_device *pdev)
|
||||
input->id.product = 0x0001;
|
||||
input->id.version = 0x0003;
|
||||
|
||||
if (pdata) {
|
||||
if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
|
||||
dev_err(&pdev->dev, "Missing platform_data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kp->n_rows = pdata->rows;
|
||||
kp->n_cols = pdata->cols;
|
||||
kp->autorepeat = pdata->rep;
|
||||
keymap_data = pdata->keymap_data;
|
||||
} else {
|
||||
error = matrix_keypad_parse_properties(&pdev->dev, &kp->n_rows,
|
||||
&kp->n_cols);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
kp->autorepeat = true;
|
||||
}
|
||||
error = matrix_keypad_parse_properties(&pdev->dev,
|
||||
&kp->n_rows, &kp->n_cols);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (kp->n_rows > TWL4030_MAX_ROWS || kp->n_cols > TWL4030_MAX_COLS) {
|
||||
dev_err(&pdev->dev,
|
||||
@@ -379,7 +358,7 @@ static int twl4030_kp_probe(struct platform_device *pdev)
|
||||
if (kp->irq < 0)
|
||||
return kp->irq;
|
||||
|
||||
error = matrix_keypad_build_keymap(keymap_data, NULL,
|
||||
error = matrix_keypad_build_keymap(NULL, NULL,
|
||||
TWL4030_MAX_ROWS,
|
||||
1 << TWL4030_ROW_SHIFT,
|
||||
kp->keymap, input);
|
||||
@@ -389,9 +368,7 @@ static int twl4030_kp_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
input_set_capability(input, EV_MSC, MSC_SCAN);
|
||||
/* Enable auto repeat feature of Linux input subsystem */
|
||||
if (kp->autorepeat)
|
||||
__set_bit(EV_REP, input->evbit);
|
||||
__set_bit(EV_REP, input->evbit);
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
|
||||
@@ -126,6 +126,17 @@ config INPUT_ATMEL_CAPTOUCH
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called atmel_captouch.
|
||||
|
||||
config INPUT_AW86927
|
||||
tristate "Awinic AW86927 Haptic Driver Support"
|
||||
depends on I2C && INPUT
|
||||
select INPUT_FF_MEMLESS
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here if you have an Awinic AW86927 haptic chip.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called aw86927.
|
||||
|
||||
config INPUT_BBNSM_PWRKEY
|
||||
tristate "NXP BBNSM Power Key Driver"
|
||||
depends on ARCH_MXC || COMPILE_TEST
|
||||
|
||||
@@ -22,6 +22,7 @@ obj-$(CONFIG_INPUT_ATC260X_ONKEY) += atc260x-onkey.o
|
||||
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
|
||||
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
|
||||
obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH) += atmel_captouch.o
|
||||
obj-$(CONFIG_INPUT_AW86927) += aw86927.o
|
||||
obj-$(CONFIG_INPUT_BBNSM_PWRKEY) += nxp-bbnsm-pwrkey.o
|
||||
obj-$(CONFIG_INPUT_BMA150) += bma150.o
|
||||
obj-$(CONFIG_INPUT_CM109) += cm109.o
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
@@ -0,0 +1,846 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2025 Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
|
||||
*
|
||||
* Partially based on vendor driver:
|
||||
* Copyright (c) 2021 AWINIC Technology CO., LTD
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define AW86927_RSTCFG_REG 0x00
|
||||
#define AW86927_RSTCFG_SOFTRST 0xaa
|
||||
|
||||
#define AW86927_SYSINT_REG 0x02
|
||||
#define AW86927_SYSINT_BST_SCPI BIT(7)
|
||||
#define AW86927_SYSINT_BST_OVPI BIT(6)
|
||||
#define AW86927_SYSINT_UVLI BIT(5)
|
||||
#define AW86927_SYSINT_FF_AEI BIT(4)
|
||||
#define AW86927_SYSINT_FF_AFI BIT(3)
|
||||
#define AW86927_SYSINT_OCDI BIT(2)
|
||||
#define AW86927_SYSINT_OTI BIT(1)
|
||||
#define AW86927_SYSINT_DONEI BIT(0)
|
||||
|
||||
#define AW86927_SYSINTM_REG 0x03
|
||||
#define AW86927_SYSINTM_BST_OVPM BIT(6)
|
||||
#define AW86927_SYSINTM_FF_AEM BIT(4)
|
||||
#define AW86927_SYSINTM_FF_AFM BIT(3)
|
||||
#define AW86927_SYSINTM_DONEM BIT(0)
|
||||
|
||||
#define AW86927_PLAYCFG1_REG 0x06
|
||||
#define AW86927_PLAYCFG1_BST_MODE_MASK GENMASK(7, 7)
|
||||
#define AW86927_PLAYCFG1_BST_MODE_BYPASS 0
|
||||
#define AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK GENMASK(6, 0)
|
||||
#define AW86927_PLAYCFG1_BST_8500MV 0x50
|
||||
|
||||
#define AW86927_PLAYCFG2_REG 0x07
|
||||
|
||||
#define AW86927_PLAYCFG3_REG 0x08
|
||||
#define AW86927_PLAYCFG3_AUTO_BST_MASK GENMASK(4, 4)
|
||||
#define AW86927_PLAYCFG3_AUTO_BST_ENABLE 1
|
||||
#define AW86927_PLAYCFG3_AUTO_BST_DISABLE 0
|
||||
#define AW86927_PLAYCFG3_PLAY_MODE_MASK GENMASK(1, 0)
|
||||
#define AW86927_PLAYCFG3_PLAY_MODE_RAM 0
|
||||
|
||||
#define AW86927_PLAYCFG4_REG 0x09
|
||||
#define AW86927_PLAYCFG4_STOP BIT(1)
|
||||
#define AW86927_PLAYCFG4_GO BIT(0)
|
||||
|
||||
#define AW86927_WAVCFG1_REG 0x0a
|
||||
#define AW86927_WAVCFG1_WAVSEQ1_MASK GENMASK(6, 0)
|
||||
|
||||
#define AW86927_WAVCFG2_REG 0x0b
|
||||
#define AW86927_WAVCFG2_WAVSEQ2_MASK GENMASK(6, 0)
|
||||
|
||||
#define AW86927_WAVCFG9_REG 0x12
|
||||
#define AW86927_WAVCFG9_SEQ1LOOP_MASK GENMASK(7, 4)
|
||||
#define AW86927_WAVCFG9_SEQ1LOOP_INFINITELY 0x0f
|
||||
|
||||
#define AW86927_CONTCFG1_REG 0x18
|
||||
#define AW86927_CONTCFG1_BRK_BST_MD_MASK GENMASK(6, 6)
|
||||
|
||||
#define AW86927_CONTCFG5_REG 0x1c
|
||||
#define AW86927_CONTCFG5_BST_BRK_GAIN_MASK GENMASK(7, 4)
|
||||
#define AW86927_CONTCFG5_BRK_GAIN_MASK GENMASK(3, 0)
|
||||
|
||||
#define AW86927_CONTCFG10_REG 0x21
|
||||
#define AW86927_CONTCFG10_BRK_TIME_MASK GENMASK(7, 0)
|
||||
#define AW86927_CONTCFG10_BRK_TIME_DEFAULT 8
|
||||
|
||||
#define AW86927_CONTCFG13_REG 0x24
|
||||
#define AW86927_CONTCFG13_TSET_MASK GENMASK(7, 4)
|
||||
#define AW86927_CONTCFG13_BEME_SET_MASK GENMASK(3, 0)
|
||||
|
||||
#define AW86927_BASEADDRH_REG 0x2d
|
||||
#define AW86927_BASEADDRL_REG 0x2e
|
||||
|
||||
#define AW86927_GLBRD5_REG 0x3f
|
||||
#define AW86927_GLBRD5_STATE_MASK GENMASK(3, 0)
|
||||
#define AW86927_GLBRD5_STATE_STANDBY 0
|
||||
|
||||
#define AW86927_RAMADDRH_REG 0x40
|
||||
|
||||
#define AW86927_RAMADDRL_REG 0x41
|
||||
|
||||
#define AW86927_RAMDATA_REG 0x42
|
||||
|
||||
#define AW86927_SYSCTRL3_REG 0x45
|
||||
#define AW86927_SYSCTRL3_STANDBY_MASK GENMASK(5, 5)
|
||||
#define AW86927_SYSCTRL3_STANDBY_ON 1
|
||||
#define AW86927_SYSCTRL3_STANDBY_OFF 0
|
||||
#define AW86927_SYSCTRL3_EN_RAMINIT_MASK GENMASK(2, 2)
|
||||
#define AW86927_SYSCTRL3_EN_RAMINIT_ON 1
|
||||
#define AW86927_SYSCTRL3_EN_RAMINIT_OFF 0
|
||||
|
||||
#define AW86927_SYSCTRL4_REG 0x46
|
||||
#define AW86927_SYSCTRL4_WAVDAT_MODE_MASK GENMASK(6, 5)
|
||||
#define AW86927_SYSCTRL4_WAVDAT_24K 0
|
||||
#define AW86927_SYSCTRL4_INT_EDGE_MODE_MASK GENMASK(4, 4)
|
||||
#define AW86927_SYSCTRL4_INT_EDGE_MODE_POS 0
|
||||
#define AW86927_SYSCTRL4_INT_MODE_MASK GENMASK(3, 3)
|
||||
#define AW86927_SYSCTRL4_INT_MODE_EDGE 1
|
||||
#define AW86927_SYSCTRL4_GAIN_BYPASS_MASK GENMASK(0, 0)
|
||||
|
||||
#define AW86927_PWMCFG1_REG 0x48
|
||||
#define AW86927_PWMCFG1_PRC_EN_MASK GENMASK(7, 7)
|
||||
#define AW86927_PWMCFG1_PRC_DISABLE 0
|
||||
|
||||
#define AW86927_PWMCFG3_REG 0x4a
|
||||
#define AW86927_PWMCFG3_PR_EN_MASK GENMASK(7, 7)
|
||||
#define AW86927_PWMCFG3_PRCTIME_MASK GENMASK(6, 0)
|
||||
|
||||
#define AW86927_PWMCFG4_REG 0x4b
|
||||
#define AW86927_PWMCFG4_PRTIME_MASK GENMASK(7, 0)
|
||||
|
||||
#define AW86927_VBATCTRL_REG 0x4c
|
||||
#define AW86927_VBATCTRL_VBAT_MODE_MASK GENMASK(6, 6)
|
||||
#define AW86927_VBATCTRL_VBAT_MODE_SW 0
|
||||
|
||||
#define AW86927_DETCFG1_REG 0x4d
|
||||
#define AW86927_DETCFG1_DET_GO_MASK GENMASK(1, 0)
|
||||
#define AW86927_DETCFG1_DET_GO_DET_SEQ0 1
|
||||
#define AW86927_DETCFG1_DET_GO_NA 0
|
||||
|
||||
#define AW86927_DETCFG2_REG 0x4e
|
||||
#define AW86927_DETCFG2_DET_SEQ0_MASK GENMASK(6, 3)
|
||||
#define AW86927_DETCFG2_DET_SEQ0_VBAT 0
|
||||
#define AW86927_DETCFG2_D2S_GAIN_MASK GENMASK(2, 0)
|
||||
#define AW86927_DETCFG2_D2S_GAIN_10 4
|
||||
|
||||
#define AW86927_CHIPIDH_REG 0x57
|
||||
#define AW86927_CHIPIDL_REG 0x58
|
||||
#define AW86927_CHIPID 0x9270
|
||||
|
||||
#define AW86927_TMCFG_REG 0x5b
|
||||
#define AW86927_TMCFG_UNLOCK 0x7d
|
||||
#define AW86927_TMCFG_LOCK 0x00
|
||||
|
||||
#define AW86927_ANACFG11_REG 0x70
|
||||
|
||||
#define AW86927_ANACFG12_REG 0x71
|
||||
#define AW86927_ANACFG12_BST_SKIP_MASK GENMASK(7, 7)
|
||||
#define AW86927_ANACFG12_BST_SKIP_SHUTDOWN 1
|
||||
|
||||
#define AW86927_ANACFG13_REG 0x72
|
||||
#define AW86927_ANACFG13_BST_PC_MASK GENMASK(7, 4)
|
||||
#define AW86927_ANACFG13_BST_PEAKCUR_3P45A 6
|
||||
|
||||
#define AW86927_ANACFG15_REG 0x74
|
||||
#define AW86927_ANACFG15_BST_PEAK_MODE_MASK GENMASK(7, 7)
|
||||
#define AW86927_ANACFG15_BST_PEAK_BACK 1
|
||||
|
||||
#define AW86927_ANACFG16_REG 0x75
|
||||
#define AW86927_ANACFG16_BST_SRC_MASK GENMASK(4, 4)
|
||||
#define AW86927_ANACFG16_BST_SRC_3NS 0
|
||||
|
||||
/* default value of base addr */
|
||||
#define AW86927_RAM_BASE_ADDR 0x800
|
||||
#define AW86927_BASEADDRH_VAL 0x08
|
||||
#define AW86927_BASEADDRL_VAL 0x00
|
||||
|
||||
enum aw86927_work_mode {
|
||||
AW86927_STANDBY_MODE,
|
||||
AW86927_RAM_MODE,
|
||||
};
|
||||
|
||||
struct aw86927_data {
|
||||
struct work_struct play_work;
|
||||
struct device *dev;
|
||||
struct input_dev *input_dev;
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct gpio_desc *reset_gpio;
|
||||
bool running;
|
||||
};
|
||||
|
||||
static const struct regmap_config aw86927_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
.max_register = 0x80,
|
||||
};
|
||||
|
||||
/*
|
||||
* Sine wave representing the magnitude of the drive to be used.
|
||||
* Data is encoded in two's complement.
|
||||
* round(84 * sin(x / 16.25))
|
||||
*/
|
||||
static const u8 aw86927_waveform[] = {
|
||||
0x00, 0x05, 0x0a, 0x0f, 0x14, 0x1a, 0x1f, 0x23, 0x28, 0x2d, 0x31, 0x35,
|
||||
0x39, 0x3d, 0x41, 0x44, 0x47, 0x4a, 0x4c, 0x4f, 0x51, 0x52, 0x53, 0x54,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x52, 0x51, 0x4f, 0x4d, 0x4a, 0x47,
|
||||
0x44, 0x41, 0x3d, 0x3a, 0x36, 0x31, 0x2d, 0x28, 0x24, 0x1f, 0x1a, 0x15,
|
||||
0x10, 0x0a, 0x05, 0x00, 0xfc, 0xf6, 0xf1, 0xec, 0xe7, 0xe2, 0xdd, 0xd8,
|
||||
0xd4, 0xcf, 0xcb, 0xc7, 0xc3, 0xbf, 0xbc, 0xb9, 0xb6, 0xb4, 0xb1, 0xb0,
|
||||
0xae, 0xad, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, 0xac, 0xae, 0xaf, 0xb1,
|
||||
0xb3, 0xb6, 0xb8, 0xbc, 0xbf, 0xc2, 0xc6, 0xca, 0xce, 0xd3, 0xd7, 0xdc,
|
||||
0xe1, 0xe6, 0xeb, 0xf0, 0xf5, 0xfb
|
||||
};
|
||||
|
||||
struct aw86927_sram_waveform_header {
|
||||
u8 version;
|
||||
__be16 start_address;
|
||||
__be16 end_address;
|
||||
} __packed;
|
||||
|
||||
static const struct aw86927_sram_waveform_header sram_waveform_header = {
|
||||
.version = 0x01,
|
||||
.start_address = cpu_to_be16(AW86927_RAM_BASE_ADDR +
|
||||
sizeof(struct aw86927_sram_waveform_header)),
|
||||
.end_address = cpu_to_be16(AW86927_RAM_BASE_ADDR +
|
||||
sizeof(struct aw86927_sram_waveform_header) +
|
||||
ARRAY_SIZE(aw86927_waveform) - 1),
|
||||
};
|
||||
|
||||
static int aw86927_wait_enter_standby(struct aw86927_data *haptics)
|
||||
{
|
||||
unsigned int reg_val;
|
||||
int err;
|
||||
|
||||
err = regmap_read_poll_timeout(haptics->regmap, AW86927_GLBRD5_REG, reg_val,
|
||||
(FIELD_GET(AW86927_GLBRD5_STATE_MASK, reg_val) ==
|
||||
AW86927_GLBRD5_STATE_STANDBY),
|
||||
2500, 2500 * 100);
|
||||
|
||||
if (err) {
|
||||
dev_err(haptics->dev, "did not enter standby: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw86927_play_mode(struct aw86927_data *haptics, u8 play_mode)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (play_mode) {
|
||||
case AW86927_STANDBY_MODE:
|
||||
/* Briefly toggle standby, then toggle back to standby off */
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_SYSCTRL3_REG,
|
||||
AW86927_SYSCTRL3_STANDBY_MASK,
|
||||
FIELD_PREP(AW86927_SYSCTRL3_STANDBY_MASK,
|
||||
AW86927_SYSCTRL3_STANDBY_ON));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_SYSCTRL3_REG,
|
||||
AW86927_SYSCTRL3_STANDBY_MASK,
|
||||
FIELD_PREP(AW86927_SYSCTRL3_STANDBY_MASK,
|
||||
AW86927_SYSCTRL3_STANDBY_OFF));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
break;
|
||||
|
||||
case AW86927_RAM_MODE:
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_PLAYCFG3_REG,
|
||||
AW86927_PLAYCFG3_PLAY_MODE_MASK,
|
||||
FIELD_PREP(AW86927_PLAYCFG3_PLAY_MODE_MASK,
|
||||
AW86927_PLAYCFG3_PLAY_MODE_RAM));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_PLAYCFG1_REG,
|
||||
AW86927_PLAYCFG1_BST_MODE_MASK,
|
||||
FIELD_PREP(AW86927_PLAYCFG1_BST_MODE_MASK,
|
||||
AW86927_PLAYCFG1_BST_MODE_BYPASS));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_VBATCTRL_REG,
|
||||
AW86927_VBATCTRL_VBAT_MODE_MASK,
|
||||
FIELD_PREP(AW86927_VBATCTRL_VBAT_MODE_MASK,
|
||||
AW86927_VBATCTRL_VBAT_MODE_SW));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw86927_stop(struct aw86927_data *haptics)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = regmap_write(haptics->regmap, AW86927_PLAYCFG4_REG, AW86927_PLAYCFG4_STOP);
|
||||
if (err) {
|
||||
dev_err(haptics->dev, "Failed to stop playback: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = aw86927_wait_enter_standby(haptics);
|
||||
if (err) {
|
||||
dev_err(haptics->dev, "Failed to enter standby, trying to force it\n");
|
||||
err = aw86927_play_mode(haptics, AW86927_STANDBY_MODE);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw86927_haptics_play(struct input_dev *dev, void *data, struct ff_effect *effect)
|
||||
{
|
||||
struct aw86927_data *haptics = input_get_drvdata(dev);
|
||||
int level;
|
||||
|
||||
level = effect->u.rumble.strong_magnitude;
|
||||
if (!level)
|
||||
level = effect->u.rumble.weak_magnitude;
|
||||
|
||||
/* If already running, don't restart playback */
|
||||
if (haptics->running && level)
|
||||
return 0;
|
||||
|
||||
haptics->running = level;
|
||||
schedule_work(&haptics->play_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw86927_play_sine(struct aw86927_data *haptics)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = aw86927_stop(haptics);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = aw86927_play_mode(haptics, AW86927_RAM_MODE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap, AW86927_PLAYCFG3_REG,
|
||||
AW86927_PLAYCFG3_AUTO_BST_MASK,
|
||||
FIELD_PREP(AW86927_PLAYCFG3_AUTO_BST_MASK,
|
||||
AW86927_PLAYCFG3_AUTO_BST_ENABLE));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Set waveseq 1 to the first wave */
|
||||
err = regmap_update_bits(haptics->regmap, AW86927_WAVCFG1_REG,
|
||||
AW86927_WAVCFG1_WAVSEQ1_MASK,
|
||||
FIELD_PREP(AW86927_WAVCFG1_WAVSEQ1_MASK, 1));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* set wavseq 2 to zero */
|
||||
err = regmap_update_bits(haptics->regmap, AW86927_WAVCFG2_REG,
|
||||
AW86927_WAVCFG2_WAVSEQ2_MASK,
|
||||
FIELD_PREP(AW86927_WAVCFG2_WAVSEQ2_MASK, 0));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_WAVCFG9_REG,
|
||||
AW86927_WAVCFG9_SEQ1LOOP_MASK,
|
||||
FIELD_PREP(AW86927_WAVCFG9_SEQ1LOOP_MASK,
|
||||
AW86927_WAVCFG9_SEQ1LOOP_INFINITELY));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* set gain to value lower than 0x80 to avoid distorted playback */
|
||||
err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, 0x7c);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Start playback */
|
||||
err = regmap_write(haptics->regmap, AW86927_PLAYCFG4_REG, AW86927_PLAYCFG4_GO);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aw86927_close(struct input_dev *input)
|
||||
{
|
||||
struct aw86927_data *haptics = input_get_drvdata(input);
|
||||
struct device *dev = &haptics->client->dev;
|
||||
int err;
|
||||
|
||||
cancel_work_sync(&haptics->play_work);
|
||||
|
||||
err = aw86927_stop(haptics);
|
||||
if (err)
|
||||
dev_err(dev, "Failed to close the Driver: %d\n", err);
|
||||
}
|
||||
|
||||
static void aw86927_haptics_play_work(struct work_struct *work)
|
||||
{
|
||||
struct aw86927_data *haptics =
|
||||
container_of(work, struct aw86927_data, play_work);
|
||||
struct device *dev = &haptics->client->dev;
|
||||
int err;
|
||||
|
||||
if (haptics->running)
|
||||
err = aw86927_play_sine(haptics);
|
||||
else
|
||||
err = aw86927_stop(haptics);
|
||||
|
||||
if (err)
|
||||
dev_err(dev, "Failed to execute work command: %d\n", err);
|
||||
}
|
||||
|
||||
static void aw86927_hw_reset(struct aw86927_data *haptics)
|
||||
{
|
||||
/* Assert reset */
|
||||
gpiod_set_value_cansleep(haptics->reset_gpio, 1);
|
||||
/* Wait ~1ms */
|
||||
usleep_range(1000, 2000);
|
||||
/* Deassert reset */
|
||||
gpiod_set_value_cansleep(haptics->reset_gpio, 0);
|
||||
/* Wait ~8ms until I2C is accessible */
|
||||
usleep_range(8000, 8500);
|
||||
}
|
||||
|
||||
static int aw86927_haptic_init(struct aw86927_data *haptics)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_SYSCTRL4_REG,
|
||||
AW86927_SYSCTRL4_WAVDAT_MODE_MASK,
|
||||
FIELD_PREP(AW86927_SYSCTRL4_WAVDAT_MODE_MASK,
|
||||
AW86927_SYSCTRL4_WAVDAT_24K));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* enable gain bypass */
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_SYSCTRL4_REG,
|
||||
AW86927_SYSCTRL4_GAIN_BYPASS_MASK,
|
||||
FIELD_PREP(AW86927_SYSCTRL4_GAIN_BYPASS_MASK,
|
||||
0x01));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_TMCFG_REG, AW86927_TMCFG_UNLOCK);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_write(haptics->regmap, AW86927_ANACFG11_REG, 0x0f);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_ANACFG12_REG,
|
||||
AW86927_ANACFG12_BST_SKIP_MASK,
|
||||
FIELD_PREP(AW86927_ANACFG12_BST_SKIP_MASK,
|
||||
AW86927_ANACFG12_BST_SKIP_SHUTDOWN));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_ANACFG15_REG,
|
||||
AW86927_ANACFG15_BST_PEAK_MODE_MASK,
|
||||
FIELD_PREP(AW86927_ANACFG15_BST_PEAK_MODE_MASK,
|
||||
AW86927_ANACFG15_BST_PEAK_BACK));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_ANACFG16_REG,
|
||||
AW86927_ANACFG16_BST_SRC_MASK,
|
||||
FIELD_PREP(AW86927_ANACFG16_BST_SRC_MASK,
|
||||
AW86927_ANACFG16_BST_SRC_3NS));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_TMCFG_REG, AW86927_TMCFG_LOCK);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_CONTCFG1_REG,
|
||||
AW86927_CONTCFG1_BRK_BST_MD_MASK,
|
||||
FIELD_PREP(AW86927_CONTCFG1_BRK_BST_MD_MASK, 0x00));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_CONTCFG5_REG,
|
||||
FIELD_PREP(AW86927_CONTCFG5_BST_BRK_GAIN_MASK, 0x05) |
|
||||
FIELD_PREP(AW86927_CONTCFG5_BRK_GAIN_MASK, 0x08));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap, AW86927_CONTCFG10_REG,
|
||||
AW86927_CONTCFG10_BRK_TIME_MASK,
|
||||
FIELD_PREP(AW86927_CONTCFG10_BRK_TIME_MASK,
|
||||
AW86927_CONTCFG10_BRK_TIME_DEFAULT));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_CONTCFG13_REG,
|
||||
FIELD_PREP(AW86927_CONTCFG13_TSET_MASK, 0x06) |
|
||||
FIELD_PREP(AW86927_CONTCFG13_BEME_SET_MASK, 0x02));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_DETCFG2_REG,
|
||||
AW86927_DETCFG2_D2S_GAIN_MASK,
|
||||
FIELD_PREP(AW86927_DETCFG2_D2S_GAIN_MASK,
|
||||
AW86927_DETCFG2_D2S_GAIN_10));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_PWMCFG1_REG,
|
||||
AW86927_PWMCFG1_PRC_EN_MASK,
|
||||
FIELD_PREP(AW86927_PWMCFG1_PRC_EN_MASK,
|
||||
AW86927_PWMCFG1_PRC_DISABLE));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_PWMCFG3_REG,
|
||||
FIELD_PREP(AW86927_PWMCFG3_PR_EN_MASK, 0x01) |
|
||||
FIELD_PREP(AW86927_PWMCFG3_PRCTIME_MASK, 0x3f));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_PWMCFG4_REG,
|
||||
AW86927_PWMCFG4_PRTIME_MASK,
|
||||
FIELD_PREP(AW86927_PWMCFG4_PRTIME_MASK, 0x32));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_TMCFG_REG, AW86927_TMCFG_UNLOCK);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_ANACFG13_REG,
|
||||
AW86927_ANACFG13_BST_PC_MASK,
|
||||
FIELD_PREP(AW86927_ANACFG13_BST_PC_MASK,
|
||||
AW86927_ANACFG13_BST_PEAKCUR_3P45A));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_TMCFG_REG, AW86927_TMCFG_LOCK);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_PLAYCFG1_REG,
|
||||
AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
|
||||
FIELD_PREP(AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
|
||||
AW86927_PLAYCFG1_BST_8500MV));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_PLAYCFG3_REG,
|
||||
AW86927_PLAYCFG3_AUTO_BST_MASK,
|
||||
FIELD_PREP(AW86927_PLAYCFG3_AUTO_BST_MASK,
|
||||
AW86927_PLAYCFG3_AUTO_BST_DISABLE));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw86927_ram_init(struct aw86927_data *haptics)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = aw86927_wait_enter_standby(haptics);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Enable SRAM init */
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_SYSCTRL3_REG,
|
||||
AW86927_SYSCTRL3_EN_RAMINIT_MASK,
|
||||
FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK,
|
||||
AW86927_SYSCTRL3_EN_RAMINIT_ON));
|
||||
|
||||
/* Set base address for the start of the SRAM waveforms */
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_BASEADDRH_REG, AW86927_BASEADDRH_VAL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_BASEADDRL_REG, AW86927_BASEADDRL_VAL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Set start of SRAM, before the data is written it will be the same as the base */
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_RAMADDRH_REG, AW86927_BASEADDRH_VAL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_write(haptics->regmap,
|
||||
AW86927_RAMADDRL_REG, AW86927_BASEADDRL_VAL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Write waveform header to SRAM */
|
||||
err = regmap_noinc_write(haptics->regmap, AW86927_RAMDATA_REG,
|
||||
&sram_waveform_header, sizeof(sram_waveform_header));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Write waveform to SRAM */
|
||||
err = regmap_noinc_write(haptics->regmap, AW86927_RAMDATA_REG,
|
||||
aw86927_waveform, ARRAY_SIZE(aw86927_waveform));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_DETCFG2_REG,
|
||||
AW86927_DETCFG2_DET_SEQ0_MASK,
|
||||
FIELD_PREP(AW86927_DETCFG2_DET_SEQ0_MASK,
|
||||
AW86927_DETCFG2_DET_SEQ0_VBAT));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_DETCFG1_REG,
|
||||
AW86927_DETCFG1_DET_GO_MASK,
|
||||
FIELD_PREP(AW86927_DETCFG1_DET_GO_MASK,
|
||||
AW86927_DETCFG1_DET_GO_DET_SEQ0));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
usleep_range(3000, 3500);
|
||||
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_DETCFG1_REG,
|
||||
AW86927_DETCFG1_DET_GO_MASK,
|
||||
FIELD_PREP(AW86927_DETCFG1_DET_GO_MASK,
|
||||
AW86927_DETCFG1_DET_GO_NA));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Disable SRAM init */
|
||||
err = regmap_update_bits(haptics->regmap,
|
||||
AW86927_SYSCTRL3_REG,
|
||||
AW86927_SYSCTRL3_EN_RAMINIT_MASK,
|
||||
FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK,
|
||||
AW86927_SYSCTRL3_EN_RAMINIT_OFF));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t aw86927_irq(int irq, void *data)
|
||||
{
|
||||
struct aw86927_data *haptics = data;
|
||||
struct device *dev = &haptics->client->dev;
|
||||
unsigned int reg_val;
|
||||
int err;
|
||||
|
||||
err = regmap_read(haptics->regmap, AW86927_SYSINT_REG, ®_val);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to read SYSINT register: %d\n", err);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (reg_val & AW86927_SYSINT_BST_SCPI)
|
||||
dev_err(dev, "Received a Short Circuit Protection interrupt\n");
|
||||
if (reg_val & AW86927_SYSINT_BST_OVPI)
|
||||
dev_err(dev, "Received an Over Voltage Protection interrupt\n");
|
||||
if (reg_val & AW86927_SYSINT_UVLI)
|
||||
dev_err(dev, "Received an Under Voltage Lock Out interrupt\n");
|
||||
if (reg_val & AW86927_SYSINT_OCDI)
|
||||
dev_err(dev, "Received an Over Current interrupt\n");
|
||||
if (reg_val & AW86927_SYSINT_OTI)
|
||||
dev_err(dev, "Received an Over Temperature interrupt\n");
|
||||
|
||||
if (reg_val & AW86927_SYSINT_DONEI)
|
||||
dev_dbg(dev, "Chip playback done!\n");
|
||||
if (reg_val & AW86927_SYSINT_FF_AFI)
|
||||
dev_dbg(dev, "The RTP mode FIFO is almost full!\n");
|
||||
if (reg_val & AW86927_SYSINT_FF_AEI)
|
||||
dev_dbg(dev, "The RTP mode FIFO is almost empty!\n");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int aw86927_detect(struct aw86927_data *haptics)
|
||||
{
|
||||
__be16 read_buf;
|
||||
u16 chip_id;
|
||||
int err;
|
||||
|
||||
err = regmap_bulk_read(haptics->regmap, AW86927_CHIPIDH_REG, &read_buf, 2);
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err, "Failed to read CHIPID registers\n");
|
||||
|
||||
chip_id = be16_to_cpu(read_buf);
|
||||
|
||||
if (chip_id != AW86927_CHIPID) {
|
||||
dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aw86927_probe(struct i2c_client *client)
|
||||
{
|
||||
struct aw86927_data *haptics;
|
||||
int err;
|
||||
|
||||
haptics = devm_kzalloc(&client->dev, sizeof(struct aw86927_data), GFP_KERNEL);
|
||||
if (!haptics)
|
||||
return -ENOMEM;
|
||||
|
||||
haptics->dev = &client->dev;
|
||||
haptics->client = client;
|
||||
|
||||
i2c_set_clientdata(client, haptics);
|
||||
|
||||
haptics->regmap = devm_regmap_init_i2c(client, &aw86927_regmap_config);
|
||||
if (IS_ERR(haptics->regmap))
|
||||
return dev_err_probe(haptics->dev, PTR_ERR(haptics->regmap),
|
||||
"Failed to allocate register map\n");
|
||||
|
||||
haptics->input_dev = devm_input_allocate_device(haptics->dev);
|
||||
if (!haptics->input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
haptics->reset_gpio = devm_gpiod_get(haptics->dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(haptics->reset_gpio))
|
||||
return dev_err_probe(haptics->dev, PTR_ERR(haptics->reset_gpio),
|
||||
"Failed to get reset gpio\n");
|
||||
|
||||
/* Hardware reset */
|
||||
aw86927_hw_reset(haptics);
|
||||
|
||||
/* Software reset */
|
||||
err = regmap_write(haptics->regmap, AW86927_RSTCFG_REG, AW86927_RSTCFG_SOFTRST);
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err, "Failed Software reset\n");
|
||||
|
||||
/* Wait ~3ms until I2C is accessible */
|
||||
usleep_range(3000, 3500);
|
||||
|
||||
err = aw86927_detect(haptics);
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err, "Failed to find chip\n");
|
||||
|
||||
/* IRQ config */
|
||||
err = regmap_write(haptics->regmap, AW86927_SYSCTRL4_REG,
|
||||
FIELD_PREP(AW86927_SYSCTRL4_INT_MODE_MASK,
|
||||
AW86927_SYSCTRL4_INT_MODE_EDGE) |
|
||||
FIELD_PREP(AW86927_SYSCTRL4_INT_EDGE_MODE_MASK,
|
||||
AW86927_SYSCTRL4_INT_EDGE_MODE_POS));
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err, "Failed to configure interrupt modes\n");
|
||||
|
||||
err = regmap_write(haptics->regmap, AW86927_SYSINTM_REG,
|
||||
AW86927_SYSINTM_BST_OVPM |
|
||||
AW86927_SYSINTM_FF_AEM |
|
||||
AW86927_SYSINTM_FF_AFM |
|
||||
AW86927_SYSINTM_DONEM);
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err, "Failed to configure interrupt masks\n");
|
||||
|
||||
err = devm_request_threaded_irq(haptics->dev, client->irq, NULL,
|
||||
aw86927_irq, IRQF_ONESHOT, NULL, haptics);
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err, "Failed to request threaded irq\n");
|
||||
|
||||
INIT_WORK(&haptics->play_work, aw86927_haptics_play_work);
|
||||
|
||||
haptics->input_dev->name = "aw86927-haptics";
|
||||
haptics->input_dev->close = aw86927_close;
|
||||
|
||||
input_set_drvdata(haptics->input_dev, haptics);
|
||||
input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
|
||||
|
||||
err = input_ff_create_memless(haptics->input_dev, NULL, aw86927_haptics_play);
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err, "Failed to create FF dev\n");
|
||||
|
||||
/* Set up registers */
|
||||
err = aw86927_play_mode(haptics, AW86927_STANDBY_MODE);
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err,
|
||||
"Failed to enter standby for Haptic init\n");
|
||||
|
||||
err = aw86927_haptic_init(haptics);
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err, "Haptic init failed\n");
|
||||
|
||||
/* RAM init, upload the waveform for playback */
|
||||
err = aw86927_ram_init(haptics);
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err, "Failed to init aw86927 sram\n");
|
||||
|
||||
err = input_register_device(haptics->input_dev);
|
||||
if (err)
|
||||
return dev_err_probe(haptics->dev, err, "Failed to register input device\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id aw86927_of_id[] = {
|
||||
{ .compatible = "awinic,aw86927" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, aw86927_of_id);
|
||||
|
||||
static struct i2c_driver aw86927_driver = {
|
||||
.driver = {
|
||||
.name = "aw86927-haptics",
|
||||
.of_match_table = aw86927_of_id,
|
||||
},
|
||||
.probe = aw86927_probe,
|
||||
};
|
||||
|
||||
module_i2c_driver(aw86927_driver);
|
||||
|
||||
MODULE_AUTHOR("Griffin Kroah-Hartman <griffin.kroah@fairphone.com>");
|
||||
MODULE_DESCRIPTION("AWINIC AW86927 LRA Haptic Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -6,6 +6,7 @@
|
||||
* Author: Hemanth V <hemanthv@ti.com>
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
@@ -60,6 +60,7 @@ struct pm8941_data {
|
||||
bool supports_ps_hold_poff_config;
|
||||
bool supports_debounce_config;
|
||||
bool has_pon_pbs;
|
||||
bool wakeup_source_default;
|
||||
const char *name;
|
||||
const char *phys;
|
||||
};
|
||||
@@ -245,7 +246,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops,
|
||||
static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm8941_pwrkey *pwrkey;
|
||||
bool pull_up;
|
||||
bool pull_up, wakeup;
|
||||
struct device *parent;
|
||||
struct device_node *regmap_node;
|
||||
const __be32 *addr;
|
||||
@@ -402,8 +403,11 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
wakeup = pwrkey->data->wakeup_source_default ||
|
||||
of_property_read_bool(pdev->dev.of_node, "wakeup-source");
|
||||
|
||||
platform_set_drvdata(pdev, pwrkey);
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
device_init_wakeup(&pdev->dev, wakeup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -424,6 +428,7 @@ static const struct pm8941_data pwrkey_data = {
|
||||
.supports_ps_hold_poff_config = true,
|
||||
.supports_debounce_config = true,
|
||||
.has_pon_pbs = false,
|
||||
.wakeup_source_default = true,
|
||||
};
|
||||
|
||||
static const struct pm8941_data resin_data = {
|
||||
@@ -434,6 +439,7 @@ static const struct pm8941_data resin_data = {
|
||||
.supports_ps_hold_poff_config = true,
|
||||
.supports_debounce_config = true,
|
||||
.has_pon_pbs = false,
|
||||
.wakeup_source_default = false,
|
||||
};
|
||||
|
||||
static const struct pm8941_data pon_gen3_pwrkey_data = {
|
||||
@@ -443,6 +449,7 @@ static const struct pm8941_data pon_gen3_pwrkey_data = {
|
||||
.supports_ps_hold_poff_config = false,
|
||||
.supports_debounce_config = false,
|
||||
.has_pon_pbs = true,
|
||||
.wakeup_source_default = true,
|
||||
};
|
||||
|
||||
static const struct pm8941_data pon_gen3_resin_data = {
|
||||
@@ -452,6 +459,7 @@ static const struct pm8941_data pon_gen3_resin_data = {
|
||||
.supports_ps_hold_poff_config = false,
|
||||
.supports_debounce_config = false,
|
||||
.has_pon_pbs = true,
|
||||
.wakeup_source_default = false,
|
||||
};
|
||||
|
||||
static const struct of_device_id pm8941_pwr_key_id_table[] = {
|
||||
|
||||
@@ -775,6 +775,7 @@ static int uinput_ff_upload_to_user(char __user *buffer,
|
||||
if (in_compat_syscall()) {
|
||||
struct uinput_ff_upload_compat ff_up_compat;
|
||||
|
||||
memset(&ff_up_compat, 0, sizeof(ff_up_compat));
|
||||
ff_up_compat.request_id = ff_up->request_id;
|
||||
ff_up_compat.retval = ff_up->retval;
|
||||
/*
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Copyright (c) 2011 Unixphere
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#ifndef _RMI_2D_SENSOR_H
|
||||
#define _RMI_2D_SENSOR_H
|
||||
|
||||
#include <linux/rmi.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
enum rmi_2d_sensor_object_type {
|
||||
RMI_2D_OBJECT_NONE,
|
||||
RMI_2D_OBJECT_FINGER,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* Copyright (c) 2011 Unixphere
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <linux/irqdomain.h>
|
||||
#include <uapi/linux/input.h>
|
||||
#include <linux/rmi.h>
|
||||
#include <linux/export.h>
|
||||
#include "rmi_bus.h"
|
||||
#include "rmi_driver.h"
|
||||
|
||||
|
||||
Loaded 100 of 509 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user