Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Input: goodix-berlin - add SPI support for Goodix Berlin Touchscreen IC

Add initial support for the new Goodix "Berlin" touchscreen ICs
over the SPI interface.

The driver doesn't use the regmap_spi code since the SPI messages
needs to be prefixed, thus this custom regmap code.

This initial driver is derived from the Goodix goodix_ts_berlin
available at [1] and [2] and only supports the GT9916 IC
present on the Qualcomm SM8550 MTP & QRD touch panel.

The current implementation only supports BerlinD, aka GT9916.

[1] https://github.com/goodix/goodix_ts_berlin
[2] https://git.codelinaro.org/clo/la/platform/vendor/opensource/touch-drivers

Reviewed-by: Jeff LaBundy <jeff@labundy.com>
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://lore.kernel.org/r/20240129-topic-goodix-berlin-upstream-initial-v15-4-6f7d096c0a0a@linaro.org
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Neil Armstrong and committed by
Dmitry Torokhov
3aa182bb fba09e81

+193
+14
drivers/input/touchscreen/Kconfig
··· 433 433 To compile this driver as a module, choose M here: the 434 434 module will be called goodix_berlin_i2c. 435 435 436 + config TOUCHSCREEN_GOODIX_BERLIN_SPI 437 + tristate "Goodix Berlin SPI touchscreen" 438 + depends on SPI_MASTER 439 + select REGMAP 440 + select TOUCHSCREEN_GOODIX_BERLIN_CORE 441 + help 442 + Say Y here if you have a Goodix Berlin IC connected to 443 + your system via SPI. 444 + 445 + If unsure, say N. 446 + 447 + To compile this driver as a module, choose M here: the 448 + module will be called goodix_berlin_spi. 449 + 436 450 config TOUCHSCREEN_HIDEEP 437 451 tristate "HiDeep Touch IC" 438 452 depends on I2C
+1
drivers/input/touchscreen/Makefile
··· 49 49 obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o 50 50 obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o 51 51 obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o 52 + obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI) += goodix_berlin_spi.o 52 53 obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o 53 54 obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o 54 55 obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
+178
drivers/input/touchscreen/goodix_berlin_spi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Goodix Berlin Touchscreen Driver 4 + * 5 + * Copyright (C) 2020 - 2021 Goodix, Inc. 6 + * Copyright (C) 2023 Linaro Ltd. 7 + * 8 + * Based on goodix_ts_berlin driver. 9 + */ 10 + #include <asm/unaligned.h> 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/regmap.h> 14 + #include <linux/spi/spi.h> 15 + #include <linux/input.h> 16 + 17 + #include "goodix_berlin.h" 18 + 19 + #define GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN 1 20 + #define GOODIX_BERLIN_REGISTER_WIDTH 4 21 + #define GOODIX_BERLIN_SPI_READ_DUMMY_LEN 3 22 + #define GOODIX_BERLIN_SPI_READ_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \ 23 + GOODIX_BERLIN_REGISTER_WIDTH + \ 24 + GOODIX_BERLIN_SPI_READ_DUMMY_LEN) 25 + #define GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \ 26 + GOODIX_BERLIN_REGISTER_WIDTH) 27 + 28 + #define GOODIX_BERLIN_SPI_WRITE_FLAG 0xF0 29 + #define GOODIX_BERLIN_SPI_READ_FLAG 0xF1 30 + 31 + static int goodix_berlin_spi_read(void *context, const void *reg_buf, 32 + size_t reg_size, void *val_buf, 33 + size_t val_size) 34 + { 35 + struct spi_device *spi = context; 36 + struct spi_transfer xfers; 37 + struct spi_message spi_msg; 38 + const u32 *reg = reg_buf; /* reg is stored as native u32 at start of buffer */ 39 + u8 *buf; 40 + int error; 41 + 42 + if (reg_size != GOODIX_BERLIN_REGISTER_WIDTH) 43 + return -EINVAL; 44 + 45 + buf = kzalloc(GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size, GFP_KERNEL); 46 + if (!buf) 47 + return -ENOMEM; 48 + 49 + spi_message_init(&spi_msg); 50 + memset(&xfers, 0, sizeof(xfers)); 51 + 52 + /* buffer format: 0xF1 + addr(4bytes) + dummy(3bytes) + data */ 53 + buf[0] = GOODIX_BERLIN_SPI_READ_FLAG; 54 + put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN); 55 + memset(buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + GOODIX_BERLIN_REGISTER_WIDTH, 56 + 0xff, GOODIX_BERLIN_SPI_READ_DUMMY_LEN); 57 + 58 + xfers.tx_buf = buf; 59 + xfers.rx_buf = buf; 60 + xfers.len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size; 61 + xfers.cs_change = 0; 62 + spi_message_add_tail(&xfers, &spi_msg); 63 + 64 + error = spi_sync(spi, &spi_msg); 65 + if (error < 0) 66 + dev_err(&spi->dev, "spi transfer error, %d", error); 67 + else 68 + memcpy(val_buf, buf + GOODIX_BERLIN_SPI_READ_PREFIX_LEN, val_size); 69 + 70 + kfree(buf); 71 + return error; 72 + } 73 + 74 + static int goodix_berlin_spi_write(void *context, const void *data, 75 + size_t count) 76 + { 77 + unsigned int len = count - GOODIX_BERLIN_REGISTER_WIDTH; 78 + struct spi_device *spi = context; 79 + struct spi_transfer xfers; 80 + struct spi_message spi_msg; 81 + const u32 *reg = data; /* reg is stored as native u32 at start of buffer */ 82 + u8 *buf; 83 + int error; 84 + 85 + buf = kzalloc(GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN + len, GFP_KERNEL); 86 + if (!buf) 87 + return -ENOMEM; 88 + 89 + spi_message_init(&spi_msg); 90 + memset(&xfers, 0, sizeof(xfers)); 91 + 92 + buf[0] = GOODIX_BERLIN_SPI_WRITE_FLAG; 93 + put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN); 94 + memcpy(buf + GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN, 95 + data + GOODIX_BERLIN_REGISTER_WIDTH, len); 96 + 97 + xfers.tx_buf = buf; 98 + xfers.len = GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN + len; 99 + xfers.cs_change = 0; 100 + spi_message_add_tail(&xfers, &spi_msg); 101 + 102 + error = spi_sync(spi, &spi_msg); 103 + if (error < 0) 104 + dev_err(&spi->dev, "spi transfer error, %d", error); 105 + 106 + kfree(buf); 107 + return error; 108 + } 109 + 110 + static const struct regmap_config goodix_berlin_spi_regmap_conf = { 111 + .reg_bits = 32, 112 + .val_bits = 8, 113 + .read = goodix_berlin_spi_read, 114 + .write = goodix_berlin_spi_write, 115 + }; 116 + 117 + /* vendor & product left unassigned here, should probably be updated from fw info */ 118 + static const struct input_id goodix_berlin_spi_input_id = { 119 + .bustype = BUS_SPI, 120 + }; 121 + 122 + static int goodix_berlin_spi_probe(struct spi_device *spi) 123 + { 124 + struct regmap_config regmap_config; 125 + struct regmap *regmap; 126 + size_t max_size; 127 + int error = 0; 128 + 129 + spi->mode = SPI_MODE_0; 130 + spi->bits_per_word = 8; 131 + error = spi_setup(spi); 132 + if (error) 133 + return error; 134 + 135 + max_size = spi_max_transfer_size(spi); 136 + 137 + regmap_config = goodix_berlin_spi_regmap_conf; 138 + regmap_config.max_raw_read = max_size - GOODIX_BERLIN_SPI_READ_PREFIX_LEN; 139 + regmap_config.max_raw_write = max_size - GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN; 140 + 141 + regmap = devm_regmap_init(&spi->dev, NULL, spi, &regmap_config); 142 + if (IS_ERR(regmap)) 143 + return PTR_ERR(regmap); 144 + 145 + error = goodix_berlin_probe(&spi->dev, spi->irq, 146 + &goodix_berlin_spi_input_id, regmap); 147 + if (error) 148 + return error; 149 + 150 + return 0; 151 + } 152 + 153 + static const struct spi_device_id goodix_berlin_spi_ids[] = { 154 + { "gt9916" }, 155 + { }, 156 + }; 157 + MODULE_DEVICE_TABLE(spi, goodix_berlin_spi_ids); 158 + 159 + static const struct of_device_id goodix_berlin_spi_of_match[] = { 160 + { .compatible = "goodix,gt9916", }, 161 + { } 162 + }; 163 + MODULE_DEVICE_TABLE(of, goodix_berlin_spi_of_match); 164 + 165 + static struct spi_driver goodix_berlin_spi_driver = { 166 + .driver = { 167 + .name = "goodix-berlin-spi", 168 + .of_match_table = goodix_berlin_spi_of_match, 169 + .pm = pm_sleep_ptr(&goodix_berlin_pm_ops), 170 + }, 171 + .probe = goodix_berlin_spi_probe, 172 + .id_table = goodix_berlin_spi_ids, 173 + }; 174 + module_spi_driver(goodix_berlin_spi_driver); 175 + 176 + MODULE_LICENSE("GPL"); 177 + MODULE_DESCRIPTION("Goodix Berlin SPI Touchscreen driver"); 178 + MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");