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

Input: add driver for Hynitron cstxxx touchscreens

Add support for the Hynitron cst3xx controller found on devices such
as the Anbernic RG353P and RG353V (the Hynitron CST340). This driver
was built from sources provided by Hynitron to Anbernic (possibly
via Rockchip as an intermediary) and marked as GPLv2 in the code.
This driver was written strictly for the cst3xx series, but in
most places was left somewhat generic so support could be easily
added to other devices in the future.

Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Link: https://lore.kernel.org/r/20221028202636.14341-4-macroalpha82@gmail.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Chris Morgan and committed by
Dmitry Torokhov
66603243 86a7d13c

+511
+12
drivers/input/touchscreen/Kconfig
··· 422 422 To compile this driver as a module, choose M here: the 423 423 module will be called hycon-hy46xx. 424 424 425 + config TOUCHSCREEN_HYNITRON_CSTXXX 426 + tristate "Hynitron touchscreen support" 427 + depends on I2C 428 + help 429 + Say Y here if you have a touchscreen using a Hynitron 430 + touchscreen controller. 431 + 432 + If unsure, say N. 433 + 434 + To compile this driver as a module, choose M here: the 435 + module will be called hynitron-cstxxx. 436 + 425 437 config TOUCHSCREEN_ILI210X 426 438 tristate "Ilitek ILI210X based touchscreen" 427 439 depends on I2C
+1
drivers/input/touchscreen/Makefile
··· 47 47 obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o 48 48 obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o 49 49 obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o 50 + obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o 50 51 obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o 51 52 obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o 52 53 obj-$(CONFIG_TOUCHSCREEN_IMAGIS) += imagis.o
+498
drivers/input/touchscreen/hynitron_cstxxx.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Driver for Hynitron cstxxx Touchscreen 4 + * 5 + * Copyright (c) 2022 Chris Morgan <macromorgan@hotmail.com> 6 + * 7 + * This code is based on hynitron_core.c authored by Hynitron. 8 + * Note that no datasheet was available, so much of these registers 9 + * are undocumented. This is essentially a cleaned-up version of the 10 + * vendor driver with support removed for hardware I cannot test and 11 + * device-specific functions replated with generic functions wherever 12 + * possible. 13 + */ 14 + 15 + #include <linux/delay.h> 16 + #include <linux/err.h> 17 + #include <linux/gpio/consumer.h> 18 + #include <linux/i2c.h> 19 + #include <linux/input.h> 20 + #include <linux/input/mt.h> 21 + #include <linux/input/touchscreen.h> 22 + #include <linux/mod_devicetable.h> 23 + #include <linux/module.h> 24 + #include <linux/property.h> 25 + #include <asm/unaligned.h> 26 + 27 + /* Per chip data */ 28 + struct hynitron_ts_chip_data { 29 + unsigned int max_touch_num; 30 + u32 ic_chkcode; 31 + int (*firmware_info)(struct i2c_client *client); 32 + int (*bootloader_enter)(struct i2c_client *client); 33 + int (*init_input)(struct i2c_client *client); 34 + void (*report_touch)(struct i2c_client *client); 35 + }; 36 + 37 + /* Data generic to all (supported and non-supported) controllers. */ 38 + struct hynitron_ts_data { 39 + const struct hynitron_ts_chip_data *chip; 40 + struct i2c_client *client; 41 + struct input_dev *input_dev; 42 + struct touchscreen_properties prop; 43 + struct gpio_desc *reset_gpio; 44 + }; 45 + 46 + /* 47 + * Since I have no datasheet, these values are guessed and/or assumed 48 + * based on observation and testing. 49 + */ 50 + #define CST3XX_FIRMWARE_INFO_START_CMD 0x01d1 51 + #define CST3XX_FIRMWARE_INFO_END_CMD 0x09d1 52 + #define CST3XX_FIRMWARE_CHK_CODE_REG 0xfcd1 53 + #define CST3XX_FIRMWARE_VERSION_REG 0x08d2 54 + #define CST3XX_FIRMWARE_VER_INVALID_VAL 0xa5a5a5a5 55 + 56 + #define CST3XX_BOOTLDR_PROG_CMD 0xaa01a0 57 + #define CST3XX_BOOTLDR_PROG_CHK_REG 0x02a0 58 + #define CST3XX_BOOTLDR_CHK_VAL 0xac 59 + 60 + #define CST3XX_TOUCH_DATA_PART_REG 0x00d0 61 + #define CST3XX_TOUCH_DATA_FULL_REG 0x07d0 62 + #define CST3XX_TOUCH_DATA_CHK_VAL 0xab 63 + #define CST3XX_TOUCH_DATA_TOUCH_VAL 0x03 64 + #define CST3XX_TOUCH_DATA_STOP_CMD 0xab00d0 65 + #define CST3XX_TOUCH_COUNT_MASK GENMASK(6, 0) 66 + 67 + 68 + /* 69 + * Hard coded reset delay value of 20ms not IC dependent in 70 + * vendor driver. 71 + */ 72 + static void hyn_reset_proc(struct i2c_client *client, int delay) 73 + { 74 + struct hynitron_ts_data *ts_data = i2c_get_clientdata(client); 75 + 76 + gpiod_set_value_cansleep(ts_data->reset_gpio, 1); 77 + msleep(20); 78 + gpiod_set_value_cansleep(ts_data->reset_gpio, 0); 79 + if (delay) 80 + fsleep(delay * 1000); 81 + } 82 + 83 + static irqreturn_t hyn_interrupt_handler(int irq, void *dev_id) 84 + { 85 + struct i2c_client *client = dev_id; 86 + struct hynitron_ts_data *ts_data = i2c_get_clientdata(client); 87 + 88 + ts_data->chip->report_touch(client); 89 + 90 + return IRQ_HANDLED; 91 + } 92 + 93 + /* 94 + * The vendor driver would retry twice before failing to read or write 95 + * to the i2c device. 96 + */ 97 + 98 + static int cst3xx_i2c_write(struct i2c_client *client, 99 + unsigned char *buf, int len) 100 + { 101 + int ret; 102 + int retries = 0; 103 + 104 + while (retries < 2) { 105 + ret = i2c_master_send(client, buf, len); 106 + if (ret == len) 107 + return 0; 108 + if (ret <= 0) 109 + retries++; 110 + else 111 + break; 112 + } 113 + 114 + return ret < 0 ? ret : -EIO; 115 + } 116 + 117 + static int cst3xx_i2c_read_register(struct i2c_client *client, u16 reg, 118 + u8 *val, u16 len) 119 + { 120 + __le16 buf = cpu_to_le16(reg); 121 + struct i2c_msg msgs[] = { 122 + { 123 + .addr = client->addr, 124 + .flags = 0, 125 + .len = 2, 126 + .buf = (u8 *)&buf, 127 + }, 128 + { 129 + .addr = client->addr, 130 + .flags = I2C_M_RD, 131 + .len = len, 132 + .buf = val, 133 + } 134 + }; 135 + int err; 136 + int ret; 137 + 138 + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 139 + if (ret == ARRAY_SIZE(msgs)) 140 + return 0; 141 + 142 + err = ret < 0 ? ret : -EIO; 143 + dev_err(&client->dev, "Error reading %d bytes from 0x%04x: %d (%d)\n", 144 + len, reg, err, ret); 145 + 146 + return err; 147 + } 148 + 149 + static int cst3xx_firmware_info(struct i2c_client *client) 150 + { 151 + struct hynitron_ts_data *ts_data = i2c_get_clientdata(client); 152 + int err; 153 + u32 tmp; 154 + unsigned char buf[4]; 155 + 156 + /* 157 + * Tests suggest this command needed to read firmware regs. 158 + */ 159 + put_unaligned_le16(CST3XX_FIRMWARE_INFO_START_CMD, buf); 160 + err = cst3xx_i2c_write(client, buf, 2); 161 + if (err) 162 + return err; 163 + 164 + usleep_range(10000, 11000); 165 + 166 + /* 167 + * Read register for check-code to determine if device detected 168 + * correctly. 169 + */ 170 + err = cst3xx_i2c_read_register(client, CST3XX_FIRMWARE_CHK_CODE_REG, 171 + buf, 4); 172 + if (err) 173 + return err; 174 + 175 + tmp = get_unaligned_le32(buf); 176 + if ((tmp & 0xffff0000) != ts_data->chip->ic_chkcode) { 177 + dev_err(&client->dev, "%s ic mismatch, chkcode is %u\n", 178 + __func__, tmp); 179 + return -ENODEV; 180 + } 181 + 182 + usleep_range(10000, 11000); 183 + 184 + /* Read firmware version and test if firmware missing. */ 185 + err = cst3xx_i2c_read_register(client, CST3XX_FIRMWARE_VERSION_REG, 186 + buf, 4); 187 + if (err) 188 + return err; 189 + 190 + tmp = get_unaligned_le32(buf); 191 + if (tmp == CST3XX_FIRMWARE_VER_INVALID_VAL) { 192 + dev_err(&client->dev, "Device firmware missing\n"); 193 + return -ENODEV; 194 + } 195 + 196 + /* 197 + * Tests suggest cmd required to exit reading firmware regs. 198 + */ 199 + put_unaligned_le16(CST3XX_FIRMWARE_INFO_END_CMD, buf); 200 + err = cst3xx_i2c_write(client, buf, 2); 201 + if (err) 202 + return err; 203 + 204 + usleep_range(5000, 6000); 205 + 206 + return 0; 207 + } 208 + 209 + static int cst3xx_bootloader_enter(struct i2c_client *client) 210 + { 211 + int err; 212 + u8 retry; 213 + u32 tmp; 214 + unsigned char buf[3]; 215 + 216 + for (retry = 0; retry < 5; retry++) { 217 + hyn_reset_proc(client, (7 + retry)); 218 + /* set cmd to enter program mode */ 219 + put_unaligned_le24(CST3XX_BOOTLDR_PROG_CMD, buf); 220 + err = cst3xx_i2c_write(client, buf, 3); 221 + if (err) 222 + continue; 223 + 224 + usleep_range(2000, 2500); 225 + 226 + /* check whether in program mode */ 227 + err = cst3xx_i2c_read_register(client, 228 + CST3XX_BOOTLDR_PROG_CHK_REG, 229 + buf, 1); 230 + if (err) 231 + continue; 232 + 233 + tmp = get_unaligned(buf); 234 + if (tmp == CST3XX_BOOTLDR_CHK_VAL) 235 + break; 236 + } 237 + 238 + if (tmp != CST3XX_BOOTLDR_CHK_VAL) { 239 + dev_err(&client->dev, "%s unable to enter bootloader mode\n", 240 + __func__); 241 + return -ENODEV; 242 + } 243 + 244 + hyn_reset_proc(client, 40); 245 + 246 + return 0; 247 + } 248 + 249 + static void cst3xx_report_contact(struct hynitron_ts_data *ts_data, 250 + u8 id, unsigned int x, unsigned int y, u8 w) 251 + { 252 + input_mt_slot(ts_data->input_dev, id); 253 + input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, 1); 254 + touchscreen_report_pos(ts_data->input_dev, &ts_data->prop, x, y, true); 255 + input_report_abs(ts_data->input_dev, ABS_MT_TOUCH_MAJOR, w); 256 + } 257 + 258 + static int cst3xx_finish_touch_read(struct i2c_client *client) 259 + { 260 + unsigned char buf[3]; 261 + int err; 262 + 263 + put_unaligned_le24(CST3XX_TOUCH_DATA_STOP_CMD, buf); 264 + err = cst3xx_i2c_write(client, buf, 3); 265 + if (err) { 266 + dev_err(&client->dev, 267 + "send read touch info ending failed: %d\n", err); 268 + return err; 269 + } 270 + 271 + return 0; 272 + } 273 + 274 + /* 275 + * Handle events from IRQ. Note that for cst3xx it appears that IRQ 276 + * fires continuously while touched, otherwise once every 1500ms 277 + * when not touched (assume touchscreen waking up periodically). 278 + * Note buffer is sized for 5 fingers, if more needed buffer must 279 + * be increased. The buffer contains 5 bytes for each touch point, 280 + * a touch count byte, a check byte, and then a second check byte after 281 + * all other touch points. 282 + * 283 + * For example 1 touch would look like this: 284 + * touch1[5]:touch_count[1]:chk_byte[1] 285 + * 286 + * 3 touches would look like this: 287 + * touch1[5]:touch_count[1]:chk_byte[1]:touch2[5]:touch3[5]:chk_byte[1] 288 + */ 289 + static void cst3xx_touch_report(struct i2c_client *client) 290 + { 291 + struct hynitron_ts_data *ts_data = i2c_get_clientdata(client); 292 + u8 buf[28]; 293 + u8 finger_id, sw, w; 294 + unsigned int x, y; 295 + unsigned int touch_cnt, end_byte; 296 + unsigned int idx = 0; 297 + unsigned int i; 298 + int err; 299 + 300 + /* Read and validate the first bits of input data. */ 301 + err = cst3xx_i2c_read_register(client, CST3XX_TOUCH_DATA_PART_REG, 302 + buf, 28); 303 + if (err || 304 + buf[6] != CST3XX_TOUCH_DATA_CHK_VAL || 305 + buf[0] == CST3XX_TOUCH_DATA_CHK_VAL) { 306 + dev_err(&client->dev, "cst3xx touch read failure\n"); 307 + return; 308 + } 309 + 310 + /* Report to the device we're done reading the touch data. */ 311 + err = cst3xx_finish_touch_read(client); 312 + if (err) 313 + return; 314 + 315 + touch_cnt = buf[5] & CST3XX_TOUCH_COUNT_MASK; 316 + /* 317 + * Check the check bit of the last touch slot. The check bit is 318 + * always present after touch point 1 for valid data, and then 319 + * appears as the last byte after all other touch data. 320 + */ 321 + if (touch_cnt > 1) { 322 + end_byte = touch_cnt * 5 + 2; 323 + if (buf[end_byte] != CST3XX_TOUCH_DATA_CHK_VAL) { 324 + dev_err(&client->dev, "cst3xx touch read failure\n"); 325 + return; 326 + } 327 + } 328 + 329 + /* Parse through the buffer to capture touch data. */ 330 + for (i = 0; i < touch_cnt; i++) { 331 + x = ((buf[idx + 1] << 4) | ((buf[idx + 3] >> 4) & 0x0f)); 332 + y = ((buf[idx + 2] << 4) | (buf[idx + 3] & 0x0f)); 333 + w = (buf[idx + 4] >> 3); 334 + sw = (buf[idx] & 0x0f) >> 1; 335 + finger_id = (buf[idx] >> 4) & 0x0f; 336 + 337 + /* Sanity check we don't have more fingers than we expect */ 338 + if (ts_data->chip->max_touch_num < finger_id) { 339 + dev_err(&client->dev, "cst3xx touch read failure\n"); 340 + break; 341 + } 342 + 343 + /* sw value of 0 means no touch, 0x03 means touch */ 344 + if (sw == CST3XX_TOUCH_DATA_TOUCH_VAL) 345 + cst3xx_report_contact(ts_data, finger_id, x, y, w); 346 + 347 + idx += 5; 348 + 349 + /* Skip the 2 bytes between point 1 and point 2 */ 350 + if (i == 0) 351 + idx += 2; 352 + } 353 + 354 + input_mt_sync_frame(ts_data->input_dev); 355 + input_sync(ts_data->input_dev); 356 + } 357 + 358 + static int cst3xx_input_dev_int(struct i2c_client *client) 359 + { 360 + struct hynitron_ts_data *ts_data = i2c_get_clientdata(client); 361 + int err; 362 + 363 + ts_data->input_dev = devm_input_allocate_device(&client->dev); 364 + if (!ts_data->input_dev) { 365 + dev_err(&client->dev, "Failed to allocate input device\n"); 366 + return -ENOMEM; 367 + } 368 + 369 + ts_data->input_dev->name = "Hynitron cst3xx Touchscreen"; 370 + ts_data->input_dev->phys = "input/ts"; 371 + ts_data->input_dev->id.bustype = BUS_I2C; 372 + 373 + input_set_drvdata(ts_data->input_dev, ts_data); 374 + 375 + input_set_capability(ts_data->input_dev, EV_ABS, ABS_MT_POSITION_X); 376 + input_set_capability(ts_data->input_dev, EV_ABS, ABS_MT_POSITION_Y); 377 + input_set_abs_params(ts_data->input_dev, ABS_MT_TOUCH_MAJOR, 378 + 0, 255, 0, 0); 379 + 380 + touchscreen_parse_properties(ts_data->input_dev, true, &ts_data->prop); 381 + 382 + if (!ts_data->prop.max_x || !ts_data->prop.max_y) { 383 + dev_err(&client->dev, 384 + "Invalid x/y (%d, %d), using defaults\n", 385 + ts_data->prop.max_x, ts_data->prop.max_y); 386 + ts_data->prop.max_x = 1152; 387 + ts_data->prop.max_y = 1920; 388 + input_abs_set_max(ts_data->input_dev, 389 + ABS_MT_POSITION_X, ts_data->prop.max_x); 390 + input_abs_set_max(ts_data->input_dev, 391 + ABS_MT_POSITION_Y, ts_data->prop.max_y); 392 + } 393 + 394 + err = input_mt_init_slots(ts_data->input_dev, 395 + ts_data->chip->max_touch_num, 396 + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 397 + if (err) { 398 + dev_err(&client->dev, 399 + "Failed to initialize input slots: %d\n", err); 400 + return err; 401 + } 402 + 403 + err = input_register_device(ts_data->input_dev); 404 + if (err) { 405 + dev_err(&client->dev, 406 + "Input device registration failed: %d\n", err); 407 + return err; 408 + } 409 + 410 + return 0; 411 + } 412 + 413 + static int hyn_probe(struct i2c_client *client) 414 + { 415 + struct hynitron_ts_data *ts_data; 416 + int err; 417 + 418 + ts_data = devm_kzalloc(&client->dev, sizeof(*ts_data), GFP_KERNEL); 419 + if (!ts_data) 420 + return -ENOMEM; 421 + 422 + ts_data->client = client; 423 + i2c_set_clientdata(client, ts_data); 424 + 425 + ts_data->chip = device_get_match_data(&client->dev); 426 + if (!ts_data->chip) 427 + return -EINVAL; 428 + 429 + ts_data->reset_gpio = devm_gpiod_get(&client->dev, 430 + "reset", GPIOD_OUT_LOW); 431 + err = PTR_ERR_OR_ZERO(ts_data->reset_gpio); 432 + if (err) { 433 + dev_err(&client->dev, "request reset gpio failed: %d\n", err); 434 + return err; 435 + } 436 + 437 + hyn_reset_proc(client, 60); 438 + 439 + err = ts_data->chip->bootloader_enter(client); 440 + if (err < 0) 441 + return err; 442 + 443 + err = ts_data->chip->init_input(client); 444 + if (err < 0) 445 + return err; 446 + 447 + err = ts_data->chip->firmware_info(client); 448 + if (err < 0) 449 + return err; 450 + 451 + err = devm_request_threaded_irq(&client->dev, client->irq, 452 + NULL, hyn_interrupt_handler, 453 + IRQF_ONESHOT, 454 + "Hynitron Touch Int", client); 455 + if (err) { 456 + dev_err(&client->dev, "failed to request IRQ: %d\n", err); 457 + return err; 458 + } 459 + 460 + return 0; 461 + } 462 + 463 + static const struct hynitron_ts_chip_data cst3xx_data = { 464 + .max_touch_num = 5, 465 + .ic_chkcode = 0xcaca0000, 466 + .firmware_info = &cst3xx_firmware_info, 467 + .bootloader_enter = &cst3xx_bootloader_enter, 468 + .init_input = &cst3xx_input_dev_int, 469 + .report_touch = &cst3xx_touch_report, 470 + }; 471 + 472 + static const struct i2c_device_id hyn_tpd_id[] = { 473 + { .name = "hynitron_ts", 0 }, 474 + { /* sentinel */ }, 475 + }; 476 + MODULE_DEVICE_TABLE(i2c, hyn_tpd_id); 477 + 478 + static const struct of_device_id hyn_dt_match[] = { 479 + { .compatible = "hynitron,cst340", .data = &cst3xx_data }, 480 + { /* sentinel */ }, 481 + }; 482 + MODULE_DEVICE_TABLE(of, hyn_dt_match); 483 + 484 + static struct i2c_driver hynitron_i2c_driver = { 485 + .driver = { 486 + .name = "Hynitron-TS", 487 + .of_match_table = hyn_dt_match, 488 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 489 + }, 490 + .id_table = hyn_tpd_id, 491 + .probe_new = hyn_probe, 492 + }; 493 + 494 + module_i2c_driver(hynitron_i2c_driver); 495 + 496 + MODULE_AUTHOR("Chris Morgan"); 497 + MODULE_DESCRIPTION("Hynitron Touchscreen Driver"); 498 + MODULE_LICENSE("GPL");