mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
Input updates for v6.15-rc0
- a brand new driver for touchpads and touchbars in newer Apple devices - support for Berlin-A series in goodix-berlin touchscreen driver - improvements to matrix_keypad driver to better handle GPIOs toggling - assorted small cleanups in other input drivers. -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQST2eWILY88ieB2DOtAj56VGEWXnAUCZ/DJvwAKCRBAj56VGEWX nIvGAQC9nGVCLQX7xO7saMfx5+4/jhkXgPTeDtRs59vNKIoEFAEAgW9DUKShtESV WQlwkyzoRbAjC8suc2sc+bs4fJ60BQ0= =xlqq -----END PGP SIGNATURE----- Merge tag 'input-for-v6.15-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input Pull input updates from Dmitry Torokhov: - a brand new driver for touchpads and touchbars in newer Apple devices - support for Berlin-A series in goodix-berlin touchscreen driver - improvements to matrix_keypad driver to better handle GPIOs toggling - assorted small cleanups in other input drivers * tag 'input-for-v6.15-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: Input: goodix_berlin - add support for Berlin-A series dt-bindings: input: goodix,gt9916: Document gt9897 compatible dt-bindings: input: matrix_keypad - add wakeup-source property dt-bindings: input: matrix_keypad - add missing property Input: pm8941-pwrkey - fix dev_dbg() output in pm8941_pwrkey_irq() Input: synaptics - hide unused smbus_pnp_ids[] array Input: apple_z2 - fix potential confusion in Kconfig Input: matrix_keypad - use fsleep for delays after activating columns Input: matrix_keypad - add settle time after enabling all columns dt-bindings: input: matrix_keypad: add settle time after enabling all columns dt-bindings: input: matrix_keypad: convert to YAML dt-bindings: input: Correct indentation and style in DTS example MAINTAINERS: Add entries for Apple Z2 touchscreen driver Input: apple_z2 - add a driver for Apple Z2 touchscreens dt-bindings: input: touchscreen: Add Z2 controller Input: Switch to use hrtimer_setup() Input: drop vb2_ops_wait_prepare/finish
This commit is contained in:
commit
56f944529e
@ -1,49 +0,0 @@
|
||||
* GPIO driven matrix keypad device tree bindings
|
||||
|
||||
GPIO driven matrix keypad is used to interface a SoC with a matrix keypad.
|
||||
The matrix keypad supports multiple row and column lines, a key can be
|
||||
placed at each intersection of a unique row and a unique column. The matrix
|
||||
keypad can sense a key-press and key-release by means of GPIO lines and
|
||||
report the event using GPIO interrupts to the cpu.
|
||||
|
||||
Required Properties:
|
||||
- compatible: Should be "gpio-matrix-keypad"
|
||||
- row-gpios: List of gpios used as row lines. The gpio specifier
|
||||
for this property depends on the gpio controller to
|
||||
which these row lines are connected.
|
||||
- col-gpios: List of gpios used as column lines. The gpio specifier
|
||||
for this property depends on the gpio controller to
|
||||
which these column lines are connected.
|
||||
- linux,keymap: The definition can be found at
|
||||
bindings/input/matrix-keymap.txt
|
||||
|
||||
Optional Properties:
|
||||
- linux,no-autorepeat: do no enable autorepeat feature.
|
||||
- wakeup-source: use any event on keypad as wakeup event.
|
||||
(Legacy property supported: "linux,wakeup")
|
||||
- debounce-delay-ms: debounce interval in milliseconds
|
||||
- col-scan-delay-us: delay, measured in microseconds, that is needed
|
||||
before we can scan keypad after activating column gpio
|
||||
- drive-inactive-cols: drive inactive columns during scan,
|
||||
default is to turn inactive columns into inputs.
|
||||
|
||||
Example:
|
||||
matrix-keypad {
|
||||
compatible = "gpio-matrix-keypad";
|
||||
debounce-delay-ms = <5>;
|
||||
col-scan-delay-us = <2>;
|
||||
|
||||
row-gpios = <&gpio2 25 0
|
||||
&gpio2 26 0
|
||||
&gpio2 27 0>;
|
||||
|
||||
col-gpios = <&gpio2 21 0
|
||||
&gpio2 22 0>;
|
||||
|
||||
linux,keymap = <0x0000008B
|
||||
0x0100009E
|
||||
0x02000069
|
||||
0x0001006A
|
||||
0x0101001C
|
||||
0x0201006C>;
|
||||
};
|
103
Documentation/devicetree/bindings/input/gpio-matrix-keypad.yaml
Normal file
103
Documentation/devicetree/bindings/input/gpio-matrix-keypad.yaml
Normal file
@ -0,0 +1,103 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
|
||||
$id: http://devicetree.org/schemas/input/gpio-matrix-keypad.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: GPIO matrix keypad
|
||||
|
||||
maintainers:
|
||||
- Marek Vasut <marek.vasut@gmail.com>
|
||||
|
||||
description:
|
||||
GPIO driven matrix keypad is used to interface a SoC with a matrix keypad.
|
||||
The matrix keypad supports multiple row and column lines, a key can be
|
||||
placed at each intersection of a unique row and a unique column. The matrix
|
||||
keypad can sense a key-press and key-release by means of GPIO lines and
|
||||
report the event using GPIO interrupts to the cpu.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/input/matrix-keymap.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: gpio-matrix-keypad
|
||||
|
||||
row-gpios:
|
||||
description:
|
||||
List of GPIOs used as row lines. The gpio specifier for this property
|
||||
depends on the gpio controller to which these row lines are connected.
|
||||
|
||||
col-gpios:
|
||||
description:
|
||||
List of GPIOs used as column lines. The gpio specifier for this property
|
||||
depends on the gpio controller to which these column lines are connected.
|
||||
|
||||
linux,keymap: true
|
||||
|
||||
linux,no-autorepeat:
|
||||
type: boolean
|
||||
description: Do not enable autorepeat feature.
|
||||
|
||||
gpio-activelow:
|
||||
type: boolean
|
||||
description:
|
||||
Force GPIO polarity to active low.
|
||||
In the absence of this property GPIOs are treated as active high.
|
||||
|
||||
debounce-delay-ms:
|
||||
description: Debounce interval in milliseconds.
|
||||
default: 0
|
||||
|
||||
col-scan-delay-us:
|
||||
description:
|
||||
Delay, measured in microseconds, that is needed
|
||||
before we can scan keypad after activating column gpio.
|
||||
default: 0
|
||||
|
||||
all-cols-on-delay-us:
|
||||
description:
|
||||
Delay, measured in microseconds, that is needed
|
||||
after activating all column gpios.
|
||||
default: 0
|
||||
|
||||
drive-inactive-cols:
|
||||
type: boolean
|
||||
description:
|
||||
Drive inactive columns during scan,
|
||||
default is to turn inactive columns into inputs.
|
||||
|
||||
wakeup-source: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- row-gpios
|
||||
- col-gpios
|
||||
- linux,keymap
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
matrix-keypad {
|
||||
compatible = "gpio-matrix-keypad";
|
||||
debounce-delay-ms = <5>;
|
||||
col-scan-delay-us = <2>;
|
||||
|
||||
row-gpios = <&gpio2 25 0
|
||||
&gpio2 26 0
|
||||
&gpio2 27 0>;
|
||||
|
||||
col-gpios = <&gpio2 21 0
|
||||
&gpio2 22 0>;
|
||||
|
||||
linux,keymap = <0x0000008B
|
||||
0x0100009E
|
||||
0x02000069
|
||||
0x0001006A
|
||||
0x0101001C
|
||||
0x0201006C>;
|
||||
|
||||
wakeup-source;
|
||||
};
|
@ -62,28 +62,28 @@ unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
pmic {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
pmic {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
keypad@148 {
|
||||
compatible = "qcom,pm8921-keypad";
|
||||
reg = <0x148>;
|
||||
interrupt-parent = <&pmicintc>;
|
||||
interrupts = <74 IRQ_TYPE_EDGE_RISING>, <75 IRQ_TYPE_EDGE_RISING>;
|
||||
linux,keymap = <
|
||||
MATRIX_KEY(0, 0, KEY_VOLUMEUP)
|
||||
MATRIX_KEY(0, 1, KEY_VOLUMEDOWN)
|
||||
MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS)
|
||||
MATRIX_KEY(0, 3, KEY_CAMERA)
|
||||
>;
|
||||
keypad,num-rows = <1>;
|
||||
keypad,num-columns = <5>;
|
||||
debounce = <15>;
|
||||
scan-delay = <32>;
|
||||
row-hold = <91500>;
|
||||
};
|
||||
};
|
||||
keypad@148 {
|
||||
compatible = "qcom,pm8921-keypad";
|
||||
reg = <0x148>;
|
||||
interrupt-parent = <&pmicintc>;
|
||||
interrupts = <74 IRQ_TYPE_EDGE_RISING>, <75 IRQ_TYPE_EDGE_RISING>;
|
||||
linux,keymap = <
|
||||
MATRIX_KEY(0, 0, KEY_VOLUMEUP)
|
||||
MATRIX_KEY(0, 1, KEY_VOLUMEDOWN)
|
||||
MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS)
|
||||
MATRIX_KEY(0, 3, KEY_CAMERA)
|
||||
>;
|
||||
keypad,num-rows = <1>;
|
||||
keypad,num-columns = <5>;
|
||||
debounce = <15>;
|
||||
scan-delay = <32>;
|
||||
row-hold = <91500>;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
@ -52,24 +52,24 @@ unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
ssbi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
ssbi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pmic@0 {
|
||||
reg = <0x0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
pmic@0 {
|
||||
reg = <0x0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pwrkey@1c {
|
||||
compatible = "qcom,pm8921-pwrkey";
|
||||
reg = <0x1c>;
|
||||
interrupt-parent = <&pmicint>;
|
||||
interrupts = <50 IRQ_TYPE_EDGE_RISING>, <51 IRQ_TYPE_EDGE_RISING>;
|
||||
debounce = <15625>;
|
||||
pull-up;
|
||||
};
|
||||
};
|
||||
};
|
||||
pwrkey@1c {
|
||||
compatible = "qcom,pm8921-pwrkey";
|
||||
reg = <0x1c>;
|
||||
interrupt-parent = <&pmicint>;
|
||||
interrupts = <50 IRQ_TYPE_EDGE_RISING>, <51 IRQ_TYPE_EDGE_RISING>;
|
||||
debounce = <15625>;
|
||||
pull-up;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
@ -0,0 +1,70 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/apple,z2-multitouch.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Apple touchscreens attached using the Z2 protocol
|
||||
|
||||
maintainers:
|
||||
- Sasha Finkelstein <fnkl.kernel@gmail.com>
|
||||
|
||||
description: A series of touschscreen controllers used in Apple products
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- apple,j293-touchbar
|
||||
- apple,j493-touchbar
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
firmware-name:
|
||||
maxItems: 1
|
||||
|
||||
apple,z2-cal-blob:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
maxItems: 4096
|
||||
description:
|
||||
Calibration blob supplied by the bootloader
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- interrupts
|
||||
- reset-gpios
|
||||
- firmware-name
|
||||
- touchscreen-size-x
|
||||
- touchscreen-size-y
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
touchscreen@0 {
|
||||
compatible = "apple,j293-touchbar";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <11500000>;
|
||||
reset-gpios = <&pinctrl_ap 139 GPIO_ACTIVE_LOW>;
|
||||
interrupts-extended = <&pinctrl_ap 194 IRQ_TYPE_EDGE_FALLING>;
|
||||
firmware-name = "apple/dfrmtfw-j293.bin";
|
||||
touchscreen-size-x = <23045>;
|
||||
touchscreen-size-y = <640>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -19,6 +19,7 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- goodix,gt9897
|
||||
- goodix,gt9916
|
||||
|
||||
reg:
|
||||
|
@ -164,20 +164,20 @@ examples:
|
||||
#size-cells = <0>;
|
||||
|
||||
touchscreen@0 {
|
||||
compatible = "ti,tsc2046";
|
||||
reg = <0>; /* CS0 */
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <8 0>; /* BOOT6 / GPIO 8 */
|
||||
pendown-gpio = <&gpio1 8 0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
vcc-supply = <®_vcc3>;
|
||||
wakeup-source;
|
||||
compatible = "ti,tsc2046";
|
||||
reg = <0>; /* CS0 */
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <8 0>; /* BOOT6 / GPIO 8 */
|
||||
pendown-gpio = <&gpio1 8 0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
vcc-supply = <®_vcc3>;
|
||||
wakeup-source;
|
||||
|
||||
ti,pressure-max = /bits/ 16 <255>;
|
||||
ti,x-max = /bits/ 16 <8000>;
|
||||
ti,x-min = /bits/ 16 <0>;
|
||||
ti,x-plate-ohms = /bits/ 16 <40>;
|
||||
ti,y-max = /bits/ 16 <4800>;
|
||||
ti,y-min = /bits/ 16 <0>;
|
||||
};
|
||||
ti,pressure-max = /bits/ 16 <255>;
|
||||
ti,x-max = /bits/ 16 <8000>;
|
||||
ti,x-min = /bits/ 16 <0>;
|
||||
ti,x-plate-ohms = /bits/ 16 <40>;
|
||||
ti,y-max = /bits/ 16 <4800>;
|
||||
ti,y-min = /bits/ 16 <0>;
|
||||
};
|
||||
};
|
||||
|
@ -23,7 +23,7 @@ List of legacy properties and respective binding document
|
||||
|
||||
1. "gpio-key,wakeup" Documentation/devicetree/bindings/input/gpio-keys{,-polled}.txt
|
||||
2. "has-tpo" Documentation/devicetree/bindings/rtc/rtc-opal.txt
|
||||
3. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt
|
||||
3. "linux,wakeup" Documentation/devicetree/bindings/input/gpio-matrix-keypad.yaml
|
||||
Documentation/devicetree/bindings/mfd/tc3589x.txt
|
||||
Documentation/devicetree/bindings/input/touchscreen/ti,ads7843.yaml
|
||||
4. "linux,keypad-wakeup" Documentation/devicetree/bindings/input/qcom,pm8921-keypad.yaml
|
||||
|
@ -2268,6 +2268,7 @@ F: Documentation/devicetree/bindings/clock/apple,nco.yaml
|
||||
F: Documentation/devicetree/bindings/cpufreq/apple,cluster-cpufreq.yaml
|
||||
F: Documentation/devicetree/bindings/dma/apple,admac.yaml
|
||||
F: Documentation/devicetree/bindings/i2c/apple,i2c.yaml
|
||||
F: Documentation/devicetree/bindings/input/touchscreen/apple,z2-multitouch.yaml
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/apple,*
|
||||
F: Documentation/devicetree/bindings/iommu/apple,dart.yaml
|
||||
F: Documentation/devicetree/bindings/iommu/apple,sart.yaml
|
||||
@ -2290,6 +2291,7 @@ F: drivers/dma/apple-admac.c
|
||||
F: drivers/pmdomain/apple/
|
||||
F: drivers/i2c/busses/i2c-pasemi-core.c
|
||||
F: drivers/i2c/busses/i2c-pasemi-platform.c
|
||||
F: drivers/input/touchscreen/apple_z2.c
|
||||
F: drivers/iommu/apple-dart.c
|
||||
F: drivers/iommu/io-pgtable-dart.c
|
||||
F: drivers/irqchip/irq-apple-aic.c
|
||||
|
@ -232,8 +232,7 @@ static void walkera0701_attach(struct parport *pp)
|
||||
goto err_unregister_device;
|
||||
}
|
||||
|
||||
hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
w->timer.function = timer_handler;
|
||||
hrtimer_setup(&w->timer, timer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
|
||||
w->input_dev = input_allocate_device();
|
||||
if (!w->input_dev) {
|
||||
|
@ -590,9 +590,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
|
||||
INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
|
||||
|
||||
hrtimer_init(&bdata->debounce_timer,
|
||||
CLOCK_REALTIME, HRTIMER_MODE_REL);
|
||||
bdata->debounce_timer.function = gpio_keys_debounce_timer;
|
||||
hrtimer_setup(&bdata->debounce_timer, gpio_keys_debounce_timer, CLOCK_REALTIME,
|
||||
HRTIMER_MODE_REL);
|
||||
|
||||
isr = gpio_keys_gpio_isr;
|
||||
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
|
||||
@ -628,9 +627,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
bdata->release_delay = button->debounce_interval;
|
||||
hrtimer_init(&bdata->release_timer,
|
||||
CLOCK_REALTIME, HRTIMER_MODE_REL_HARD);
|
||||
bdata->release_timer.function = gpio_keys_irq_timer;
|
||||
hrtimer_setup(&bdata->release_timer, gpio_keys_irq_timer, CLOCK_REALTIME,
|
||||
HRTIMER_MODE_REL_HARD);
|
||||
|
||||
isr = gpio_keys_irq_isr;
|
||||
irqflags = 0;
|
||||
|
@ -26,6 +26,7 @@ struct matrix_keypad {
|
||||
unsigned int row_shift;
|
||||
|
||||
unsigned int col_scan_delay_us;
|
||||
unsigned int all_cols_on_delay_us;
|
||||
/* key debounce interval in milli-second */
|
||||
unsigned int debounce_ms;
|
||||
bool drive_inactive_cols;
|
||||
@ -68,7 +69,7 @@ static void activate_col(struct matrix_keypad *keypad, int col, bool on)
|
||||
__activate_col(keypad, col, on);
|
||||
|
||||
if (on && keypad->col_scan_delay_us)
|
||||
udelay(keypad->col_scan_delay_us);
|
||||
fsleep(keypad->col_scan_delay_us);
|
||||
}
|
||||
|
||||
static void activate_all_cols(struct matrix_keypad *keypad, bool on)
|
||||
@ -77,6 +78,9 @@ static void activate_all_cols(struct matrix_keypad *keypad, bool on)
|
||||
|
||||
for (col = 0; col < keypad->num_col_gpios; col++)
|
||||
__activate_col(keypad, col, on);
|
||||
|
||||
if (on && keypad->all_cols_on_delay_us)
|
||||
fsleep(keypad->all_cols_on_delay_us);
|
||||
}
|
||||
|
||||
static bool row_asserted(struct matrix_keypad *keypad, int row)
|
||||
@ -392,6 +396,8 @@ static int matrix_keypad_probe(struct platform_device *pdev)
|
||||
&keypad->debounce_ms);
|
||||
device_property_read_u32(&pdev->dev, "col-scan-delay-us",
|
||||
&keypad->col_scan_delay_us);
|
||||
device_property_read_u32(&pdev->dev, "all-cols-on-delay-us",
|
||||
&keypad->all_cols_on_delay_us);
|
||||
|
||||
err = matrix_keypad_init_gpio(pdev, keypad);
|
||||
if (err)
|
||||
|
@ -154,8 +154,8 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
|
||||
if (pwrkey->sw_debounce_time_us) {
|
||||
if (ktime_before(ktime_get(), pwrkey->sw_debounce_end_time)) {
|
||||
dev_dbg(pwrkey->dev,
|
||||
"ignoring key event received before debounce end %llu us\n",
|
||||
pwrkey->sw_debounce_end_time);
|
||||
"ignoring key event received before debounce end %lld us\n",
|
||||
ktime_to_us(pwrkey->sw_debounce_end_time));
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
@ -161,6 +161,7 @@ static const char * const topbuttonpad_pnp_ids[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS
|
||||
static const char * const smbus_pnp_ids[] = {
|
||||
/* all of the topbuttonpad_pnp_ids are valid, we just add some extras */
|
||||
"LEN0048", /* X1 Carbon 3 */
|
||||
@ -196,6 +197,7 @@ static const char * const smbus_pnp_ids[] = {
|
||||
"SYN3257", /* HP Envy 13-ad105ng */
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
static const char * const forcepad_pnp_ids[] = {
|
||||
"SYN300D",
|
||||
|
@ -372,8 +372,6 @@ static const struct vb2_ops rmi_f54_queue_ops = {
|
||||
.queue_setup = rmi_f54_queue_setup,
|
||||
.buf_queue = rmi_f54_buffer_queue,
|
||||
.stop_streaming = rmi_f54_stop_streaming,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
};
|
||||
|
||||
static const struct vb2_queue rmi_f54_queue = {
|
||||
|
@ -103,6 +103,19 @@ config TOUCHSCREEN_ADC
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called resistive-adc-touch.ko.
|
||||
|
||||
config TOUCHSCREEN_APPLE_Z2
|
||||
tristate "Apple Z2 touchscreens"
|
||||
default ARCH_APPLE
|
||||
depends on SPI && (ARCH_APPLE || COMPILE_TEST)
|
||||
help
|
||||
Say Y here if you have an ARM Apple device with
|
||||
a touchscreen or a touchbar.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called apple_z2.
|
||||
|
||||
config TOUCHSCREEN_AR1021_I2C
|
||||
tristate "Microchip AR1020/1021 i2c touchscreen"
|
||||
depends on I2C && OF
|
||||
|
@ -15,6 +15,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ADC) += resistive-adc-touch.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_APPLE_Z2) += apple_z2.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
|
||||
|
477
drivers/input/touchscreen/apple_z2.c
Normal file
477
drivers/input/touchscreen/apple_z2.c
Normal file
@ -0,0 +1,477 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Apple Z2 touchscreen driver
|
||||
*
|
||||
* Copyright (C) The Asahi Linux Contributors
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/input/touchscreen.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/unaligned.h>
|
||||
|
||||
#define APPLE_Z2_NUM_FINGERS_OFFSET 16
|
||||
#define APPLE_Z2_FINGERS_OFFSET 24
|
||||
#define APPLE_Z2_TOUCH_STARTED 3
|
||||
#define APPLE_Z2_TOUCH_MOVED 4
|
||||
#define APPLE_Z2_CMD_READ_INTERRUPT_DATA 0xEB
|
||||
#define APPLE_Z2_HBPP_CMD_BLOB 0x3001
|
||||
#define APPLE_Z2_FW_MAGIC 0x5746325A
|
||||
#define LOAD_COMMAND_INIT_PAYLOAD 0
|
||||
#define LOAD_COMMAND_SEND_BLOB 1
|
||||
#define LOAD_COMMAND_SEND_CALIBRATION 2
|
||||
#define CAL_PROP_NAME "apple,z2-cal-blob"
|
||||
|
||||
struct apple_z2 {
|
||||
struct spi_device *spidev;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct input_dev *input_dev;
|
||||
struct completion boot_irq;
|
||||
bool booted;
|
||||
int index_parity;
|
||||
struct touchscreen_properties props;
|
||||
const char *fw_name;
|
||||
u8 *tx_buf;
|
||||
u8 *rx_buf;
|
||||
};
|
||||
|
||||
struct apple_z2_finger {
|
||||
u8 finger;
|
||||
u8 state;
|
||||
__le16 unknown2;
|
||||
__le16 abs_x;
|
||||
__le16 abs_y;
|
||||
__le16 rel_x;
|
||||
__le16 rel_y;
|
||||
__le16 tool_major;
|
||||
__le16 tool_minor;
|
||||
__le16 orientation;
|
||||
__le16 touch_major;
|
||||
__le16 touch_minor;
|
||||
__le16 unused[2];
|
||||
__le16 pressure;
|
||||
__le16 multi;
|
||||
} __packed;
|
||||
|
||||
struct apple_z2_hbpp_blob_hdr {
|
||||
__le16 cmd;
|
||||
__le16 len;
|
||||
__le32 addr;
|
||||
__le16 checksum;
|
||||
};
|
||||
|
||||
struct apple_z2_fw_hdr {
|
||||
__le32 magic;
|
||||
__le32 version;
|
||||
};
|
||||
|
||||
struct apple_z2_read_interrupt_cmd {
|
||||
u8 cmd;
|
||||
u8 counter;
|
||||
u8 unused[12];
|
||||
__le16 checksum;
|
||||
};
|
||||
|
||||
static void apple_z2_parse_touches(struct apple_z2 *z2,
|
||||
const u8 *msg, size_t msg_len)
|
||||
{
|
||||
int i;
|
||||
int nfingers;
|
||||
int slot;
|
||||
int slot_valid;
|
||||
struct apple_z2_finger *fingers;
|
||||
|
||||
if (msg_len <= APPLE_Z2_NUM_FINGERS_OFFSET)
|
||||
return;
|
||||
nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
|
||||
fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
|
||||
for (i = 0; i < nfingers; i++) {
|
||||
slot = input_mt_get_slot_by_key(z2->input_dev, fingers[i].finger);
|
||||
if (slot < 0) {
|
||||
dev_warn(&z2->spidev->dev, "unable to get slot for finger\n");
|
||||
continue;
|
||||
}
|
||||
slot_valid = fingers[i].state == APPLE_Z2_TOUCH_STARTED ||
|
||||
fingers[i].state == APPLE_Z2_TOUCH_MOVED;
|
||||
input_mt_slot(z2->input_dev, slot);
|
||||
if (!input_mt_report_slot_state(z2->input_dev, MT_TOOL_FINGER, slot_valid))
|
||||
continue;
|
||||
touchscreen_report_pos(z2->input_dev, &z2->props,
|
||||
le16_to_cpu(fingers[i].abs_x),
|
||||
le16_to_cpu(fingers[i].abs_y),
|
||||
true);
|
||||
input_report_abs(z2->input_dev, ABS_MT_WIDTH_MAJOR,
|
||||
le16_to_cpu(fingers[i].tool_major));
|
||||
input_report_abs(z2->input_dev, ABS_MT_WIDTH_MINOR,
|
||||
le16_to_cpu(fingers[i].tool_minor));
|
||||
input_report_abs(z2->input_dev, ABS_MT_ORIENTATION,
|
||||
le16_to_cpu(fingers[i].orientation));
|
||||
input_report_abs(z2->input_dev, ABS_MT_TOUCH_MAJOR,
|
||||
le16_to_cpu(fingers[i].touch_major));
|
||||
input_report_abs(z2->input_dev, ABS_MT_TOUCH_MINOR,
|
||||
le16_to_cpu(fingers[i].touch_minor));
|
||||
}
|
||||
input_mt_sync_frame(z2->input_dev);
|
||||
input_sync(z2->input_dev);
|
||||
}
|
||||
|
||||
static int apple_z2_read_packet(struct apple_z2 *z2)
|
||||
{
|
||||
struct apple_z2_read_interrupt_cmd *len_cmd = (void *)z2->tx_buf;
|
||||
struct spi_transfer xfer;
|
||||
int error;
|
||||
size_t pkt_len;
|
||||
|
||||
memset(&xfer, 0, sizeof(xfer));
|
||||
len_cmd->cmd = APPLE_Z2_CMD_READ_INTERRUPT_DATA;
|
||||
len_cmd->counter = z2->index_parity + 1;
|
||||
len_cmd->checksum =
|
||||
cpu_to_le16(APPLE_Z2_CMD_READ_INTERRUPT_DATA + len_cmd->counter);
|
||||
z2->index_parity = !z2->index_parity;
|
||||
xfer.tx_buf = z2->tx_buf;
|
||||
xfer.rx_buf = z2->rx_buf;
|
||||
xfer.len = sizeof(*len_cmd);
|
||||
|
||||
error = spi_sync_transfer(z2->spidev, &xfer, 1);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc;
|
||||
|
||||
error = spi_read(z2->spidev, z2->rx_buf, pkt_len);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
apple_z2_parse_touches(z2, z2->rx_buf + 5, pkt_len - 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t apple_z2_irq(int irq, void *data)
|
||||
{
|
||||
struct apple_z2 *z2 = data;
|
||||
|
||||
if (unlikely(!z2->booted))
|
||||
complete(&z2->boot_irq);
|
||||
else
|
||||
apple_z2_read_packet(z2);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Build calibration blob, caller is responsible for freeing the blob data. */
|
||||
static const u8 *apple_z2_build_cal_blob(struct apple_z2 *z2,
|
||||
u32 address, size_t *size)
|
||||
{
|
||||
u8 *cal_data;
|
||||
int cal_size;
|
||||
size_t blob_size;
|
||||
u32 checksum;
|
||||
u16 checksum_hdr;
|
||||
int i;
|
||||
struct apple_z2_hbpp_blob_hdr *hdr;
|
||||
int error;
|
||||
|
||||
if (!device_property_present(&z2->spidev->dev, CAL_PROP_NAME))
|
||||
return NULL;
|
||||
|
||||
cal_size = device_property_count_u8(&z2->spidev->dev, CAL_PROP_NAME);
|
||||
if (cal_size < 0)
|
||||
return ERR_PTR(cal_size);
|
||||
|
||||
blob_size = sizeof(struct apple_z2_hbpp_blob_hdr) + cal_size + sizeof(__le32);
|
||||
u8 *blob_data __free(kfree) = kzalloc(blob_size, GFP_KERNEL);
|
||||
if (!blob_data)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
hdr = (struct apple_z2_hbpp_blob_hdr *)blob_data;
|
||||
hdr->cmd = cpu_to_le16(APPLE_Z2_HBPP_CMD_BLOB);
|
||||
hdr->len = cpu_to_le16(round_up(cal_size, 4) / 4);
|
||||
hdr->addr = cpu_to_le32(address);
|
||||
|
||||
checksum_hdr = 0;
|
||||
for (i = 2; i < 8; i++)
|
||||
checksum_hdr += blob_data[i];
|
||||
hdr->checksum = cpu_to_le16(checksum_hdr);
|
||||
|
||||
cal_data = blob_data + sizeof(struct apple_z2_hbpp_blob_hdr);
|
||||
error = device_property_read_u8_array(&z2->spidev->dev, CAL_PROP_NAME,
|
||||
cal_data, cal_size);
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
|
||||
checksum = 0;
|
||||
for (i = 0; i < cal_size; i++)
|
||||
checksum += cal_data[i];
|
||||
put_unaligned_le32(checksum, cal_data + cal_size);
|
||||
|
||||
*size = blob_size;
|
||||
return no_free_ptr(blob_data);
|
||||
}
|
||||
|
||||
static int apple_z2_send_firmware_blob(struct apple_z2 *z2, const u8 *data,
|
||||
u32 size, bool init)
|
||||
{
|
||||
struct spi_message msg;
|
||||
struct spi_transfer blob_xfer, ack_xfer;
|
||||
int error;
|
||||
|
||||
z2->tx_buf[0] = 0x1a;
|
||||
z2->tx_buf[1] = 0xa1;
|
||||
|
||||
spi_message_init(&msg);
|
||||
memset(&blob_xfer, 0, sizeof(blob_xfer));
|
||||
memset(&ack_xfer, 0, sizeof(ack_xfer));
|
||||
|
||||
blob_xfer.tx_buf = data;
|
||||
blob_xfer.len = size;
|
||||
blob_xfer.bits_per_word = init ? 8 : 16;
|
||||
spi_message_add_tail(&blob_xfer, &msg);
|
||||
|
||||
ack_xfer.tx_buf = z2->tx_buf;
|
||||
ack_xfer.len = 2;
|
||||
spi_message_add_tail(&ack_xfer, &msg);
|
||||
|
||||
reinit_completion(&z2->boot_irq);
|
||||
error = spi_sync(z2->spidev, &msg);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Irq only happens sometimes, but the thing boots reliably nonetheless */
|
||||
wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apple_z2_upload_firmware(struct apple_z2 *z2)
|
||||
{
|
||||
const struct apple_z2_fw_hdr *fw_hdr;
|
||||
size_t fw_idx = sizeof(struct apple_z2_fw_hdr);
|
||||
int error;
|
||||
u32 load_cmd;
|
||||
u32 address;
|
||||
bool init;
|
||||
size_t size;
|
||||
|
||||
const struct firmware *fw __free(firmware) = NULL;
|
||||
error = request_firmware(&fw, z2->fw_name, &z2->spidev->dev);
|
||||
if (error) {
|
||||
dev_err(&z2->spidev->dev, "unable to load firmware\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
fw_hdr = (const struct apple_z2_fw_hdr *)fw->data;
|
||||
if (le32_to_cpu(fw_hdr->magic) != APPLE_Z2_FW_MAGIC || le32_to_cpu(fw_hdr->version) != 1) {
|
||||
dev_err(&z2->spidev->dev, "invalid firmware header\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This will interrupt the upload half-way if the file is malformed
|
||||
* As the device has no non-volatile storage to corrupt, and gets reset
|
||||
* on boot anyway, this is fine.
|
||||
*/
|
||||
while (fw_idx < fw->size) {
|
||||
if (fw->size - fw_idx < 8) {
|
||||
dev_err(&z2->spidev->dev, "firmware malformed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
load_cmd = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
|
||||
fw_idx += sizeof(u32);
|
||||
if (load_cmd == LOAD_COMMAND_INIT_PAYLOAD || load_cmd == LOAD_COMMAND_SEND_BLOB) {
|
||||
size = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
|
||||
fw_idx += sizeof(u32);
|
||||
if (fw->size - fw_idx < size) {
|
||||
dev_err(&z2->spidev->dev, "firmware malformed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
init = load_cmd == LOAD_COMMAND_INIT_PAYLOAD;
|
||||
error = apple_z2_send_firmware_blob(z2, fw->data + fw_idx,
|
||||
size, init);
|
||||
if (error)
|
||||
return error;
|
||||
fw_idx += size;
|
||||
} else if (load_cmd == LOAD_COMMAND_SEND_CALIBRATION) {
|
||||
address = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
|
||||
fw_idx += sizeof(u32);
|
||||
|
||||
const u8 *data __free(kfree) =
|
||||
apple_z2_build_cal_blob(z2, address, &size);
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
if (data) {
|
||||
error = apple_z2_send_firmware_blob(z2, data, size, false);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
} else {
|
||||
dev_err(&z2->spidev->dev, "firmware malformed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
fw_idx = round_up(fw_idx, 4);
|
||||
}
|
||||
|
||||
|
||||
z2->booted = true;
|
||||
apple_z2_read_packet(z2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apple_z2_boot(struct apple_z2 *z2)
|
||||
{
|
||||
int error;
|
||||
|
||||
reinit_completion(&z2->boot_irq);
|
||||
enable_irq(z2->spidev->irq);
|
||||
gpiod_set_value(z2->reset_gpio, 0);
|
||||
if (!wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20)))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
error = apple_z2_upload_firmware(z2);
|
||||
if (error) {
|
||||
gpiod_set_value(z2->reset_gpio, 1);
|
||||
disable_irq(z2->spidev->irq);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apple_z2_probe(struct spi_device *spi)
|
||||
{
|
||||
struct device *dev = &spi->dev;
|
||||
struct apple_z2 *z2;
|
||||
int error;
|
||||
|
||||
z2 = devm_kzalloc(dev, sizeof(*z2), GFP_KERNEL);
|
||||
if (!z2)
|
||||
return -ENOMEM;
|
||||
|
||||
z2->tx_buf = devm_kzalloc(dev, sizeof(struct apple_z2_read_interrupt_cmd), GFP_KERNEL);
|
||||
if (!z2->tx_buf)
|
||||
return -ENOMEM;
|
||||
/* 4096 will end up being rounded up to 8192 due to devres header */
|
||||
z2->rx_buf = devm_kzalloc(dev, 4000, GFP_KERNEL);
|
||||
if (!z2->rx_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
z2->spidev = spi;
|
||||
init_completion(&z2->boot_irq);
|
||||
spi_set_drvdata(spi, z2);
|
||||
|
||||
/* Reset the device on boot */
|
||||
z2->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(z2->reset_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(z2->reset_gpio), "unable to get reset\n");
|
||||
|
||||
error = devm_request_threaded_irq(dev, z2->spidev->irq, NULL, apple_z2_irq,
|
||||
IRQF_ONESHOT | IRQF_NO_AUTOEN,
|
||||
"apple-z2-irq", z2);
|
||||
if (error)
|
||||
return dev_err_probe(dev, error, "unable to request irq\n");
|
||||
|
||||
error = device_property_read_string(dev, "firmware-name", &z2->fw_name);
|
||||
if (error)
|
||||
return dev_err_probe(dev, error, "unable to get firmware name\n");
|
||||
|
||||
z2->input_dev = devm_input_allocate_device(dev);
|
||||
if (!z2->input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
z2->input_dev->name = (char *)spi_get_device_id(spi)->driver_data;
|
||||
z2->input_dev->phys = "apple_z2";
|
||||
z2->input_dev->id.bustype = BUS_SPI;
|
||||
|
||||
/* Allocate the axes before setting from DT */
|
||||
input_set_abs_params(z2->input_dev, ABS_MT_POSITION_X, 0, 0, 0, 0);
|
||||
input_set_abs_params(z2->input_dev, ABS_MT_POSITION_Y, 0, 0, 0, 0);
|
||||
touchscreen_parse_properties(z2->input_dev, true, &z2->props);
|
||||
input_abs_set_res(z2->input_dev, ABS_MT_POSITION_X, 100);
|
||||
input_abs_set_res(z2->input_dev, ABS_MT_POSITION_Y, 100);
|
||||
input_set_abs_params(z2->input_dev, ABS_MT_WIDTH_MAJOR, 0, 65535, 0, 0);
|
||||
input_set_abs_params(z2->input_dev, ABS_MT_WIDTH_MINOR, 0, 65535, 0, 0);
|
||||
input_set_abs_params(z2->input_dev, ABS_MT_TOUCH_MAJOR, 0, 65535, 0, 0);
|
||||
input_set_abs_params(z2->input_dev, ABS_MT_TOUCH_MINOR, 0, 65535, 0, 0);
|
||||
input_set_abs_params(z2->input_dev, ABS_MT_ORIENTATION, -32768, 32767, 0, 0);
|
||||
|
||||
error = input_mt_init_slots(z2->input_dev, 256, INPUT_MT_DIRECT);
|
||||
if (error)
|
||||
return dev_err_probe(dev, error, "unable to initialize multitouch slots\n");
|
||||
|
||||
error = input_register_device(z2->input_dev);
|
||||
if (error)
|
||||
return dev_err_probe(dev, error, "unable to register input device\n");
|
||||
|
||||
/* Wait for device reset to finish */
|
||||
usleep_range(5000, 10000);
|
||||
error = apple_z2_boot(z2);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void apple_z2_shutdown(struct spi_device *spi)
|
||||
{
|
||||
struct apple_z2 *z2 = spi_get_drvdata(spi);
|
||||
|
||||
disable_irq(z2->spidev->irq);
|
||||
gpiod_direction_output(z2->reset_gpio, 1);
|
||||
z2->booted = false;
|
||||
}
|
||||
|
||||
static int apple_z2_suspend(struct device *dev)
|
||||
{
|
||||
apple_z2_shutdown(to_spi_device(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apple_z2_resume(struct device *dev)
|
||||
{
|
||||
struct apple_z2 *z2 = spi_get_drvdata(to_spi_device(dev));
|
||||
|
||||
return apple_z2_boot(z2);
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(apple_z2_pm, apple_z2_suspend, apple_z2_resume);
|
||||
|
||||
static const struct of_device_id apple_z2_of_match[] = {
|
||||
{ .compatible = "apple,j293-touchbar" },
|
||||
{ .compatible = "apple,j493-touchbar" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, apple_z2_of_match);
|
||||
|
||||
static struct spi_device_id apple_z2_of_id[] = {
|
||||
{ .name = "j293-touchbar", .driver_data = (kernel_ulong_t)"MacBookPro17,1 Touch Bar" },
|
||||
{ .name = "j493-touchbar", .driver_data = (kernel_ulong_t)"Mac14,7 Touch Bar" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, apple_z2_of_id);
|
||||
|
||||
static struct spi_driver apple_z2_driver = {
|
||||
.driver = {
|
||||
.name = "apple-z2",
|
||||
.pm = pm_sleep_ptr(&apple_z2_pm),
|
||||
.of_match_table = apple_z2_of_match,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.id_table = apple_z2_of_id,
|
||||
.probe = apple_z2_probe,
|
||||
.remove = apple_z2_shutdown,
|
||||
};
|
||||
|
||||
module_spi_driver(apple_z2_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_FIRMWARE("apple/dfrmtfw-*.bin");
|
||||
MODULE_DESCRIPTION("Apple Z2 touchscreens driver");
|
@ -2535,8 +2535,6 @@ fault:
|
||||
static const struct vb2_ops mxt_queue_ops = {
|
||||
.queue_setup = mxt_queue_setup,
|
||||
.buf_queue = mxt_buffer_queue,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
};
|
||||
|
||||
static const struct vb2_queue mxt_queue = {
|
||||
|
@ -12,12 +12,26 @@
|
||||
|
||||
#include <linux/pm.h>
|
||||
|
||||
#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR_A 0x1000C
|
||||
#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D 0x10014
|
||||
|
||||
#define GOODIX_BERLIN_IC_INFO_ADDR_A 0x10068
|
||||
#define GOODIX_BERLIN_IC_INFO_ADDR_D 0x10070
|
||||
|
||||
struct goodix_berlin_ic_data {
|
||||
int fw_version_info_addr;
|
||||
int ic_info_addr;
|
||||
ssize_t read_dummy_len;
|
||||
ssize_t read_prefix_len;
|
||||
};
|
||||
|
||||
struct device;
|
||||
struct input_id;
|
||||
struct regmap;
|
||||
|
||||
int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
|
||||
struct regmap *regmap);
|
||||
struct regmap *regmap,
|
||||
const struct goodix_berlin_ic_data *ic_data);
|
||||
|
||||
extern const struct dev_pm_ops goodix_berlin_pm_ops;
|
||||
extern const struct attribute_group *goodix_berlin_groups[];
|
||||
|
@ -12,7 +12,7 @@
|
||||
* to the previous generations.
|
||||
*
|
||||
* Currently the driver only handles Multitouch events with already
|
||||
* programmed firmware and "config" for "Revision D" Berlin IC.
|
||||
* programmed firmware and "config" for "Revision A/D" Berlin IC.
|
||||
*
|
||||
* Support is missing for:
|
||||
* - ESD Management
|
||||
@ -20,7 +20,7 @@
|
||||
* - "Config" update/flashing
|
||||
* - Stylus Events
|
||||
* - Gesture Events
|
||||
* - Support for older revisions (A & B)
|
||||
* - Support for revision B
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
@ -28,6 +28,7 @@
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/input/touchscreen.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/sizes.h>
|
||||
@ -53,10 +54,8 @@
|
||||
|
||||
#define GOODIX_BERLIN_DEV_CONFIRM_VAL 0xAA
|
||||
#define GOODIX_BERLIN_BOOTOPTION_ADDR 0x10000
|
||||
#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR 0x10014
|
||||
|
||||
#define GOODIX_BERLIN_IC_INFO_MAX_LEN SZ_1K
|
||||
#define GOODIX_BERLIN_IC_INFO_ADDR 0x10070
|
||||
|
||||
#define GOODIX_BERLIN_CHECKSUM_SIZE sizeof(u16)
|
||||
|
||||
@ -175,6 +174,8 @@ struct goodix_berlin_core {
|
||||
/* Runtime parameters extracted from IC_INFO buffer */
|
||||
u32 touch_data_addr;
|
||||
|
||||
const struct goodix_berlin_ic_data *ic_data;
|
||||
|
||||
struct goodix_berlin_event event;
|
||||
};
|
||||
|
||||
@ -299,7 +300,7 @@ static int goodix_berlin_read_version(struct goodix_berlin_core *cd)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_FW_VERSION_INFO_ADDR,
|
||||
error = regmap_raw_read(cd->regmap, cd->ic_data->fw_version_info_addr,
|
||||
&cd->fw_version, sizeof(cd->fw_version));
|
||||
if (error) {
|
||||
dev_err(cd->dev, "error reading fw version, %d\n", error);
|
||||
@ -367,7 +368,7 @@ static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd)
|
||||
if (!afe_data)
|
||||
return -ENOMEM;
|
||||
|
||||
error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR,
|
||||
error = regmap_raw_read(cd->regmap, cd->ic_data->ic_info_addr,
|
||||
&length_raw, sizeof(length_raw));
|
||||
if (error) {
|
||||
dev_err(cd->dev, "failed get ic info length, %d\n", error);
|
||||
@ -380,8 +381,8 @@ static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR,
|
||||
afe_data, length);
|
||||
error = regmap_raw_read(cd->regmap, cd->ic_data->ic_info_addr, afe_data,
|
||||
length);
|
||||
if (error) {
|
||||
dev_err(cd->dev, "failed get ic info data, %d\n", error);
|
||||
return error;
|
||||
@ -716,7 +717,8 @@ const struct attribute_group *goodix_berlin_groups[] = {
|
||||
EXPORT_SYMBOL_GPL(goodix_berlin_groups);
|
||||
|
||||
int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
|
||||
struct regmap *regmap)
|
||||
struct regmap *regmap,
|
||||
const struct goodix_berlin_ic_data *ic_data)
|
||||
{
|
||||
struct goodix_berlin_core *cd;
|
||||
int error;
|
||||
@ -733,6 +735,7 @@ int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
|
||||
cd->dev = dev;
|
||||
cd->regmap = regmap;
|
||||
cd->irq = irq;
|
||||
cd->ic_data = ic_data;
|
||||
|
||||
cd->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(cd->reset_gpio))
|
||||
|
@ -31,6 +31,8 @@ static const struct input_id goodix_berlin_i2c_input_id = {
|
||||
|
||||
static int goodix_berlin_i2c_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct goodix_berlin_ic_data *ic_data =
|
||||
i2c_get_match_data(client);
|
||||
struct regmap *regmap;
|
||||
int error;
|
||||
|
||||
@ -39,22 +41,28 @@ static int goodix_berlin_i2c_probe(struct i2c_client *client)
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
error = goodix_berlin_probe(&client->dev, client->irq,
|
||||
&goodix_berlin_i2c_input_id, regmap);
|
||||
&goodix_berlin_i2c_input_id, regmap,
|
||||
ic_data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct goodix_berlin_ic_data gt9916_data = {
|
||||
.fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D,
|
||||
.ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_D,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id goodix_berlin_i2c_id[] = {
|
||||
{ "gt9916" },
|
||||
{ .name = "gt9916", .driver_data = (long)>9916_data },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, goodix_berlin_i2c_id);
|
||||
|
||||
static const struct of_device_id goodix_berlin_i2c_of_match[] = {
|
||||
{ .compatible = "goodix,gt9916", },
|
||||
{ .compatible = "goodix,gt9916", .data = >9916_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, goodix_berlin_i2c_of_match);
|
||||
|
@ -18,10 +18,14 @@
|
||||
|
||||
#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 + \
|
||||
#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A 4
|
||||
#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D 3
|
||||
#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN_A (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
|
||||
GOODIX_BERLIN_REGISTER_WIDTH + \
|
||||
GOODIX_BERLIN_SPI_READ_DUMMY_LEN)
|
||||
GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A)
|
||||
#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN_D (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
|
||||
GOODIX_BERLIN_REGISTER_WIDTH + \
|
||||
GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D)
|
||||
#define GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
|
||||
GOODIX_BERLIN_REGISTER_WIDTH)
|
||||
|
||||
@ -33,6 +37,7 @@ static int goodix_berlin_spi_read(void *context, const void *reg_buf,
|
||||
size_t val_size)
|
||||
{
|
||||
struct spi_device *spi = context;
|
||||
const struct goodix_berlin_ic_data *ic_data = spi_get_device_match_data(spi);
|
||||
struct spi_transfer xfers;
|
||||
struct spi_message spi_msg;
|
||||
const u32 *reg = reg_buf; /* reg is stored as native u32 at start of buffer */
|
||||
@ -42,23 +47,22 @@ static int goodix_berlin_spi_read(void *context, const void *reg_buf,
|
||||
return -EINVAL;
|
||||
|
||||
u8 *buf __free(kfree) =
|
||||
kzalloc(GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size,
|
||||
GFP_KERNEL);
|
||||
kzalloc(ic_data->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 */
|
||||
/* buffer format: 0xF1 + addr(4bytes) + dummy(3/4bytes) + 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);
|
||||
0xff, ic_data->read_dummy_len);
|
||||
|
||||
xfers.tx_buf = buf;
|
||||
xfers.rx_buf = buf;
|
||||
xfers.len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size;
|
||||
xfers.len = ic_data->read_prefix_len + val_size;
|
||||
xfers.cs_change = 0;
|
||||
spi_message_add_tail(&xfers, &spi_msg);
|
||||
|
||||
@ -68,7 +72,7 @@ static int goodix_berlin_spi_read(void *context, const void *reg_buf,
|
||||
return error;
|
||||
}
|
||||
|
||||
memcpy(val_buf, buf + GOODIX_BERLIN_SPI_READ_PREFIX_LEN, val_size);
|
||||
memcpy(val_buf, buf + ic_data->read_prefix_len, val_size);
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -123,6 +127,7 @@ static const struct input_id goodix_berlin_spi_input_id = {
|
||||
|
||||
static int goodix_berlin_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct goodix_berlin_ic_data *ic_data = spi_get_device_match_data(spi);
|
||||
struct regmap_config regmap_config;
|
||||
struct regmap *regmap;
|
||||
size_t max_size;
|
||||
@ -137,7 +142,7 @@ static int goodix_berlin_spi_probe(struct spi_device *spi)
|
||||
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_read = max_size - ic_data->read_prefix_len;
|
||||
regmap_config.max_raw_write = max_size - GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN;
|
||||
|
||||
regmap = devm_regmap_init(&spi->dev, NULL, spi, ®map_config);
|
||||
@ -145,21 +150,38 @@ static int goodix_berlin_spi_probe(struct spi_device *spi)
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
error = goodix_berlin_probe(&spi->dev, spi->irq,
|
||||
&goodix_berlin_spi_input_id, regmap);
|
||||
&goodix_berlin_spi_input_id, regmap,
|
||||
ic_data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct goodix_berlin_ic_data gt9897_data = {
|
||||
.fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_A,
|
||||
.ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_A,
|
||||
.read_dummy_len = GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A,
|
||||
.read_prefix_len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN_A,
|
||||
};
|
||||
|
||||
static const struct goodix_berlin_ic_data gt9916_data = {
|
||||
.fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D,
|
||||
.ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_D,
|
||||
.read_dummy_len = GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D,
|
||||
.read_prefix_len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN_D,
|
||||
};
|
||||
|
||||
static const struct spi_device_id goodix_berlin_spi_ids[] = {
|
||||
{ "gt9916" },
|
||||
{ .name = "gt9897", .driver_data = (long)>9897_data },
|
||||
{ .name = "gt9916", .driver_data = (long)>9916_data },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, goodix_berlin_spi_ids);
|
||||
|
||||
static const struct of_device_id goodix_berlin_spi_of_match[] = {
|
||||
{ .compatible = "goodix,gt9916", },
|
||||
{ .compatible = "goodix,gt9897", .data = >9897_data },
|
||||
{ .compatible = "goodix,gt9916", .data = >9916_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, goodix_berlin_spi_of_match);
|
||||
|
@ -1108,8 +1108,6 @@ static const struct vb2_ops sur40_queue_ops = {
|
||||
.buf_queue = sur40_buffer_queue,
|
||||
.start_streaming = sur40_start_streaming,
|
||||
.stop_streaming = sur40_stop_streaming,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
};
|
||||
|
||||
static const struct vb2_queue sur40_queue = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user