Commit 6885d726 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull input updates from Dmitry Torokhov:

 - a new driver for Goodix Berlin I2C and SPI touch controllers

 - support for IQS7222D v1.1 and v1.2 in iqs7222 driver

 - support for IST3032C and IST3038B parts in Imagis touchscreen driver

 - support for touch keys for Imagis touchscreen controllers

 - support for Snakebyte GAMEPADs in xpad driver

 - various cleanups and conversions to yaml for device tree bindings

 - assorted fixes and cleanups

 - old Synaptics navpoint driver has been removed since the only board
   that used it (HP iPAQ hx4700) was removed a while ago.

* tag 'input-for-v6.9-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (37 commits)
  Input: xpad - add support for Snakebyte GAMEPADs
  dt-bindings: input: samsung,s3c6410-keypad: convert to DT Schema
  Input: imagis - add touch key support
  dt-bindings: input: imagis: Document touch keys
  Input: imagis - use FIELD_GET where applicable
  Input: make input_class constant
  dt-bindings: input: atmel,captouch: convert bindings to YAML
  Input: iqs7222 - add support for IQS7222D v1.1 and v1.2
  dt-bindings: input: allwinner,sun4i-a10-lrad: drop redundant type from label
  Input: serio - make serio_bus const
  Input: synaptics-rmi4 - make rmi_bus_type const
  Input: xilinx_ps2 - fix kernel-doc for xps2_of_probe function
  input/touchscreen: imagis: add support for IST3032C
  dt-bindings: input/touchscreen: imagis: add compatible for IST3032C
  input/touchscreen: imagis: Add support for Imagis IST3038B
  dt-bindings: input/touchscreen: Add compatible for IST3038B
  input/touchscreen: imagis: Correct the maximum touch area value
  Input: leds - change config symbol dependency for audio mute trigger
  Input: ti_am335x_tsc - remove redundant assignment to variable config
  Input: xpad - sort xpad_device by vendor and product ID
  ...
parents 741e9d66 57ed9567
...@@ -49,7 +49,6 @@ patternProperties: ...@@ -49,7 +49,6 @@ patternProperties:
$ref: input.yaml# $ref: input.yaml#
properties: properties:
label: label:
$ref: /schemas/types.yaml#/definitions/string
description: Descriptive name of the key description: Descriptive name of the key
linux,code: true linux,code: true
......
Device tree bindings for Atmel capacitive touch device, typically
an Atmel touch sensor connected to AtmegaXX MCU running firmware
based on Qtouch library.
The node for this device must be a child of a I2C controller node, as the
device communicates via I2C.
Required properties:
compatible: Must be "atmel,captouch".
reg: The I2C slave address of the device.
interrupts: Property describing the interrupt line the device
is connected to. The device only has one interrupt
source.
linux,keycodes: Specifies an array of numeric keycode values to
be used for reporting button presses. The array can
contain up to 8 entries.
Optional properties:
autorepeat: Enables the Linux input system's autorepeat
feature on the input device.
Example:
atmel-captouch@51 {
compatible = "atmel,captouch";
reg = <0x51>;
interrupt-parent = <&tlmm>;
interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
linux,keycodes = <BTN_0>, <BTN_1>,
<BTN_2>, <BTN_3>,
<BTN_4>, <BTN_5>,
<BTN_6>, <BTN_7>;
autorepeat;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/atmel,captouch.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Atmel capacitive touch device
maintainers:
- Dharma balasubiramani <dharma.b@microchip.com>
description:
Atmel capacitive touch device, typically an Atmel touch sensor connected to
AtmegaXX MCU running firmware based on Qtouch library.
allOf:
- $ref: input.yaml#
properties:
compatible:
const: atmel,captouch
reg:
maxItems: 1
interrupts:
maxItems: 1
linux,keycodes:
minItems: 1
maxItems: 8
required:
- compatible
- reg
- interrupts
- linux,keycodes
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/linux-event-codes.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
touch@51 {
compatible = "atmel,captouch";
reg = <0x51>;
interrupt-parent = <&tlmm>;
interrupts = <67 IRQ_TYPE_EDGE_FALLING>;
linux,keycodes = <BTN_0>, <BTN_1>,
<BTN_2>, <BTN_3>,
<BTN_4>, <BTN_5>,
<BTN_6>, <BTN_7>;
autorepeat;
};
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/samsung,s3c6410-keypad.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung SoC series Keypad Controller
description:
Samsung SoC Keypad controller is used to interface a SoC with a matrix-type
keypad device. The keypad controller supports multiple row and column lines.
A key can be placed at each intersection of a unique row and a unique column.
The keypad controller can sense a key-press and key-release and report the
event using a interrupt to the cpu.
maintainers:
- Krzysztof Kozlowski <krzk@kernel.org>
properties:
compatible:
enum:
- samsung,s3c6410-keypad
- samsung,s5pv210-keypad
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: keypad
interrupts:
maxItems: 1
wakeup-source: true
linux,input-no-autorepeat:
type: boolean
description:
Do no enable autorepeat feature.
linux,input-wakeup:
type: boolean
deprecated: true
samsung,keypad-num-columns:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Number of column lines connected to the keypad controller.
samsung,keypad-num-rows:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Number of row lines connected to the keypad controller.
patternProperties:
'^key-[0-9a-z]+$':
type: object
$ref: input.yaml#
additionalProperties: false
description:
Each key connected to the keypad controller is represented as a child
node to the keypad controller device node.
properties:
keypad,column:
$ref: /schemas/types.yaml#/definitions/uint32
description: The column number to which the key is connected.
keypad,row:
$ref: /schemas/types.yaml#/definitions/uint32
description: The row number to which the key is connected.
linux,code: true
required:
- keypad,column
- keypad,row
- linux,code
required:
- compatible
- reg
- interrupts
- samsung,keypad-num-columns
- samsung,keypad-num-rows
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/exynos4.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
keypad@100a0000 {
compatible = "samsung,s5pv210-keypad";
reg = <0x100a0000 0x100>;
interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clock CLK_KEYIF>;
clock-names = "keypad";
samsung,keypad-num-rows = <2>;
samsung,keypad-num-columns = <8>;
linux,input-no-autorepeat;
wakeup-source;
key-1 {
keypad,row = <0>;
keypad,column = <3>;
linux,code = <2>;
};
key-2 {
keypad,row = <0>;
keypad,column = <4>;
linux,code = <3>;
};
};
* Samsung's Keypad Controller device tree bindings
Samsung's Keypad controller is used to interface a SoC with a matrix-type
keypad device. The keypad controller supports multiple row and column lines.
A key can be placed at each intersection of a unique row and a unique column.
The keypad controller can sense a key-press and key-release and report the
event using a interrupt to the cpu.
Required SoC Specific Properties:
- compatible: should be one of the following
- "samsung,s3c6410-keypad": For controllers compatible with s3c6410 keypad
controller.
- "samsung,s5pv210-keypad": For controllers compatible with s5pv210 keypad
controller.
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: The interrupt number to the cpu.
Required Board Specific Properties:
- samsung,keypad-num-rows: Number of row lines connected to the keypad
controller.
- samsung,keypad-num-columns: Number of column lines connected to the
keypad controller.
- Keys represented as child nodes: Each key connected to the keypad
controller is represented as a child node to the keypad controller
device node and should include the following properties.
- keypad,row: the row number to which the key is connected.
- keypad,column: the column number to which the key is connected.
- linux,code: the key-code to be reported when the key is pressed
and released.
- pinctrl-0: Should specify pin control groups used for this controller.
- pinctrl-names: Should contain only one value - "default".
Optional Properties:
- wakeup-source: use any event on keypad as wakeup event.
(Legacy property supported: "linux,input-wakeup")
Optional Properties specific to linux:
- linux,keypad-no-autorepeat: do no enable autorepeat feature.
Example:
keypad@100a0000 {
compatible = "samsung,s5pv210-keypad";
reg = <0x100A0000 0x100>;
interrupts = <173>;
samsung,keypad-num-rows = <2>;
samsung,keypad-num-columns = <8>;
linux,input-no-autorepeat;
wakeup-source;
pinctrl-names = "default";
pinctrl-0 = <&keypad_rows &keypad_columns>;
key_1 {
keypad,row = <0>;
keypad,column = <3>;
linux,code = <2>;
};
key_2 {
keypad,row = <0>;
keypad,column = <4>;
linux,code = <3>;
};
key_3 {
keypad,row = <0>;
keypad,column = <5>;
linux,code = <4>;
};
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/touchscreen/goodix,gt9916.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Goodix Berlin series touchscreen controller
description: The Goodix Berlin series of touchscreen controllers
be connected to either I2C or SPI buses.
maintainers:
- Neil Armstrong <neil.armstrong@linaro.org>
allOf:
- $ref: touchscreen.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
enum:
- goodix,gt9916
reg:
maxItems: 1
interrupts:
maxItems: 1
reset-gpios:
maxItems: 1
avdd-supply:
description: Analog power supply regulator on AVDD pin
vddio-supply:
description: power supply regulator on VDDIO pin
spi-max-frequency: true
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
- avdd-supply
- touchscreen-size-x
- touchscreen-size-y
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
touchscreen@5d {
compatible = "goodix,gt9916";
reg = <0x5d>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
avdd-supply = <&ts_avdd>;
touchscreen-size-x = <1024>;
touchscreen-size-y = <768>;
};
};
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
num-cs = <1>;
cs-gpios = <&gpio 2 GPIO_ACTIVE_HIGH>;
touchscreen@0 {
compatible = "goodix,gt9916";
reg = <0>;
interrupt-parent = <&gpio>;
interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
avdd-supply = <&ts_avdd>;
spi-max-frequency = <1000000>;
touchscreen-size-x = <1024>;
touchscreen-size-y = <768>;
};
};
...
...@@ -37,8 +37,9 @@ properties: ...@@ -37,8 +37,9 @@ properties:
maxItems: 1 maxItems: 1
irq-gpios: irq-gpios:
description: GPIO pin used for IRQ. The driver uses the interrupt gpio pin description: GPIO pin used for IRQ input. Additionally, this line is
as output to reset the device. sampled by the device on reset deassertion to select the I2C client
address, thus it can be driven by the host during the reset sequence.
maxItems: 1 maxItems: 1
reset-gpios: reset-gpios:
......
...@@ -9,15 +9,14 @@ title: Imagis IST30XXC family touchscreen controller ...@@ -9,15 +9,14 @@ title: Imagis IST30XXC family touchscreen controller
maintainers: maintainers:
- Markuss Broks <markuss.broks@gmail.com> - Markuss Broks <markuss.broks@gmail.com>
allOf:
- $ref: touchscreen.yaml#
properties: properties:
$nodename: $nodename:
pattern: "^touchscreen@[0-9a-f]+$" pattern: "^touchscreen@[0-9a-f]+$"
compatible: compatible:
enum: enum:
- imagis,ist3032c
- imagis,ist3038b
- imagis,ist3038c - imagis,ist3038c
reg: reg:
...@@ -32,6 +31,10 @@ properties: ...@@ -32,6 +31,10 @@ properties:
vddio-supply: vddio-supply:
description: Power supply regulator for the I2C bus description: Power supply regulator for the I2C bus
linux,keycodes:
description: Keycodes for the touch keys
maxItems: 5
touchscreen-size-x: true touchscreen-size-x: true
touchscreen-size-y: true touchscreen-size-y: true
touchscreen-fuzz-x: true touchscreen-fuzz-x: true
...@@ -42,6 +45,18 @@ properties: ...@@ -42,6 +45,18 @@ properties:
additionalProperties: false additionalProperties: false
allOf:
- $ref: touchscreen.yaml#
- if:
not:
properties:
compatible:
contains:
const: imagis,ist3032c
then:
properties:
linux,keycodes: false
required: required:
- compatible - compatible
- reg - reg
......
...@@ -17,13 +17,17 @@ properties: ...@@ -17,13 +17,17 @@ properties:
pattern: "^touchscreen(@.*)?$" pattern: "^touchscreen(@.*)?$"
compatible: compatible:
items: oneOf:
- enum: - enum:
- melfas,mms114 - melfas,mms114
- melfas,mms134s - melfas,mms134s
- melfas,mms136 - melfas,mms136
- melfas,mms152 - melfas,mms152
- melfas,mms345l - melfas,mms345l
- items:
- enum:
- melfas,mms252
- const: melfas,mms114
reg: reg:
description: I2C address description: I2C address
......
...@@ -31,7 +31,7 @@ properties: ...@@ -31,7 +31,7 @@ properties:
maxItems: 1 maxItems: 1
firmware-name: firmware-name:
$ref: /schemas/types.yaml#/definitions/string maxItems: 1
description: > description: >
File basename for board specific firmware File basename for board specific firmware
......
...@@ -27,7 +27,7 @@ List of legacy properties and respective binding document ...@@ -27,7 +27,7 @@ List of legacy properties and respective binding document
Documentation/devicetree/bindings/mfd/tc3589x.txt Documentation/devicetree/bindings/mfd/tc3589x.txt
Documentation/devicetree/bindings/input/touchscreen/ads7846.txt Documentation/devicetree/bindings/input/touchscreen/ads7846.txt
4. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt 4. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
5. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung-keypad.txt 5. "linux,input-wakeup" Documentation/devicetree/bindings/input/samsung,s3c6410-keypad.yaml
6. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt 6. "nvidia,wakeup-source" Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt
Examples Examples
......
...@@ -38,7 +38,7 @@ static DEFINE_MUTEX(gameport_mutex); ...@@ -38,7 +38,7 @@ static DEFINE_MUTEX(gameport_mutex);
static LIST_HEAD(gameport_list); static LIST_HEAD(gameport_list);
static struct bus_type gameport_bus; static const struct bus_type gameport_bus;
static void gameport_add_port(struct gameport *gameport); static void gameport_add_port(struct gameport *gameport);
static void gameport_attach_driver(struct gameport_driver *drv); static void gameport_attach_driver(struct gameport_driver *drv);
...@@ -813,7 +813,7 @@ static int gameport_bus_match(struct device *dev, struct device_driver *drv) ...@@ -813,7 +813,7 @@ static int gameport_bus_match(struct device *dev, struct device_driver *drv)
return !gameport_drv->ignore; return !gameport_drv->ignore;
} }
static struct bus_type gameport_bus = { static const struct bus_type gameport_bus = {
.name = "gameport", .name = "gameport",
.dev_groups = gameport_device_groups, .dev_groups = gameport_device_groups,
.drv_groups = gameport_driver_groups, .drv_groups = gameport_driver_groups,
......
...@@ -18,6 +18,12 @@ ...@@ -18,6 +18,12 @@
#define VT_TRIGGER(_name) .trigger = NULL #define VT_TRIGGER(_name) .trigger = NULL
#endif #endif
#if IS_ENABLED(CONFIG_SND_CTL_LED)
#define AUDIO_TRIGGER(_name) .trigger = _name
#else
#define AUDIO_TRIGGER(_name) .trigger = NULL
#endif
static const struct { static const struct {
const char *name; const char *name;
const char *trigger; const char *trigger;
...@@ -29,7 +35,7 @@ static const struct { ...@@ -29,7 +35,7 @@ static const struct {
[LED_KANA] = { "kana", VT_TRIGGER("kbd-kanalock") }, [LED_KANA] = { "kana", VT_TRIGGER("kbd-kanalock") },
[LED_SLEEP] = { "sleep" } , [LED_SLEEP] = { "sleep" } ,
[LED_SUSPEND] = { "suspend" }, [LED_SUSPEND] = { "suspend" },
[LED_MUTE] = { "mute" }, [LED_MUTE] = { "mute", AUDIO_TRIGGER("audio-mute") },
[LED_MISC] = { "misc" }, [LED_MISC] = { "misc" },
[LED_MAIL] = { "mail" }, [LED_MAIL] = { "mail" },
[LED_CHARGING] = { "charging" }, [LED_CHARGING] = { "charging" },
......
...@@ -1918,7 +1918,7 @@ static char *input_devnode(const struct device *dev, umode_t *mode) ...@@ -1918,7 +1918,7 @@ static char *input_devnode(const struct device *dev, umode_t *mode)
return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev)); return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
} }
struct class input_class = { const struct class input_class = {
.name = "input", .name = "input",
.devnode = input_devnode, .devnode = input_devnode,
}; };
...@@ -2629,17 +2629,15 @@ int input_get_new_minor(int legacy_base, unsigned int legacy_num, ...@@ -2629,17 +2629,15 @@ int input_get_new_minor(int legacy_base, unsigned int legacy_num,
* locking is needed here. * locking is needed here.
*/ */
if (legacy_base >= 0) { if (legacy_base >= 0) {
int minor = ida_simple_get(&input_ida, int minor = ida_alloc_range(&input_ida, legacy_base,
legacy_base, legacy_base + legacy_num - 1,
legacy_base + legacy_num, GFP_KERNEL);
GFP_KERNEL);
if (minor >= 0 || !allow_dynamic) if (minor >= 0 || !allow_dynamic)
return minor; return minor;
} }
return ida_simple_get(&input_ida, return ida_alloc_range(&input_ida, INPUT_FIRST_DYNAMIC_DEV,
INPUT_FIRST_DYNAMIC_DEV, INPUT_MAX_CHAR_DEVICES, INPUT_MAX_CHAR_DEVICES - 1, GFP_KERNEL);
GFP_KERNEL);
} }
EXPORT_SYMBOL(input_get_new_minor); EXPORT_SYMBOL(input_get_new_minor);
...@@ -2652,7 +2650,7 @@ EXPORT_SYMBOL(input_get_new_minor); ...@@ -2652,7 +2650,7 @@ EXPORT_SYMBOL(input_get_new_minor);
*/ */
void input_free_minor(unsigned int minor) void input_free_minor(unsigned int minor)
{ {
ida_simple_remove(&input_ida, minor); ida_free(&input_ida, minor);
} }
EXPORT_SYMBOL(input_free_minor); EXPORT_SYMBOL(input_free_minor);
......
...@@ -127,6 +127,7 @@ static const struct xpad_device { ...@@ -127,6 +127,7 @@ static const struct xpad_device {
u8 mapping; u8 mapping;
u8 xtype; u8 xtype;
} xpad_device[] = { } xpad_device[] = {
/* Please keep this list sorted by vendor and product ID. */
{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 }, { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
{ 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 },
{ 0x03eb, 0xff02, "Wooting Two (Legacy)", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff02, "Wooting Two (Legacy)", 0, XTYPE_XBOX360 },
...@@ -152,9 +153,9 @@ static const struct xpad_device { ...@@ -152,9 +153,9 @@ static const struct xpad_device {
{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE }, { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE }, { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE },
{ 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE },
{ 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE },
{ 0x045e, 0x0b0a, "Microsoft X-Box Adaptive Controller", MAP_PROFILE_BUTTON, XTYPE_XBOXONE }, { 0x045e, 0x0b0a, "Microsoft X-Box Adaptive Controller", MAP_PROFILE_BUTTON, XTYPE_XBOXONE },
{ 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE },
{ 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, { 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 },
...@@ -340,7 +341,6 @@ static const struct xpad_device { ...@@ -340,7 +341,6 @@ static const struct xpad_device {
{ 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE }, { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
{ 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE }, { 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE },
{ 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 }, { 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 },
{ 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
...@@ -355,9 +355,9 @@ static const struct xpad_device { ...@@ -355,9 +355,9 @@ static const struct xpad_device {
{ 0x24c6, 0x5502, "Hori Fighting Stick VX Alt", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5502, "Hori Fighting Stick VX Alt", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x5503, "Hori Fighting Edge", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5503, "Hori Fighting Edge", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5510, "Hori Fighting Commander ONE (Xbox 360/PC Mode)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x550d, "Hori GEM Xbox controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x550d, "Hori GEM Xbox controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x5510, "Hori Fighting Commander ONE (Xbox 360/PC Mode)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE }, { 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x561a, "PowerA FUSION Controller", 0, XTYPE_XBOXONE }, { 0x24c6, 0x561a, "PowerA FUSION Controller", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 },
...@@ -366,8 +366,11 @@ static const struct xpad_device { ...@@ -366,8 +366,11 @@ static const struct xpad_device {
{ 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 },
{ 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
{ 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 }, { 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 },
{ 0x294b, 0x3303, "Snakebyte GAMEPAD BASE X", 0, XTYPE_XBOXONE },
{ 0x294b, 0x3404, "Snakebyte GAMEPAD RGB X", 0, XTYPE_XBOXONE },
{ 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE }, { 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE },
{ 0x2dc8, 0x3106, "8BitDo Pro 2 Wired Controller", 0, XTYPE_XBOX360 }, { 0x2dc8, 0x3106, "8BitDo Pro 2 Wired Controller", 0, XTYPE_XBOX360 },
{ 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 },
...@@ -465,6 +468,10 @@ static const signed short xpad_btn_paddles[] = { ...@@ -465,6 +468,10 @@ static const signed short xpad_btn_paddles[] = {
{ XPAD_XBOXONE_VENDOR_PROTOCOL((vend), 208) } { XPAD_XBOXONE_VENDOR_PROTOCOL((vend), 208) }
static const struct usb_device_id xpad_table[] = { static const struct usb_device_id xpad_table[] = {
/*
* Please keep this list sorted by vendor ID. Note that there are 2
* macros - XPAD_XBOX360_VENDOR and XPAD_XBOXONE_VENDOR.
*/
{ USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not-approved class */ { USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not-approved class */
XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 controller */ XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 controller */
XPAD_XBOX360_VENDOR(0x03eb), /* Wooting Keyboards (Legacy) */ XPAD_XBOX360_VENDOR(0x03eb), /* Wooting Keyboards (Legacy) */
...@@ -507,6 +514,7 @@ static const struct usb_device_id xpad_table[] = { ...@@ -507,6 +514,7 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA controllers */ XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA controllers */
XPAD_XBOX360_VENDOR(0x2563), /* OneXPlayer Gamepad */ XPAD_XBOX360_VENDOR(0x2563), /* OneXPlayer Gamepad */
XPAD_XBOX360_VENDOR(0x260d), /* Dareu H101 */ XPAD_XBOX360_VENDOR(0x260d), /* Dareu H101 */
XPAD_XBOXONE_VENDOR(0x294b), /* Snakebyte */
XPAD_XBOX360_VENDOR(0x2c22), /* Qanba Controllers */ XPAD_XBOX360_VENDOR(0x2c22), /* Qanba Controllers */
XPAD_XBOX360_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller */ XPAD_XBOX360_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller */
XPAD_XBOXONE_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller for Xbox */ XPAD_XBOXONE_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller for Xbox */
......
...@@ -418,7 +418,7 @@ static struct platform_driver bcm_kp_device_driver = { ...@@ -418,7 +418,7 @@ static struct platform_driver bcm_kp_device_driver = {
.probe = bcm_kp_probe, .probe = bcm_kp_probe,
.driver = { .driver = {
.name = "bcm-keypad", .name = "bcm-keypad",
.of_match_table = of_match_ptr(bcm_kp_of_match), .of_match_table = bcm_kp_of_match,
} }
}; };
......
...@@ -28,7 +28,9 @@ struct matrix_keypad { ...@@ -28,7 +28,9 @@ struct matrix_keypad {
struct input_dev *input_dev; struct input_dev *input_dev;
unsigned int row_shift; unsigned int row_shift;
DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS); unsigned int row_irqs[MATRIX_MAX_ROWS];
unsigned int num_row_irqs;
DECLARE_BITMAP(wakeup_enabled_irqs, MATRIX_MAX_ROWS);
uint32_t last_key_state[MATRIX_MAX_COLS]; uint32_t last_key_state[MATRIX_MAX_COLS];
struct delayed_work work; struct delayed_work work;
...@@ -85,28 +87,18 @@ static bool row_asserted(const struct matrix_keypad_platform_data *pdata, ...@@ -85,28 +87,18 @@ static bool row_asserted(const struct matrix_keypad_platform_data *pdata,
static void enable_row_irqs(struct matrix_keypad *keypad) static void enable_row_irqs(struct matrix_keypad *keypad)
{ {
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i; int i;
if (pdata->clustered_irq > 0) for (i = 0; i < keypad->num_row_irqs; i++)
enable_irq(pdata->clustered_irq); enable_irq(keypad->row_irqs[i]);
else {
for (i = 0; i < pdata->num_row_gpios; i++)
enable_irq(gpio_to_irq(pdata->row_gpios[i]));
}
} }
static void disable_row_irqs(struct matrix_keypad *keypad) static void disable_row_irqs(struct matrix_keypad *keypad)
{ {
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i; int i;
if (pdata->clustered_irq > 0) for (i = 0; i < keypad->num_row_irqs; i++)
disable_irq_nosync(pdata->clustered_irq); disable_irq_nosync(keypad->row_irqs[i]);
else {
for (i = 0; i < pdata->num_row_gpios; i++)
disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
}
} }
/* /*
...@@ -232,44 +224,20 @@ static void matrix_keypad_stop(struct input_dev *dev) ...@@ -232,44 +224,20 @@ static void matrix_keypad_stop(struct input_dev *dev)
static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad) static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
{ {
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
unsigned int gpio;
int i; int i;
if (pdata->clustered_irq > 0) { for_each_clear_bit(i, keypad->wakeup_enabled_irqs, keypad->num_row_irqs)
if (enable_irq_wake(pdata->clustered_irq) == 0) if (enable_irq_wake(keypad->row_irqs[i]) == 0)
keypad->gpio_all_disabled = true; __set_bit(i, keypad->wakeup_enabled_irqs);
} else {
for (i = 0; i < pdata->num_row_gpios; i++) {
if (!test_bit(i, keypad->disabled_gpios)) {
gpio = pdata->row_gpios[i];
if (enable_irq_wake(gpio_to_irq(gpio)) == 0)
__set_bit(i, keypad->disabled_gpios);
}
}
}
} }
static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad) static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
{ {
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
unsigned int gpio;
int i; int i;
if (pdata->clustered_irq > 0) { for_each_set_bit(i, keypad->wakeup_enabled_irqs, keypad->num_row_irqs) {
if (keypad->gpio_all_disabled) { disable_irq_wake(keypad->row_irqs[i]);
disable_irq_wake(pdata->clustered_irq); __clear_bit(i, keypad->wakeup_enabled_irqs);
keypad->gpio_all_disabled = false;
}
} else {
for (i = 0; i < pdata->num_row_gpios; i++) {
if (test_and_clear_bit(i, keypad->disabled_gpios)) {
gpio = pdata->row_gpios[i];
disable_irq_wake(gpio_to_irq(gpio));
}
}
} }
} }
...@@ -306,96 +274,83 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev, ...@@ -306,96 +274,83 @@ static int matrix_keypad_init_gpio(struct platform_device *pdev,
struct matrix_keypad *keypad) struct matrix_keypad *keypad)
{ {
const struct matrix_keypad_platform_data *pdata = keypad->pdata; const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i, err; int i, irq, err;
/* initialized strobe lines as outputs, activated */ /* initialized strobe lines as outputs, activated */
for (i = 0; i < pdata->num_col_gpios; i++) { for (i = 0; i < pdata->num_col_gpios; i++) {
err = gpio_request(pdata->col_gpios[i], "matrix_kbd_col"); err = devm_gpio_request(&pdev->dev,
pdata->col_gpios[i], "matrix_kbd_col");
if (err) { if (err) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"failed to request GPIO%d for COL%d\n", "failed to request GPIO%d for COL%d\n",
pdata->col_gpios[i], i); pdata->col_gpios[i], i);
goto err_free_cols; return err;
} }
gpio_direction_output(pdata->col_gpios[i], !pdata->active_low); gpio_direction_output(pdata->col_gpios[i], !pdata->active_low);
} }
for (i = 0; i < pdata->num_row_gpios; i++) { for (i = 0; i < pdata->num_row_gpios; i++) {
err = gpio_request(pdata->row_gpios[i], "matrix_kbd_row"); err = devm_gpio_request(&pdev->dev,
pdata->row_gpios[i], "matrix_kbd_row");
if (err) { if (err) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"failed to request GPIO%d for ROW%d\n", "failed to request GPIO%d for ROW%d\n",
pdata->row_gpios[i], i); pdata->row_gpios[i], i);
goto err_free_rows; return err;
} }
gpio_direction_input(pdata->row_gpios[i]); gpio_direction_input(pdata->row_gpios[i]);
} }
if (pdata->clustered_irq > 0) { if (pdata->clustered_irq > 0) {
err = request_any_context_irq(pdata->clustered_irq, err = devm_request_any_context_irq(&pdev->dev,
pdata->clustered_irq,
matrix_keypad_interrupt, matrix_keypad_interrupt,
pdata->clustered_irq_flags, pdata->clustered_irq_flags,
"matrix-keypad", keypad); "matrix-keypad", keypad);
if (err < 0) { if (err < 0) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Unable to acquire clustered interrupt\n"); "Unable to acquire clustered interrupt\n");
goto err_free_rows; return err;
} }
keypad->row_irqs[0] = pdata->clustered_irq;
keypad->num_row_irqs = 1;
} else { } else {
for (i = 0; i < pdata->num_row_gpios; i++) { for (i = 0; i < pdata->num_row_gpios; i++) {
err = request_any_context_irq( irq = gpio_to_irq(pdata->row_gpios[i]);
gpio_to_irq(pdata->row_gpios[i]), if (irq < 0) {
err = irq;
dev_err(&pdev->dev,
"Unable to convert GPIO line %i to irq: %d\n",
pdata->row_gpios[i], err);
return err;
}
err = devm_request_any_context_irq(&pdev->dev,
irq,
matrix_keypad_interrupt, matrix_keypad_interrupt,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING, IRQF_TRIGGER_FALLING,
"matrix-keypad", keypad); "matrix-keypad", keypad);
if (err < 0) { if (err < 0) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Unable to acquire interrupt for GPIO line %i\n", "Unable to acquire interrupt for GPIO line %i\n",
pdata->row_gpios[i]); pdata->row_gpios[i]);
goto err_free_irqs; return err;
} }
keypad->row_irqs[i] = irq;
} }
keypad->num_row_irqs = pdata->num_row_gpios;
} }
/* initialized as disabled - enabled by input->open */ /* initialized as disabled - enabled by input->open */
disable_row_irqs(keypad); disable_row_irqs(keypad);
return 0;
err_free_irqs:
while (--i >= 0)
free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
i = pdata->num_row_gpios;
err_free_rows:
while (--i >= 0)
gpio_free(pdata->row_gpios[i]);
i = pdata->num_col_gpios;
err_free_cols:
while (--i >= 0)
gpio_free(pdata->col_gpios[i]);
return err;
}
static void matrix_keypad_free_gpio(struct matrix_keypad *keypad)
{
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
int i;
if (pdata->clustered_irq > 0) { return 0;
free_irq(pdata->clustered_irq, keypad);
} else {
for (i = 0; i < pdata->num_row_gpios; i++)
free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
}
for (i = 0; i < pdata->num_row_gpios; i++)
gpio_free(pdata->row_gpios[i]);
for (i = 0; i < pdata->num_col_gpios; i++)
gpio_free(pdata->col_gpios[i]);
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -494,12 +449,13 @@ static int matrix_keypad_probe(struct platform_device *pdev) ...@@ -494,12 +449,13 @@ static int matrix_keypad_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL); keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL);
input_dev = input_allocate_device(); if (!keypad)
if (!keypad || !input_dev) { return -ENOMEM;
err = -ENOMEM;
goto err_free_mem; input_dev = devm_input_allocate_device(&pdev->dev);
} if (!input_dev)
return -ENOMEM;
keypad->input_dev = input_dev; keypad->input_dev = input_dev;
keypad->pdata = pdata; keypad->pdata = pdata;
...@@ -510,7 +466,6 @@ static int matrix_keypad_probe(struct platform_device *pdev) ...@@ -510,7 +466,6 @@ static int matrix_keypad_probe(struct platform_device *pdev)
input_dev->name = pdev->name; input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST; input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
input_dev->open = matrix_keypad_start; input_dev->open = matrix_keypad_start;
input_dev->close = matrix_keypad_stop; input_dev->close = matrix_keypad_stop;
...@@ -520,7 +475,7 @@ static int matrix_keypad_probe(struct platform_device *pdev) ...@@ -520,7 +475,7 @@ static int matrix_keypad_probe(struct platform_device *pdev)
NULL, input_dev); NULL, input_dev);
if (err) { if (err) {
dev_err(&pdev->dev, "failed to build keymap\n"); dev_err(&pdev->dev, "failed to build keymap\n");
goto err_free_mem; return -ENOMEM;
} }
if (!pdata->no_autorepeat) if (!pdata->no_autorepeat)
...@@ -530,32 +485,16 @@ static int matrix_keypad_probe(struct platform_device *pdev) ...@@ -530,32 +485,16 @@ static int matrix_keypad_probe(struct platform_device *pdev)
err = matrix_keypad_init_gpio(pdev, keypad); err = matrix_keypad_init_gpio(pdev, keypad);
if (err) if (err)
goto err_free_mem; return err;
err = input_register_device(keypad->input_dev); err = input_register_device(keypad->input_dev);
if (err) if (err)
goto err_free_gpio; return err;
device_init_wakeup(&pdev->dev, pdata->wakeup); device_init_wakeup(&pdev->dev, pdata->wakeup);
platform_set_drvdata(pdev, keypad); platform_set_drvdata(pdev, keypad);
return 0; return 0;
err_free_gpio:
matrix_keypad_free_gpio(keypad);
err_free_mem:
input_free_device(input_dev);
kfree(keypad);
return err;
}
static void matrix_keypad_remove(struct platform_device *pdev)
{
struct matrix_keypad *keypad = platform_get_drvdata(pdev);
matrix_keypad_free_gpio(keypad);
input_unregister_device(keypad->input_dev);
kfree(keypad);
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -568,7 +507,6 @@ MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match); ...@@ -568,7 +507,6 @@ MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match);
static struct platform_driver matrix_keypad_driver = { static struct platform_driver matrix_keypad_driver = {
.probe = matrix_keypad_probe, .probe = matrix_keypad_probe,
.remove_new = matrix_keypad_remove,
.driver = { .driver = {
.name = "matrix-keypad", .name = "matrix-keypad",
.pm = pm_sleep_ptr(&matrix_keypad_pm_ops), .pm = pm_sleep_ptr(&matrix_keypad_pm_ops),
......
// SPDX-License-Identifier: GPL-2.0-only
/* /*
* Marvell 88PM80x ONKEY driver * Marvell 88PM80x ONKEY driver
* *
* Copyright (C) 2012 Marvell International Ltd. * Copyright (C) 2012 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com> * Haojian Zhuang <haojian.zhuang@marvell.com>
* Qiao Zhou <zhouqiao@marvell.com> * Qiao Zhou <zhouqiao@marvell.com>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file "COPYING" in the main directory of this
* archive for more details.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
......
...@@ -620,6 +620,118 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = { ...@@ -620,6 +620,118 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
}, },
}, },
}, },
{
.prod_num = IQS7222_PROD_NUM_D,
.fw_major = 1,
.fw_minor = 2,
.touch_link = 1770,
.allow_offset = 9,
.event_offset = 10,
.comms_offset = 11,
.reg_grps = {
[IQS7222_REG_GRP_STAT] = {
.base = IQS7222_SYS_STATUS,
.num_row = 1,
.num_col = 7,
},
[IQS7222_REG_GRP_CYCLE] = {
.base = 0x8000,
.num_row = 7,
.num_col = 2,
},
[IQS7222_REG_GRP_GLBL] = {
.base = 0x8700,
.num_row = 1,
.num_col = 3,
},
[IQS7222_REG_GRP_BTN] = {
.base = 0x9000,
.num_row = 14,
.num_col = 3,
},
[IQS7222_REG_GRP_CHAN] = {
.base = 0xA000,
.num_row = 14,
.num_col = 4,
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAE00,
.num_row = 1,
.num_col = 2,
},
[IQS7222_REG_GRP_TPAD] = {
.base = 0xB000,
.num_row = 1,
.num_col = 24,
},
[IQS7222_REG_GRP_GPIO] = {
.base = 0xC000,
.num_row = 3,
.num_col = 3,
},
[IQS7222_REG_GRP_SYS] = {
.base = IQS7222_SYS_SETUP,
.num_row = 1,
.num_col = 12,
},
},
},
{
.prod_num = IQS7222_PROD_NUM_D,
.fw_major = 1,
.fw_minor = 1,
.touch_link = 1774,
.allow_offset = 9,
.event_offset = 10,
.comms_offset = 11,
.reg_grps = {
[IQS7222_REG_GRP_STAT] = {
.base = IQS7222_SYS_STATUS,
.num_row = 1,
.num_col = 7,
},
[IQS7222_REG_GRP_CYCLE] = {
.base = 0x8000,
.num_row = 7,
.num_col = 2,
},
[IQS7222_REG_GRP_GLBL] = {
.base = 0x8700,
.num_row = 1,
.num_col = 3,
},
[IQS7222_REG_GRP_BTN] = {
.base = 0x9000,
.num_row = 14,
.num_col = 3,
},
[IQS7222_REG_GRP_CHAN] = {
.base = 0xA000,
.num_row = 14,
.num_col = 4,
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAE00,
.num_row = 1,
.num_col = 2,
},
[IQS7222_REG_GRP_TPAD] = {
.base = 0xB000,
.num_row = 1,
.num_col = 24,
},
[IQS7222_REG_GRP_GPIO] = {
.base = 0xC000,
.num_row = 3,
.num_col = 3,
},
[IQS7222_REG_GRP_SYS] = {
.base = IQS7222_SYS_SETUP,
.num_row = 1,
.num_col = 12,
},
},
},
{ {
.prod_num = IQS7222_PROD_NUM_D, .prod_num = IQS7222_PROD_NUM_D,
.fw_major = 0, .fw_major = 0,
......
...@@ -439,16 +439,4 @@ config MOUSE_SYNAPTICS_USB ...@@ -439,16 +439,4 @@ config MOUSE_SYNAPTICS_USB
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called synaptics_usb. module will be called synaptics_usb.
config MOUSE_NAVPOINT_PXA27x
tristate "Synaptics NavPoint (PXA27x SSP/SPI)"
depends on PXA27x && PXA_SSP
help
This driver adds support for the Synaptics NavPoint touchpad connected
to a PXA27x SSP port in SPI slave mode. The device emulates a mouse;
a tap or tap-and-a-half drag gesture emulates the left mouse button.
For example, use the xf86-input-evdev driver for an X pointing device.
To compile this driver as a module, choose M here: the
module will be called navpoint.
endif endif
...@@ -15,7 +15,6 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o ...@@ -15,7 +15,6 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o obj-$(CONFIG_MOUSE_INPORT) += inport.o
obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x) += navpoint.o
obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o
obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Synaptics NavPoint (PXA27x SSP/SPI) driver.
*
* Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/input/navpoint.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/pxa2xx_ssp.h>
#include <linux/slab.h>
/*
* Synaptics Modular Embedded Protocol: Module Packet Format.
* Module header byte 2:0 = Length (# bytes that follow)
* Module header byte 4:3 = Control
* Module header byte 7:5 = Module Address
*/
#define HEADER_LENGTH(byte) ((byte) & 0x07)
#define HEADER_CONTROL(byte) (((byte) >> 3) & 0x03)
#define HEADER_ADDRESS(byte) ((byte) >> 5)
struct navpoint {
struct ssp_device *ssp;
struct input_dev *input;
struct device *dev;
struct gpio_desc *gpiod;
int index;
u8 data[1 + HEADER_LENGTH(0xff)];
};
/*
* Initialization values for SSCR0_x, SSCR1_x, SSSR_x.
*/
static const u32 sscr0 = 0
| SSCR0_TUM /* TIM = 1; No TUR interrupts */
| SSCR0_RIM /* RIM = 1; No ROR interrupts */
| SSCR0_SSE /* SSE = 1; SSP enabled */
| SSCR0_Motorola /* FRF = 0; Motorola SPI */
| SSCR0_DataSize(16) /* DSS = 15; Data size = 16-bit */
;
static const u32 sscr1 = 0
| SSCR1_SCFR /* SCFR = 1; SSPSCLK only during transfers */
| SSCR1_SCLKDIR /* SCLKDIR = 1; Slave mode */
| SSCR1_SFRMDIR /* SFRMDIR = 1; Slave mode */
| SSCR1_RWOT /* RWOT = 1; Receive without transmit mode */
| SSCR1_RxTresh(1) /* RFT = 0; Receive FIFO threshold = 1 */
| SSCR1_SPH /* SPH = 1; SSPSCLK inactive 0.5 + 1 cycles */
| SSCR1_RIE /* RIE = 1; Receive FIFO interrupt enabled */
;
static const u32 sssr = 0
| SSSR_BCE /* BCE = 1; Clear BCE */
| SSSR_TUR /* TUR = 1; Clear TUR */
| SSSR_EOC /* EOC = 1; Clear EOC */
| SSSR_TINT /* TINT = 1; Clear TINT */
| SSSR_PINT /* PINT = 1; Clear PINT */
| SSSR_ROR /* ROR = 1; Clear ROR */
;
/*
* MEP Query $22: Touchpad Coordinate Range Query is not supported by
* the NavPoint module, so sampled values provide the default limits.
*/
#define NAVPOINT_X_MIN 1278
#define NAVPOINT_X_MAX 5340
#define NAVPOINT_Y_MIN 1572
#define NAVPOINT_Y_MAX 4396
#define NAVPOINT_PRESSURE_MIN 0
#define NAVPOINT_PRESSURE_MAX 255
static void navpoint_packet(struct navpoint *navpoint)
{
int finger;
int gesture;
int x, y, z;
switch (navpoint->data[0]) {
case 0xff: /* Garbage (packet?) between reset and Hello packet */
case 0x00: /* Module 0, NULL packet */
break;
case 0x0e: /* Module 0, Absolute packet */
finger = (navpoint->data[1] & 0x01);
gesture = (navpoint->data[1] & 0x02);
x = ((navpoint->data[2] & 0x1f) << 8) | navpoint->data[3];
y = ((navpoint->data[4] & 0x1f) << 8) | navpoint->data[5];
z = navpoint->data[6];
input_report_key(navpoint->input, BTN_TOUCH, finger);
input_report_abs(navpoint->input, ABS_X, x);
input_report_abs(navpoint->input, ABS_Y, y);
input_report_abs(navpoint->input, ABS_PRESSURE, z);
input_report_key(navpoint->input, BTN_TOOL_FINGER, finger);
input_report_key(navpoint->input, BTN_LEFT, gesture);
input_sync(navpoint->input);
break;
case 0x19: /* Module 0, Hello packet */
if ((navpoint->data[1] & 0xf0) == 0x10)
break;
fallthrough;
default:
dev_warn(navpoint->dev,
"spurious packet: data=0x%02x,0x%02x,...\n",
navpoint->data[0], navpoint->data[1]);
break;
}
}
static irqreturn_t navpoint_irq(int irq, void *dev_id)
{
struct navpoint *navpoint = dev_id;
struct ssp_device *ssp = navpoint->ssp;
irqreturn_t ret = IRQ_NONE;
u32 status;
status = pxa_ssp_read_reg(ssp, SSSR);
if (status & sssr) {
dev_warn(navpoint->dev,
"unexpected interrupt: status=0x%08x\n", status);
pxa_ssp_write_reg(ssp, SSSR, (status & sssr));
ret = IRQ_HANDLED;
}
while (status & SSSR_RNE) {
u32 data;
data = pxa_ssp_read_reg(ssp, SSDR);
navpoint->data[navpoint->index + 0] = (data >> 8);
navpoint->data[navpoint->index + 1] = data;
navpoint->index += 2;
if (HEADER_LENGTH(navpoint->data[0]) < navpoint->index) {
navpoint_packet(navpoint);
navpoint->index = 0;
}
status = pxa_ssp_read_reg(ssp, SSSR);
ret = IRQ_HANDLED;
}
return ret;
}
static void navpoint_up(struct navpoint *navpoint)
{
struct ssp_device *ssp = navpoint->ssp;
int timeout;
clk_prepare_enable(ssp->clk);
pxa_ssp_write_reg(ssp, SSCR1, sscr1);
pxa_ssp_write_reg(ssp, SSSR, sssr);
pxa_ssp_write_reg(ssp, SSTO, 0);
pxa_ssp_write_reg(ssp, SSCR0, sscr0); /* SSCR0_SSE written last */
/* Wait until SSP port is ready for slave clock operations */
for (timeout = 100; timeout != 0; --timeout) {
if (!(pxa_ssp_read_reg(ssp, SSSR) & SSSR_CSS))
break;
msleep(1);
}
if (timeout == 0)
dev_err(navpoint->dev,
"timeout waiting for SSSR[CSS] to clear\n");
gpiod_set_value(navpoint->gpiod, 1);
}
static void navpoint_down(struct navpoint *navpoint)
{
struct ssp_device *ssp = navpoint->ssp;
gpiod_set_value(navpoint->gpiod, 0);
pxa_ssp_write_reg(ssp, SSCR0, 0);
clk_disable_unprepare(ssp->clk);
}
static int navpoint_open(struct input_dev *input)
{
struct navpoint *navpoint = input_get_drvdata(input);
navpoint_up(navpoint);
return 0;
}
static void navpoint_close(struct input_dev *input)
{
struct navpoint *navpoint = input_get_drvdata(input);
navpoint_down(navpoint);
}
static int navpoint_probe(struct platform_device *pdev)
{
const struct navpoint_platform_data *pdata =
dev_get_platdata(&pdev->dev);
struct ssp_device *ssp;
struct input_dev *input;
struct navpoint *navpoint;
int error;
if (!pdata) {
dev_err(&pdev->dev, "no platform data\n");
return -EINVAL;
}
ssp = pxa_ssp_request(pdata->port, pdev->name);
if (!ssp)
return -ENODEV;
/* HaRET does not disable devices before jumping into Linux */
if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
pxa_ssp_write_reg(ssp, SSCR0, 0);
dev_warn(&pdev->dev, "ssp%d already enabled\n", pdata->port);
}
navpoint = kzalloc(sizeof(*navpoint), GFP_KERNEL);
input = input_allocate_device();
if (!navpoint || !input) {
error = -ENOMEM;
goto err_free_mem;
}
navpoint->gpiod = gpiod_get_optional(&pdev->dev,
NULL, GPIOD_OUT_LOW);
if (IS_ERR(navpoint->gpiod)) {
error = PTR_ERR(navpoint->gpiod);
dev_err(&pdev->dev, "error getting GPIO\n");
goto err_free_mem;
}
gpiod_set_consumer_name(navpoint->gpiod, "SYNAPTICS_ON");
navpoint->ssp = ssp;
navpoint->input = input;
navpoint->dev = &pdev->dev;
input->name = pdev->name;
input->dev.parent = &pdev->dev;
__set_bit(EV_KEY, input->evbit);
__set_bit(EV_ABS, input->evbit);
__set_bit(BTN_LEFT, input->keybit);
__set_bit(BTN_TOUCH, input->keybit);
__set_bit(BTN_TOOL_FINGER, input->keybit);
input_set_abs_params(input, ABS_X,
NAVPOINT_X_MIN, NAVPOINT_X_MAX, 0, 0);
input_set_abs_params(input, ABS_Y,
NAVPOINT_Y_MIN, NAVPOINT_Y_MAX, 0, 0);
input_set_abs_params(input, ABS_PRESSURE,
NAVPOINT_PRESSURE_MIN, NAVPOINT_PRESSURE_MAX,
0, 0);
input->open = navpoint_open;
input->close = navpoint_close;
input_set_drvdata(input, navpoint);
error = request_irq(ssp->irq, navpoint_irq, 0, pdev->name, navpoint);
if (error)
goto err_free_mem;
error = input_register_device(input);
if (error)
goto err_free_irq;
platform_set_drvdata(pdev, navpoint);
dev_dbg(&pdev->dev, "ssp%d, irq %d\n", pdata->port, ssp->irq);
return 0;
err_free_irq:
free_irq(ssp->irq, navpoint);
err_free_mem:
input_free_device(input);
kfree(navpoint);
pxa_ssp_free(ssp);
return error;
}
static void navpoint_remove(struct platform_device *pdev)
{
struct navpoint *navpoint = platform_get_drvdata(pdev);
struct ssp_device *ssp = navpoint->ssp;
free_irq(ssp->irq, navpoint);
input_unregister_device(navpoint->input);
kfree(navpoint);
pxa_ssp_free(ssp);
}
static int navpoint_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct navpoint *navpoint = platform_get_drvdata(pdev);
struct input_dev *input = navpoint->input;
mutex_lock(&input->mutex);
if (input_device_enabled(input))
navpoint_down(navpoint);
mutex_unlock(&input->mutex);
return 0;
}
static int navpoint_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct navpoint *navpoint = platform_get_drvdata(pdev);
struct input_dev *input = navpoint->input;
mutex_lock(&input->mutex);
if (input_device_enabled(input))
navpoint_up(navpoint);
mutex_unlock(&input->mutex);
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(navpoint_pm_ops,
navpoint_suspend, navpoint_resume);
static struct platform_driver navpoint_driver = {
.probe = navpoint_probe,
.remove_new = navpoint_remove,
.driver = {
.name = "navpoint",
.pm = pm_sleep_ptr(&navpoint_pm_ops),
},
};
module_platform_driver(navpoint_driver);
MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
MODULE_DESCRIPTION("Synaptics NavPoint (PXA27x SSP/SPI) driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:navpoint");
...@@ -344,7 +344,7 @@ static int rmi_bus_match(struct device *dev, struct device_driver *drv) ...@@ -344,7 +344,7 @@ static int rmi_bus_match(struct device *dev, struct device_driver *drv)
return physical || rmi_function_match(dev, drv); return physical || rmi_function_match(dev, drv);
} }
struct bus_type rmi_bus_type = { const struct bus_type rmi_bus_type = {
.match = rmi_bus_match, .match = rmi_bus_match,
.name = "rmi4", .name = "rmi4",
}; };
......
...@@ -185,7 +185,7 @@ static inline int rmi_write_block(struct rmi_device *d, u16 addr, ...@@ -185,7 +185,7 @@ static inline int rmi_write_block(struct rmi_device *d, u16 addr,
int rmi_for_each_dev(void *data, int (*func)(struct device *dev, void *data)); int rmi_for_each_dev(void *data, int (*func)(struct device *dev, void *data));
extern struct bus_type rmi_bus_type; extern const struct bus_type rmi_bus_type;
int rmi_of_property_read_u32(struct device *dev, u32 *result, int rmi_of_property_read_u32(struct device *dev, u32 *result,
const char *prop, bool optional); const char *prop, bool optional);
......
...@@ -1196,7 +1196,11 @@ static int rmi_driver_probe(struct device *dev) ...@@ -1196,7 +1196,11 @@ static int rmi_driver_probe(struct device *dev)
} }
rmi_driver_set_input_params(rmi_dev, data->input); rmi_driver_set_input_params(rmi_dev, data->input);
data->input->phys = devm_kasprintf(dev, GFP_KERNEL, data->input->phys = devm_kasprintf(dev, GFP_KERNEL,
"%s/input0", dev_name(dev)); "%s/input0", dev_name(dev));
if (!data->input->phys) {
retval = -ENOMEM;
goto err;
}
} }
retval = rmi_init_functions(data); retval = rmi_init_functions(data);
......
...@@ -1007,7 +1007,7 @@ irqreturn_t serio_interrupt(struct serio *serio, ...@@ -1007,7 +1007,7 @@ irqreturn_t serio_interrupt(struct serio *serio,
} }
EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(serio_interrupt);
struct bus_type serio_bus = { const struct bus_type serio_bus = {
.name = "serio", .name = "serio",
.drv_groups = serio_driver_groups, .drv_groups = serio_driver_groups,
.match = serio_bus_match, .match = serio_bus_match,
......
...@@ -219,8 +219,7 @@ static void sxps2_close(struct serio *pserio) ...@@ -219,8 +219,7 @@ static void sxps2_close(struct serio *pserio)
/** /**
* xps2_of_probe - probe method for the PS/2 device. * xps2_of_probe - probe method for the PS/2 device.
* @of_dev: pointer to OF device structure * @ofdev: pointer to OF device structure
* @match: pointer to the structure used for matching a device
* *
* This function probes the PS/2 device in the device tree. * This function probes the PS/2 device in the device tree.
* It initializes the driver data structure and the hardware. * It initializes the driver data structure and the hardware.
......
...@@ -416,6 +416,37 @@ config TOUCHSCREEN_GOODIX ...@@ -416,6 +416,37 @@ config TOUCHSCREEN_GOODIX
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called goodix. module will be called goodix.
config TOUCHSCREEN_GOODIX_BERLIN_CORE
tristate
config TOUCHSCREEN_GOODIX_BERLIN_I2C
tristate "Goodix Berlin I2C touchscreen"
depends on I2C
select REGMAP_I2C
select TOUCHSCREEN_GOODIX_BERLIN_CORE
help
Say Y here if you have a Goodix Berlin IC connected to
your system via I2C.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called goodix_berlin_i2c.
config TOUCHSCREEN_GOODIX_BERLIN_SPI
tristate "Goodix Berlin SPI touchscreen"
depends on SPI_MASTER
select REGMAP
select TOUCHSCREEN_GOODIX_BERLIN_CORE
help
Say Y here if you have a Goodix Berlin IC connected to
your system via SPI.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called goodix_berlin_spi.
config TOUCHSCREEN_HIDEEP config TOUCHSCREEN_HIDEEP
tristate "HiDeep Touch IC" tristate "HiDeep Touch IC"
depends on I2C depends on I2C
......
...@@ -47,6 +47,9 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o ...@@ -47,6 +47,9 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI) += goodix_berlin_spi.o
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
......
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Goodix Touchscreen Driver
* Copyright (C) 2020 - 2021 Goodix, Inc.
* Copyright (C) 2023 Linaro Ltd.
*
* Based on goodix_berlin_berlin driver.
*/
#ifndef __GOODIX_BERLIN_H_
#define __GOODIX_BERLIN_H_
#include <linux/pm.h>
struct device;
struct input_id;
struct regmap;
int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
struct regmap *regmap);
extern const struct dev_pm_ops goodix_berlin_pm_ops;
#endif
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Goodix Berlin Touchscreen Driver
*
* Copyright (C) 2020 - 2021 Goodix, Inc.
* Copyright (C) 2023 Linaro Ltd.
*
* Based on goodix_ts_berlin driver.
*/
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/input.h>
#include "goodix_berlin.h"
#define I2C_MAX_TRANSFER_SIZE 256
static const struct regmap_config goodix_berlin_i2c_regmap_conf = {
.reg_bits = 32,
.val_bits = 8,
.max_raw_read = I2C_MAX_TRANSFER_SIZE,
.max_raw_write = I2C_MAX_TRANSFER_SIZE,
};
/* vendor & product left unassigned here, should probably be updated from fw info */
static const struct input_id goodix_berlin_i2c_input_id = {
.bustype = BUS_I2C,
};
static int goodix_berlin_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;
int error;
regmap = devm_regmap_init_i2c(client, &goodix_berlin_i2c_regmap_conf);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
error = goodix_berlin_probe(&client->dev, client->irq,
&goodix_berlin_i2c_input_id, regmap);
if (error)
return error;
return 0;
}
static const struct i2c_device_id goodix_berlin_i2c_id[] = {
{ "gt9916", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, goodix_berlin_i2c_id);
static const struct of_device_id goodix_berlin_i2c_of_match[] = {
{ .compatible = "goodix,gt9916", },
{ }
};
MODULE_DEVICE_TABLE(of, goodix_berlin_i2c_of_match);
static struct i2c_driver goodix_berlin_i2c_driver = {
.driver = {
.name = "goodix-berlin-i2c",
.of_match_table = goodix_berlin_i2c_of_match,
.pm = pm_sleep_ptr(&goodix_berlin_pm_ops),
},
.probe = goodix_berlin_i2c_probe,
.id_table = goodix_berlin_i2c_id,
};
module_i2c_driver(goodix_berlin_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Goodix Berlin I2C Touchscreen driver");
MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Goodix Berlin Touchscreen Driver
*
* Copyright (C) 2020 - 2021 Goodix, Inc.
* Copyright (C) 2023 Linaro Ltd.
*
* Based on goodix_ts_berlin driver.
*/
#include <asm/unaligned.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include <linux/input.h>
#include "goodix_berlin.h"
#define GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN 1
#define GOODIX_BERLIN_REGISTER_WIDTH 4
#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN 3
#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
GOODIX_BERLIN_REGISTER_WIDTH + \
GOODIX_BERLIN_SPI_READ_DUMMY_LEN)
#define GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
GOODIX_BERLIN_REGISTER_WIDTH)
#define GOODIX_BERLIN_SPI_WRITE_FLAG 0xF0
#define GOODIX_BERLIN_SPI_READ_FLAG 0xF1
static int goodix_berlin_spi_read(void *context, const void *reg_buf,
size_t reg_size, void *val_buf,
size_t val_size)
{
struct spi_device *spi = context;
struct spi_transfer xfers;
struct spi_message spi_msg;
const u32 *reg = reg_buf; /* reg is stored as native u32 at start of buffer */
u8 *buf;
int error;
if (reg_size != GOODIX_BERLIN_REGISTER_WIDTH)
return -EINVAL;
buf = kzalloc(GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
spi_message_init(&spi_msg);
memset(&xfers, 0, sizeof(xfers));
/* buffer format: 0xF1 + addr(4bytes) + dummy(3bytes) + data */
buf[0] = GOODIX_BERLIN_SPI_READ_FLAG;
put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN);
memset(buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + GOODIX_BERLIN_REGISTER_WIDTH,
0xff, GOODIX_BERLIN_SPI_READ_DUMMY_LEN);
xfers.tx_buf = buf;
xfers.rx_buf = buf;
xfers.len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size;
xfers.cs_change = 0;
spi_message_add_tail(&xfers, &spi_msg);
error = spi_sync(spi, &spi_msg);
if (error < 0)
dev_err(&spi->dev, "spi transfer error, %d", error);
else
memcpy(val_buf, buf + GOODIX_BERLIN_SPI_READ_PREFIX_LEN, val_size);
kfree(buf);
return error;
}
static int goodix_berlin_spi_write(void *context, const void *data,
size_t count)
{
unsigned int len = count - GOODIX_BERLIN_REGISTER_WIDTH;
struct spi_device *spi = context;
struct spi_transfer xfers;
struct spi_message spi_msg;
const u32 *reg = data; /* reg is stored as native u32 at start of buffer */
u8 *buf;
int error;
buf = kzalloc(GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN + len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
spi_message_init(&spi_msg);
memset(&xfers, 0, sizeof(xfers));
buf[0] = GOODIX_BERLIN_SPI_WRITE_FLAG;
put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN);
memcpy(buf + GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN,
data + GOODIX_BERLIN_REGISTER_WIDTH, len);
xfers.tx_buf = buf;
xfers.len = GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN + len;
xfers.cs_change = 0;
spi_message_add_tail(&xfers, &spi_msg);
error = spi_sync(spi, &spi_msg);
if (error < 0)
dev_err(&spi->dev, "spi transfer error, %d", error);
kfree(buf);
return error;
}
static const struct regmap_config goodix_berlin_spi_regmap_conf = {
.reg_bits = 32,
.val_bits = 8,
.read = goodix_berlin_spi_read,
.write = goodix_berlin_spi_write,
};
/* vendor & product left unassigned here, should probably be updated from fw info */
static const struct input_id goodix_berlin_spi_input_id = {
.bustype = BUS_SPI,
};
static int goodix_berlin_spi_probe(struct spi_device *spi)
{
struct regmap_config regmap_config;
struct regmap *regmap;
size_t max_size;
int error = 0;
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
error = spi_setup(spi);
if (error)
return error;
max_size = spi_max_transfer_size(spi);
regmap_config = goodix_berlin_spi_regmap_conf;
regmap_config.max_raw_read = max_size - GOODIX_BERLIN_SPI_READ_PREFIX_LEN;
regmap_config.max_raw_write = max_size - GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN;
regmap = devm_regmap_init(&spi->dev, NULL, spi, &regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
error = goodix_berlin_probe(&spi->dev, spi->irq,
&goodix_berlin_spi_input_id, regmap);
if (error)
return error;
return 0;
}
static const struct spi_device_id goodix_berlin_spi_ids[] = {
{ "gt9916" },
{ },
};
MODULE_DEVICE_TABLE(spi, goodix_berlin_spi_ids);
static const struct of_device_id goodix_berlin_spi_of_match[] = {
{ .compatible = "goodix,gt9916", },
{ }
};
MODULE_DEVICE_TABLE(of, goodix_berlin_spi_of_match);
static struct spi_driver goodix_berlin_spi_driver = {
.driver = {
.name = "goodix-berlin-spi",
.of_match_table = goodix_berlin_spi_of_match,
.pm = pm_sleep_ptr(&goodix_berlin_pm_ops),
},
.probe = goodix_berlin_spi_probe,
.id_table = goodix_berlin_spi_ids,
};
module_spi_driver(goodix_berlin_spi_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Goodix Berlin SPI Touchscreen driver");
MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
#include <linux/bitfield.h>
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/i2c.h> #include <linux/i2c.h>
...@@ -11,9 +12,15 @@ ...@@ -11,9 +12,15 @@
#include <linux/property.h> #include <linux/property.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#define IST3032C_WHOAMI 0x32c
#define IST3038B_REG_STATUS 0x20
#define IST3038B_REG_CHIPID 0x30
#define IST3038B_WHOAMI 0x30380b
#define IST3038C_HIB_ACCESS (0x800B << 16) #define IST3038C_HIB_ACCESS (0x800B << 16)
#define IST3038C_DIRECT_ACCESS BIT(31) #define IST3038C_DIRECT_ACCESS BIT(31)
#define IST3038C_REG_CHIPID 0x40001000 #define IST3038C_REG_CHIPID (0x40001000 | IST3038C_DIRECT_ACCESS)
#define IST3038C_REG_HIB_BASE 0x30000100 #define IST3038C_REG_HIB_BASE 0x30000100
#define IST3038C_REG_TOUCH_STATUS (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS) #define IST3038C_REG_TOUCH_STATUS (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS)
#define IST3038C_REG_TOUCH_COORD (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS | 0x8) #define IST3038C_REG_TOUCH_COORD (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS | 0x8)
...@@ -23,19 +30,29 @@ ...@@ -23,19 +30,29 @@
#define IST3038C_I2C_RETRY_COUNT 3 #define IST3038C_I2C_RETRY_COUNT 3
#define IST3038C_MAX_FINGER_NUM 10 #define IST3038C_MAX_FINGER_NUM 10
#define IST3038C_X_MASK GENMASK(23, 12) #define IST3038C_X_MASK GENMASK(23, 12)
#define IST3038C_X_SHIFT 12
#define IST3038C_Y_MASK GENMASK(11, 0) #define IST3038C_Y_MASK GENMASK(11, 0)
#define IST3038C_AREA_MASK GENMASK(27, 24) #define IST3038C_AREA_MASK GENMASK(27, 24)
#define IST3038C_AREA_SHIFT 24
#define IST3038C_FINGER_COUNT_MASK GENMASK(15, 12) #define IST3038C_FINGER_COUNT_MASK GENMASK(15, 12)
#define IST3038C_FINGER_COUNT_SHIFT 12
#define IST3038C_FINGER_STATUS_MASK GENMASK(9, 0) #define IST3038C_FINGER_STATUS_MASK GENMASK(9, 0)
#define IST3032C_KEY_STATUS_MASK GENMASK(20, 16)
struct imagis_properties {
unsigned int interrupt_msg_cmd;
unsigned int touch_coord_cmd;
unsigned int whoami_cmd;
unsigned int whoami_val;
bool protocol_b;
bool touch_keys_supported;
};
struct imagis_ts { struct imagis_ts {
struct i2c_client *client; struct i2c_client *client;
const struct imagis_properties *tdata;
struct input_dev *input_dev; struct input_dev *input_dev;
struct touchscreen_properties prop; struct touchscreen_properties prop;
struct regulator_bulk_data supplies[2]; struct regulator_bulk_data supplies[2];
u32 keycodes[5];
int num_keycodes;
}; };
static int imagis_i2c_read_reg(struct imagis_ts *ts, static int imagis_i2c_read_reg(struct imagis_ts *ts,
...@@ -80,20 +97,18 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id) ...@@ -80,20 +97,18 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id)
{ {
struct imagis_ts *ts = dev_id; struct imagis_ts *ts = dev_id;
u32 intr_message, finger_status; u32 intr_message, finger_status;
unsigned int finger_count, finger_pressed; unsigned int finger_count, finger_pressed, key_pressed;
int i; int i;
int error; int error;
error = imagis_i2c_read_reg(ts, IST3038C_REG_INTR_MESSAGE, error = imagis_i2c_read_reg(ts, ts->tdata->interrupt_msg_cmd, &intr_message);
&intr_message);
if (error) { if (error) {
dev_err(&ts->client->dev, dev_err(&ts->client->dev,
"failed to read the interrupt message: %d\n", error); "failed to read the interrupt message: %d\n", error);
goto out; goto out;
} }
finger_count = (intr_message & IST3038C_FINGER_COUNT_MASK) >> finger_count = FIELD_GET(IST3038C_FINGER_COUNT_MASK, intr_message);
IST3038C_FINGER_COUNT_SHIFT;
if (finger_count > IST3038C_MAX_FINGER_NUM) { if (finger_count > IST3038C_MAX_FINGER_NUM) {
dev_err(&ts->client->dev, dev_err(&ts->client->dev,
"finger count %d is more than maximum supported\n", "finger count %d is more than maximum supported\n",
...@@ -101,12 +116,16 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id) ...@@ -101,12 +116,16 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id)
goto out; goto out;
} }
finger_pressed = intr_message & IST3038C_FINGER_STATUS_MASK; finger_pressed = FIELD_GET(IST3038C_FINGER_STATUS_MASK, intr_message);
for (i = 0; i < finger_count; i++) { for (i = 0; i < finger_count; i++) {
error = imagis_i2c_read_reg(ts, if (ts->tdata->protocol_b)
IST3038C_REG_TOUCH_COORD + (i * 4), error = imagis_i2c_read_reg(ts,
&finger_status); ts->tdata->touch_coord_cmd, &finger_status);
else
error = imagis_i2c_read_reg(ts,
ts->tdata->touch_coord_cmd + (i * 4),
&finger_status);
if (error) { if (error) {
dev_err(&ts->client->dev, dev_err(&ts->client->dev,
"failed to read coordinates for finger %d: %d\n", "failed to read coordinates for finger %d: %d\n",
...@@ -118,14 +137,19 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id) ...@@ -118,14 +137,19 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id)
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
finger_pressed & BIT(i)); finger_pressed & BIT(i));
touchscreen_report_pos(ts->input_dev, &ts->prop, touchscreen_report_pos(ts->input_dev, &ts->prop,
(finger_status & IST3038C_X_MASK) >> FIELD_GET(IST3038C_X_MASK, finger_status),
IST3038C_X_SHIFT, FIELD_GET(IST3038C_Y_MASK, finger_status),
finger_status & IST3038C_Y_MASK, 1); true);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
(finger_status & IST3038C_AREA_MASK) >> FIELD_GET(IST3038C_AREA_MASK, finger_status));
IST3038C_AREA_SHIFT);
} }
key_pressed = FIELD_GET(IST3032C_KEY_STATUS_MASK, intr_message);
for (int i = 0; i < ts->num_keycodes; i++)
input_report_key(ts->input_dev, ts->keycodes[i],
key_pressed & BIT(i));
input_mt_sync_frame(ts->input_dev); input_mt_sync_frame(ts->input_dev);
input_sync(ts->input_dev); input_sync(ts->input_dev);
...@@ -210,7 +234,24 @@ static int imagis_init_input_dev(struct imagis_ts *ts) ...@@ -210,7 +234,24 @@ static int imagis_init_input_dev(struct imagis_ts *ts)
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X); input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y); input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 16, 0, 0);
if (ts->tdata->touch_keys_supported) {
ts->num_keycodes = of_property_read_variable_u32_array(
ts->client->dev.of_node, "linux,keycodes",
ts->keycodes, 0, ARRAY_SIZE(ts->keycodes));
if (ts->num_keycodes <= 0) {
ts->keycodes[0] = KEY_APPSELECT;
ts->keycodes[1] = KEY_BACK;
ts->num_keycodes = 2;
}
input_dev->keycodemax = ts->num_keycodes;
input_dev->keycodesize = sizeof(ts->keycodes[0]);
input_dev->keycode = ts->keycodes;
}
for (int i = 0; i < ts->num_keycodes; i++)
input_set_capability(input_dev, EV_KEY, ts->keycodes[i]);
touchscreen_parse_properties(input_dev, true, &ts->prop); touchscreen_parse_properties(input_dev, true, &ts->prop);
if (!ts->prop.max_x || !ts->prop.max_y) { if (!ts->prop.max_x || !ts->prop.max_y) {
...@@ -261,6 +302,12 @@ static int imagis_probe(struct i2c_client *i2c) ...@@ -261,6 +302,12 @@ static int imagis_probe(struct i2c_client *i2c)
ts->client = i2c; ts->client = i2c;
ts->tdata = device_get_match_data(dev);
if (!ts->tdata) {
dev_err(dev, "missing chip data\n");
return -EINVAL;
}
error = imagis_init_regulators(ts); error = imagis_init_regulators(ts);
if (error) { if (error) {
dev_err(dev, "regulator init error: %d\n", error); dev_err(dev, "regulator init error: %d\n", error);
...@@ -279,15 +326,13 @@ static int imagis_probe(struct i2c_client *i2c) ...@@ -279,15 +326,13 @@ static int imagis_probe(struct i2c_client *i2c)
return error; return error;
} }
error = imagis_i2c_read_reg(ts, error = imagis_i2c_read_reg(ts, ts->tdata->whoami_cmd, &chip_id);
IST3038C_REG_CHIPID | IST3038C_DIRECT_ACCESS,
&chip_id);
if (error) { if (error) {
dev_err(dev, "chip ID read failure: %d\n", error); dev_err(dev, "chip ID read failure: %d\n", error);
return error; return error;
} }
if (chip_id != IST3038C_WHOAMI) { if (chip_id != ts->tdata->whoami_val) {
dev_err(dev, "unknown chip ID: 0x%x\n", chip_id); dev_err(dev, "unknown chip ID: 0x%x\n", chip_id);
return -EINVAL; return -EINVAL;
} }
...@@ -343,9 +388,34 @@ static int imagis_resume(struct device *dev) ...@@ -343,9 +388,34 @@ static int imagis_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume); static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume);
static const struct imagis_properties imagis_3032c_data = {
.interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE,
.touch_coord_cmd = IST3038C_REG_TOUCH_COORD,
.whoami_cmd = IST3038C_REG_CHIPID,
.whoami_val = IST3032C_WHOAMI,
.touch_keys_supported = true,
};
static const struct imagis_properties imagis_3038b_data = {
.interrupt_msg_cmd = IST3038B_REG_STATUS,
.touch_coord_cmd = IST3038B_REG_STATUS,
.whoami_cmd = IST3038B_REG_CHIPID,
.whoami_val = IST3038B_WHOAMI,
.protocol_b = true,
};
static const struct imagis_properties imagis_3038c_data = {
.interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE,
.touch_coord_cmd = IST3038C_REG_TOUCH_COORD,
.whoami_cmd = IST3038C_REG_CHIPID,
.whoami_val = IST3038C_WHOAMI,
};
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id imagis_of_match[] = { static const struct of_device_id imagis_of_match[] = {
{ .compatible = "imagis,ist3038c", }, { .compatible = "imagis,ist3032c", .data = &imagis_3032c_data },
{ .compatible = "imagis,ist3038b", .data = &imagis_3038b_data },
{ .compatible = "imagis,ist3038c", .data = &imagis_3038c_data },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, imagis_of_match); MODULE_DEVICE_TABLE(of, imagis_of_match);
......
...@@ -157,7 +157,6 @@ static void titsc_step_config(struct titsc *ts_dev) ...@@ -157,7 +157,6 @@ static void titsc_step_config(struct titsc *ts_dev)
n++ == 0 ? STEPCONFIG_OPENDLY : 0); n++ == 0 ? STEPCONFIG_OPENDLY : 0);
} }
config = 0;
config = STEPCONFIG_MODE_HWSYNC | config = STEPCONFIG_MODE_HWSYNC |
STEPCONFIG_AVG_16 | ts_dev->bit_yn | STEPCONFIG_AVG_16 | ts_dev->bit_yn |
STEPCONFIG_INM_ADCREFM; STEPCONFIG_INM_ADCREFM;
......
...@@ -514,7 +514,7 @@ void input_enable_softrepeat(struct input_dev *dev, int delay, int period); ...@@ -514,7 +514,7 @@ void input_enable_softrepeat(struct input_dev *dev, int delay, int period);
bool input_device_enabled(struct input_dev *dev); bool input_device_enabled(struct input_dev *dev);
extern struct class input_class; extern const struct class input_class;
/** /**
* struct ff_device - force-feedback part of an input device * struct ff_device - force-feedback part of an input device
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.com>
*/
struct navpoint_platform_data {
int port; /* PXA SSP port for pxa_ssp_request() */
};
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <uapi/linux/serio.h> #include <uapi/linux/serio.h>
extern struct bus_type serio_bus; extern const struct bus_type serio_bus;
struct serio { struct serio {
void *port_data; void *port_data;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment