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:
Linus Torvalds 2025-04-05 09:20:39 -07:00
commit 56f944529e
24 changed files with 813 additions and 149 deletions

View File

@ -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>;
};

View 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;
};

View File

@ -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>;
};
};
...

View File

@ -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;
};
};
};
...

View File

@ -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>;
};
};
...

View File

@ -19,6 +19,7 @@ allOf:
properties:
compatible:
enum:
- goodix,gt9897
- goodix,gt9916
reg:

View File

@ -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 = <&reg_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 = <&reg_vcc3>;
wakeup-source;
ti,pressure-max = /bits/ 16 <255>;
ti,x-max = /bits/ 16 <8000>;
ti,x-min = /bits/ 16 <0>;
ti,x-plate-ohms = /bits/ 16 <40>;
ti,y-max = /bits/ 16 <4800>;
ti,y-min = /bits/ 16 <0>;
};
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>;
};
};

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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",

View File

@ -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 = {

View File

@ -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

View File

@ -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

View 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");

View File

@ -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 = {

View File

@ -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[];

View File

@ -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))

View File

@ -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)&gt9916_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 = &gt9916_data },
{ }
};
MODULE_DEVICE_TABLE(of, goodix_berlin_i2c_of_match);

View File

@ -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, &regmap_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)&gt9897_data },
{ .name = "gt9916", .driver_data = (long)&gt9916_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 = &gt9897_data },
{ .compatible = "goodix,gt9916", .data = &gt9916_data },
{ }
};
MODULE_DEVICE_TABLE(of, goodix_berlin_spi_of_match);

View File

@ -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 = {