Identity
| Part | Goodix GT911 |
| Role | Capacitive multitouch controller for the PineTab2 panel |
| Bus / address | PineTab2 i2c1 addr 0x5d; FreeBSD iicbus uses shifted address 0xba internally |
| GPIO / IRQ | IRQ GPIO0_B0, falling edge; reset GPIO0_C2 |
| Supplies | AVDD28 = vcc3v3_pmu, VDDIO = vcca1v8_pmu |
| DTS compatible | goodix,gt911 |
Status — ◐ partial
The PinePhone Pro Goodix driver is now generalized for the PineTab2
GT911 instance. It matches both goodix,gt917s and goodix,gt911,
selects the correct I2C address during reset, and uses the model’s
matching configuration block: GT917S stays on 0x8050 / 240 bytes,
while GT911 uses the GT9x 0x8047 / 186-byte block.
This is still hardware-pending. The expected first PineTab2 evidence is
that goodix0 probes at 0x5d, reports chip ID 911, exposes
dev.goodix.0.config_addr=32839 (0x8047), and registers an evdev
touchscreen. Real coordinate orientation waits until the internal DSI
panel path is active; before that, the touch controller can still be
proved over I2C and evdev.
Driver Notes
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2026 Josh Adams
5
*
6
* Goodix GT9xx Touchscreen Driver
7
*
8
* Multitouch I2C touchscreen controller for PinePhone Pro and PineTab2.
9
* Reports touch events via evdev MT Protocol B.
10
*/
11
12
#include <sys/param.h>
13
#include <sys/systm.h>
14
#include <sys/bus.h>
15
#include <sys/callout.h>
16
#include <sys/kernel.h>
17
#include <sys/taskqueue.h>
18
#include <sys/module.h>
19
#include <sys/endian.h>
20
#include <sys/gpio.h>
21
#include <sys/rman.h>
22
#include <sys/sysctl.h>
23
#include <machine/bus.h>
24
#include <machine/resource.h>
25
26
#include <dev/iicbus/iicbus.h>
27
#include <dev/iicbus/iiconf.h>
28
29
#include <dev/evdev/evdev.h>
30
#include <dev/evdev/input.h>
31
32
#include <dev/gpio/gpiobusvar.h>
33
34
#include <dev/ofw/ofw_bus.h>
35
#include <dev/ofw/ofw_bus_subr.h>
36
37
/* Goodix registers (16-bit big-endian addresses) */
38
#define GOODIX_REG_ID 0x8140
39
#define GOODIX_GT1X_REG_CONFIG 0x8050
40
#define GOODIX_GT9X_REG_CONFIG 0x8047
41
#define GOODIX_REG_STATUS 0x814E
42
#define GOODIX_CONFIG_GT911_LEN 186
43
#define GOODIX_CONFIG_GT9X_LEN 240
44
45
/* Touch contact: 8 bytes per point */
46
#define GOODIX_CONTACT_SIZE 8
47
#define GOODIX_MAX_CONTACTS 10
48
49
enum goodix_model_id {
50
GOODIX_MODEL_GT917S = 1,
51
GOODIX_MODEL_GT911,
52
};
53
54
struct goodix_model {
55
enum goodix_model_id id;
56
const char *desc;
57
const char *evdev_name;
58
uint16_t product;
59
uint16_t config_addr;
60
uint16_t config_len;
61
uint16_t fallback_x;
62
uint16_t fallback_y;
63
uint8_t fallback_touches;
64
};
65
66
static const struct goodix_model goodix_models[] = {
67
{
68
.id = GOODIX_MODEL_GT917S,
69
.desc = "Goodix GT917S Touchscreen",
70
.evdev_name = "Goodix GT917S Touchscreen",
71
.product = 0x9170,
72
.config_addr = GOODIX_GT1X_REG_CONFIG,
73
.config_len = GOODIX_CONFIG_GT9X_LEN,
74
.fallback_x = 720,
75
.fallback_y = 1440,
76
.fallback_touches = 5,
77
},
78
{
79
.id = GOODIX_MODEL_GT911,
80
.desc = "Goodix GT911 Touchscreen",
81
.evdev_name = "Goodix GT911 Touchscreen",
82
.product = 0x0911,
83
.config_addr = GOODIX_GT9X_REG_CONFIG,
84
.config_len = GOODIX_CONFIG_GT911_LEN,
85
.fallback_x = 1280,
86
.fallback_y = 800,
87
.fallback_touches = 5,
88
},
89
};
90
91
static const struct ofw_compat_data goodix_compat[] = {
92
{ "goodix,gt917s", GOODIX_MODEL_GT917S },
93
{ "goodix,gt911", GOODIX_MODEL_GT911 },
94
{ NULL, 0 },
95
};
96
97
struct goodix_softc {
98
device_t sc_dev;
99
const struct goodix_model *sc_model;
100
uint16_t sc_addr; /* I2C address (shifted) */
101
uint16_t sc_addr7;
102
gpio_pin_t sc_rst_pin;
103
gpio_pin_t sc_int_pin;
104
struct evdev_dev *sc_evdev;
105
struct resource *sc_irq_res;
106
void *sc_irq_hdl;
107
struct callout sc_poll_callout;
108
struct task sc_poll_task;
109
uint16_t sc_max_x;
110
uint16_t sc_max_y;
111
uint16_t sc_dt_max_x;
112
uint16_t sc_dt_max_y;
113
uint16_t sc_version;
114
uint16_t sc_config_addr;
115
uint16_t sc_config_len;
116
uint8_t sc_max_touch;
117
uint8_t sc_polling;
118
char sc_chip_id[5];
119
uint8_t sc_contact_buf[GOODIX_MAX_CONTACTS * GOODIX_CONTACT_SIZE];
120
/* Track which slots are active for release detection */
121
uint16_t sc_active_slots;
122
};
123
124
static const struct goodix_model *
125
goodix_model_by_id(enum goodix_model_id id)
126
{
127
int i;
128
129
for (i = 0; i < nitems(goodix_models); i++) {
130
if (goodix_models[i].id == id)
131
return (&goodix_models[i]);
132
}
133
134
return (NULL);
135
}
136
137
static const struct goodix_model *
138
goodix_model_for_dev(device_t dev)
139
{
140
const struct ofw_compat_data *compat;
141
142
compat = ofw_bus_search_compatible(dev, goodix_compat);
143
if (compat->ocd_data == 0)
144
return (NULL);
145
146
return (goodix_model_by_id((enum goodix_model_id)compat->ocd_data));
147
}
148
149
static uint16_t
150
goodix_addr_7bit(struct goodix_softc *sc)
151
{
152
153
if (sc->sc_addr > 0x7f)
154
return (sc->sc_addr >> 1);
155
156
return (sc->sc_addr);
157
}
158
159
static uint16_t
160
goodix_fallback_x(struct goodix_softc *sc)
161
{
162
163
if (sc->sc_dt_max_x != 0)
164
return (sc->sc_dt_max_x);
165
166
return (sc->sc_model->fallback_x);
167
}
168
169
static uint16_t
170
goodix_fallback_y(struct goodix_softc *sc)
171
{
172
173
if (sc->sc_dt_max_y != 0)
174
return (sc->sc_dt_max_y);
175
176
return (sc->sc_model->fallback_y);
177
}
178
179
static void
180
goodix_read_size_prop(phandle_t node, const char *name, uint16_t *val)
181
{
182
uint32_t tmp;
183
184
if (OF_getencprop(node, name, &tmp, sizeof(tmp)) > 0 &&
185
tmp <= 0xffff)
186
*val = tmp;
187
}
188
189
static int
190
goodix_read(struct goodix_softc *sc, uint16_t reg, uint8_t *buf, uint16_t len)
191
{
192
uint8_t reg_buf[2];
193
struct iic_msg msgs[2];
194
195
reg_buf[0] = reg >> 8;
196
reg_buf[1] = reg & 0xFF;
197
198
msgs[0].slave = sc->sc_addr;
199
msgs[0].flags = IIC_M_WR;
200
msgs[0].len = 2;
201
msgs[0].buf = reg_buf;
202
203
msgs[1].slave = sc->sc_addr;
204
msgs[1].flags = IIC_M_RD;
205
msgs[1].len = len;
206
msgs[1].buf = buf;
207
208
return (iicbus_transfer(sc->sc_dev, msgs, 2));
209
}
210
211
static int
212
goodix_write_u8(struct goodix_softc *sc, uint16_t reg, uint8_t val)
213
{
214
uint8_t buf[3];
215
struct iic_msg msg;
216
217
buf[0] = reg >> 8;
218
buf[1] = reg & 0xFF;
219
buf[2] = val;
220
221
msg.slave = sc->sc_addr;
222
msg.flags = IIC_M_WR;
223
msg.len = 3;
224
msg.buf = buf;
225
226
return (iicbus_transfer(sc->sc_dev, &msg, 1));
227
}
228
229
static int
230
goodix_reset(struct goodix_softc *sc)
231
{
232
uint16_t addr7;
233
bool int_high;
234
int error;
235
236
if (sc->sc_rst_pin == NULL || sc->sc_int_pin == NULL)
237
return (0); /* No GPIOs, skip reset */
238
239
addr7 = goodix_addr_7bit(sc);
240
if (addr7 != 0x14 && addr7 != 0x5d) {
241
device_printf(sc->sc_dev,
242
"unsupported reset address select for I2C addr 0x%02x\n",
243
addr7);
244
return (EINVAL);
245
}
246
int_high = (addr7 == 0x14);
247
248
/* Drive RST low */
249
gpio_pin_setflags(sc->sc_rst_pin, GPIO_PIN_OUTPUT);
250
gpio_pin_set_active(sc->sc_rst_pin, false);
251
DELAY(20000); /* 20ms */
252
253
/* HIGH selects 0x14; LOW selects 0x5d. */
254
gpio_pin_setflags(sc->sc_int_pin, GPIO_PIN_OUTPUT);
255
gpio_pin_set_active(sc->sc_int_pin, int_high);
256
DELAY(100); /* 100us */
257
258
/* Release RST */
259
gpio_pin_set_active(sc->sc_rst_pin, true);
260
DELAY(6000); /* 6ms */
261
262
/* INT sync: drive low 50ms, then set as input */
263
gpio_pin_set_active(sc->sc_int_pin, false);
264
DELAY(50000); /* 50ms */
265
266
error = gpio_pin_setflags(sc->sc_int_pin, GPIO_PIN_INPUT);
267
268
DELAY(50000); /* 50ms settle */
269
return (error);
270
}
271
272
static int
273
goodix_read_version(struct goodix_softc *sc)
274
{
275
uint8_t buf[6];
276
int error;
277
278
error = goodix_read(sc, GOODIX_REG_ID, buf, 6);
279
if (error)
280
return (error);
281
282
memcpy(sc->sc_chip_id, buf, 4);
283
sc->sc_chip_id[4] = '\0';
284
sc->sc_version = le16dec(&buf[4]);
285
286
device_printf(sc->sc_dev, "Goodix chip ID: %c%c%c%c version: %02x%02x\n",
287
buf[0], buf[1], buf[2], buf[3], buf[5], buf[4]);
288
return (0);
289
}
290
291
static int
292
goodix_read_config(struct goodix_softc *sc)
293
{
294
uint8_t cfg[GOODIX_CONFIG_GT9X_LEN];
295
int error;
296
297
error = goodix_read(sc, sc->sc_model->config_addr, cfg,
298
sc->sc_model->config_len);
299
if (error) {
300
device_printf(sc->sc_dev,
301
"Failed to read config at 0x%04x len %u: %d; using fallback geometry\n",
302
sc->sc_model->config_addr, sc->sc_model->config_len, error);
303
sc->sc_max_x = goodix_fallback_x(sc);
304
sc->sc_max_y = goodix_fallback_y(sc);
305
sc->sc_max_touch = sc->sc_model->fallback_touches;
306
return (0);
307
}
308
309
sc->sc_max_x = le16dec(&cfg[1]);
310
sc->sc_max_y = le16dec(&cfg[3]);
311
sc->sc_max_touch = cfg[5] & 0x0F;
312
313
if (sc->sc_max_x == 0)
314
sc->sc_max_x = goodix_fallback_x(sc);
315
if (sc->sc_max_y == 0)
316
sc->sc_max_y = goodix_fallback_y(sc);
317
if (sc->sc_max_touch == 0)
318
sc->sc_max_touch = sc->sc_model->fallback_touches;
319
else if (sc->sc_max_touch > GOODIX_MAX_CONTACTS)
320
sc->sc_max_touch = GOODIX_MAX_CONTACTS;
321
322
device_printf(sc->sc_dev, "Resolution: %dx%d, max touches: %d\n",
323
sc->sc_max_x, sc->sc_max_y, sc->sc_max_touch);
324
return (0);
325
}
326
327
static void goodix_poll(void *arg);
328
329
static void
330
goodix_intr(void *arg)
331
{
332
struct goodix_softc *sc = arg;
333
uint8_t header[1 + GOODIX_CONTACT_SIZE]; /* status + first contact */
334
uint8_t touch_count;
335
uint16_t new_active = 0;
336
int error, i;
337
338
/* Read status byte + first contact */
339
error = goodix_read(sc, GOODIX_REG_STATUS, header, sizeof(header));
340
if (error)
341
goto clear;
342
343
/* Bit 7 = buffer ready */
344
if (!(header[0] & 0x80))
345
goto clear;
346
347
touch_count = header[0] & 0x0F;
348
if (touch_count > sc->sc_max_touch)
349
touch_count = sc->sc_max_touch;
350
351
/* Read remaining contacts if more than 1 */
352
if (touch_count > 1) {
353
error = goodix_read(sc,
354
GOODIX_REG_STATUS + 1 + GOODIX_CONTACT_SIZE,
355
sc->sc_contact_buf,
356
(touch_count - 1) * GOODIX_CONTACT_SIZE);
357
if (error)
358
goto clear;
359
}
360
361
/* Process each touch point */
362
for (i = 0; i < touch_count; i++) {
363
uint8_t *contact;
364
uint8_t id;
365
uint16_t x, y, w;
366
367
if (i == 0)
368
contact = &header[1];
369
else
370
contact = &sc->sc_contact_buf[(i - 1) * GOODIX_CONTACT_SIZE];
371
372
id = contact[0] & 0x0F;
373
x = le16dec(&contact[1]);
374
y = le16dec(&contact[3]);
375
w = le16dec(&contact[5]);
376
377
if (id >= sc->sc_max_touch)
378
continue;
379
380
new_active |= (1 << id);
381
382
evdev_push_abs(sc->sc_evdev, ABS_MT_SLOT, id);
383
evdev_push_abs(sc->sc_evdev, ABS_MT_TRACKING_ID, id);
384
evdev_push_abs(sc->sc_evdev, ABS_MT_POSITION_X, x);
385
evdev_push_abs(sc->sc_evdev, ABS_MT_POSITION_Y, y);
386
evdev_push_abs(sc->sc_evdev, ABS_MT_TOUCH_MAJOR, w);
387
}
388
389
/* Release slots that are no longer active */
390
for (i = 0; i < sc->sc_max_touch; i++) {
391
if ((sc->sc_active_slots & (1 << i)) &&
392
!(new_active & (1 << i))) {
393
evdev_push_abs(sc->sc_evdev, ABS_MT_SLOT, i);
394
evdev_push_abs(sc->sc_evdev, ABS_MT_TRACKING_ID, -1);
395
}
396
}
397
sc->sc_active_slots = new_active;
398
399
/* Report single-touch ABS_X/Y from first contact for libinput */
400
if (touch_count > 0) {
401
evdev_push_abs(sc->sc_evdev, ABS_X,
402
le16dec(&header[1 + 1]));
403
evdev_push_abs(sc->sc_evdev, ABS_Y,
404
le16dec(&header[1 + 3]));
405
}
406
407
evdev_push_key(sc->sc_evdev, BTN_TOUCH, touch_count > 0);
408
evdev_sync(sc->sc_evdev);
409
410
clear:
411
/* Clear status, required by Goodix protocol. */
412
goodix_write_u8(sc, GOODIX_REG_STATUS, 0);
413
414
/* Re-arm polling timer if in polling mode */
415
if (sc->sc_polling)
416
callout_reset(&sc->sc_poll_callout, hz / 100,
417
goodix_poll, sc);
418
}
419
420
static void
421
goodix_poll_task(void *arg, int pending)
422
{
423
struct goodix_softc *sc = arg;
424
425
goodix_intr(sc);
426
}
427
428
static void
429
goodix_poll(void *arg)
430
{
431
struct goodix_softc *sc = arg;
432
433
/*
434
* Callout runs in softclock context where sleeping is prohibited.
435
* Defer the actual I2C work to a taskqueue thread.
436
*/
437
taskqueue_enqueue(taskqueue_thread, &sc->sc_poll_task);
438
}
439
440
static int
441
goodix_probe(device_t dev)
442
{
443
const struct goodix_model *model;
444
445
if (!ofw_bus_status_okay(dev))
446
return (ENXIO);
447
model = goodix_model_for_dev(dev);
448
if (model == NULL)
449
return (ENXIO);
450
451
device_set_desc(dev, model->desc);
452
return (BUS_PROBE_DEFAULT);
453
}
454
455
static int
456
goodix_attach(device_t dev)
457
{
458
struct goodix_softc *sc;
459
struct sysctl_ctx_list *ctx;
460
struct sysctl_oid_list *tree;
461
phandle_t node;
462
int error, rid;
463
464
sc = device_get_softc(dev);
465
sc->sc_dev = dev;
466
sc->sc_model = goodix_model_for_dev(dev);
467
if (sc->sc_model == NULL)
468
return (ENXIO);
469
sc->sc_addr = iicbus_get_addr(dev);
470
sc->sc_addr7 = goodix_addr_7bit(sc);
471
sc->sc_config_addr = sc->sc_model->config_addr;
472
sc->sc_config_len = sc->sc_model->config_len;
473
474
/* Get GPIOs from device tree */
475
node = ofw_bus_get_node(dev);
476
goodix_read_size_prop(node, "touchscreen-size-x", &sc->sc_dt_max_x);
477
goodix_read_size_prop(node, "touchscreen-size-y", &sc->sc_dt_max_y);
478
479
if (bootverbose)
480
device_printf(dev, "OFW node: 0x%x\n", node);
481
482
error = gpio_pin_get_by_ofw_property(dev, node, "reset-gpios",
483
&sc->sc_rst_pin);
484
if (error)
485
device_printf(dev, "No reset GPIO: %d\n", error);
486
487
error = gpio_pin_get_by_ofw_property(dev, node, "irq-gpios",
488
&sc->sc_int_pin);
489
if (error)
490
device_printf(dev, "No IRQ GPIO: %d\n", error);
491
492
/* Reset the controller */
493
error = goodix_reset(sc);
494
if (error)
495
device_printf(dev, "Reset failed: %d (continuing)\n", error);
496
497
/* Read chip ID and version */
498
error = goodix_read_version(sc);
499
if (error) {
500
device_printf(dev, "Failed to read version: %d\n", error);
501
return (error);
502
}
503
504
/* Read config (resolution, max touches) */
505
error = goodix_read_config(sc);
506
if (error)
507
return (error);
508
509
/* Create evdev device */
510
sc->sc_evdev = evdev_alloc();
511
evdev_set_name(sc->sc_evdev, sc->sc_model->evdev_name);
512
evdev_set_phys(sc->sc_evdev, device_get_nameunit(dev));
513
evdev_set_id(sc->sc_evdev, BUS_I2C, 0x0416, sc->sc_model->product,
514
0x0001);
515
516
evdev_support_event(sc->sc_evdev, EV_SYN);
517
evdev_support_event(sc->sc_evdev, EV_ABS);
518
evdev_support_event(sc->sc_evdev, EV_KEY);
519
520
evdev_support_abs(sc->sc_evdev, ABS_MT_SLOT,
521
0, sc->sc_max_touch - 1, 0, 0, 0);
522
evdev_support_abs(sc->sc_evdev, ABS_MT_TRACKING_ID,
523
-1, 65535, 0, 0, 0);
524
evdev_support_abs(sc->sc_evdev, ABS_MT_POSITION_X,
525
0, sc->sc_max_x, 0, 0, 0);
526
evdev_support_abs(sc->sc_evdev, ABS_MT_POSITION_Y,
527
0, sc->sc_max_y, 0, 0, 0);
528
evdev_support_abs(sc->sc_evdev, ABS_MT_TOUCH_MAJOR,
529
0, 255, 0, 0, 0);
530
531
/* Single-touch axes, required for libinput touchscreen classification. */
532
evdev_support_abs(sc->sc_evdev, ABS_X,
533
0, sc->sc_max_x, 0, 0, 0);
534
evdev_support_abs(sc->sc_evdev, ABS_Y,
535
0, sc->sc_max_y, 0, 0, 0);
536
537
evdev_support_key(sc->sc_evdev, BTN_TOUCH);
538
evdev_support_prop(sc->sc_evdev, INPUT_PROP_DIRECT);
539
540
error = evdev_register(sc->sc_evdev);
541
if (error) {
542
device_printf(dev, "evdev register failed: %d\n", error);
543
evdev_free(sc->sc_evdev);
544
return (error);
545
}
546
547
/*
548
* Setup interrupt. ofw_iicbus_attach already populated our
549
* resource list with the IRQ derived from the FDT `interrupts`
550
* property mapped through the gpio3 PIC. The matching kernel-side
551
* fix is patches/.../rk_i2c.c.patch. Without that, rk_i2c's
552
* device class (which lacks bus_* method passthroughs) blackholes
553
* the alloc and we silently fall back to polling.
554
*/
555
rid = 0;
556
sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
557
RF_ACTIVE);
558
if (sc->sc_irq_res != NULL) {
559
if (sc->sc_int_pin != NULL)
560
gpio_pin_setflags(sc->sc_int_pin, GPIO_PIN_INPUT);
561
error = bus_setup_intr(dev, sc->sc_irq_res,
562
INTR_TYPE_MISC | INTR_MPSAFE,
563
NULL, goodix_intr, sc, &sc->sc_irq_hdl);
564
if (error) {
565
device_printf(dev,
566
"bus_setup_intr failed: %d\n", error);
567
bus_release_resource(dev, SYS_RES_IRQ, rid,
568
sc->sc_irq_res);
569
sc->sc_irq_res = NULL;
570
} else {
571
device_printf(dev,
572
"IRQ mode enabled (irq %ju)\n",
573
(uintmax_t)rman_get_start(sc->sc_irq_res));
574
}
575
} else {
576
device_printf(dev,
577
"bus_alloc_resource_any(SYS_RES_IRQ) returned NULL "
578
"- check rk_i2c.c.patch is applied\n");
579
}
580
581
if (sc->sc_irq_res == NULL) {
582
/*
583
* No IRQ available, fall back to polling mode.
584
* Poll every 10ms (100 Hz) for responsive touch.
585
*/
586
device_printf(dev, "Using polling mode (no IRQ)\n");
587
callout_init(&sc->sc_poll_callout, 1);
588
TASK_INIT(&sc->sc_poll_task, 0, goodix_poll_task, sc);
589
sc->sc_polling = 1;
590
callout_reset(&sc->sc_poll_callout, hz / 100,
591
goodix_poll, sc);
592
}
593
594
ctx = device_get_sysctl_ctx(dev);
595
tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
596
SYSCTL_ADD_STRING(ctx, tree, OID_AUTO, "chip_id",
597
CTLFLAG_RD | CTLFLAG_MPSAFE, sc->sc_chip_id, 0,
598
"Goodix chip ID string");
599
SYSCTL_ADD_U16(ctx, tree, OID_AUTO, "version",
600
CTLFLAG_RD | CTLFLAG_MPSAFE, &sc->sc_version, 0,
601
"Goodix firmware version");
602
SYSCTL_ADD_U16(ctx, tree, OID_AUTO, "i2c_addr_7bit",
603
CTLFLAG_RD | CTLFLAG_MPSAFE, &sc->sc_addr7, 0,
604
"7-bit I2C address selected by reset sequence");
605
SYSCTL_ADD_U16(ctx, tree, OID_AUTO, "config_addr",
606
CTLFLAG_RD | CTLFLAG_MPSAFE, &sc->sc_config_addr, 0,
607
"Goodix config register address");
608
SYSCTL_ADD_U16(ctx, tree, OID_AUTO, "config_len",
609
CTLFLAG_RD | CTLFLAG_MPSAFE, &sc->sc_config_len, 0,
610
"Goodix config register length");
611
SYSCTL_ADD_U16(ctx, tree, OID_AUTO, "max_x",
612
CTLFLAG_RD | CTLFLAG_MPSAFE, &sc->sc_max_x, 0,
613
"Touchscreen X coordinate maximum");
614
SYSCTL_ADD_U16(ctx, tree, OID_AUTO, "max_y",
615
CTLFLAG_RD | CTLFLAG_MPSAFE, &sc->sc_max_y, 0,
616
"Touchscreen Y coordinate maximum");
617
SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "max_touch",
618
CTLFLAG_RD | CTLFLAG_MPSAFE, &sc->sc_max_touch, 0,
619
"Maximum touch contacts");
620
SYSCTL_ADD_U8(ctx, tree, OID_AUTO, "polling",
621
CTLFLAG_RD | CTLFLAG_MPSAFE, &sc->sc_polling, 0,
622
"Polling fallback active");
623
624
device_printf(dev, "Goodix touchscreen attached\n");
625
return (0);
626
}
627
628
static int
629
goodix_detach(device_t dev)
630
{
631
struct goodix_softc *sc = device_get_softc(dev);
632
633
if (sc->sc_irq_hdl != NULL)
634
bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_hdl);
635
if (sc->sc_irq_res != NULL)
636
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
637
if (sc->sc_polling) {
638
callout_drain(&sc->sc_poll_callout);
639
taskqueue_drain(taskqueue_thread, &sc->sc_poll_task);
640
}
641
if (sc->sc_evdev != NULL)
642
evdev_free(sc->sc_evdev);
643
return (0);
644
}
645
646
static device_method_t goodix_methods[] = {
647
DEVMETHOD(device_probe, goodix_probe),
648
DEVMETHOD(device_attach, goodix_attach),
649
DEVMETHOD(device_detach, goodix_detach),
650
DEVMETHOD_END
651
};
652
653
static driver_t goodix_driver = {
654
"goodix",
655
goodix_methods,
656
sizeof(struct goodix_softc),
657
};
658
659
DRIVER_MODULE(goodix, iicbus, goodix_driver, NULL, NULL);
660
MODULE_DEPEND(goodix, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
661
MODULE_DEPEND(goodix, evdev, 1, 1, 1);
662
MODULE_VERSION(goodix, 1);
663
IICBUS_FDT_PNP_INFO(goodix_compat);
664
The address-select behavior matters for PineTab2. The Goodix reset
sequence samples INT while reset is deasserted: INT high selects the
0x14 address used by the PinePhone Pro, while INT low selects the
0x5d address used by PineTab2.
The driver now exposes first-boot receipt sysctls:
dev.goodix.0.chip_iddev.goodix.0.versiondev.goodix.0.i2c_addr_7bitdev.goodix.0.config_addrdev.goodix.0.config_lendev.goodix.0.max_xdev.goodix.0.max_ydev.goodix.0.max_touchdev.goodix.0.polling
Bring-Up Predicate
After booting the PineTab2 kernel:
dmesg | grep -i goodix
sysctl dev.goodix.0
libinput list-devices
Expected first-pass evidence:
goodix0attaches as aGoodix GT911 Touchscreen.chip_idis911or another GT9xx-compatible ID from the same controller family.i2c_addr_7bitis93(0x5d).config_addris32839(0x8047) andconfig_lenis186.pollingis0if the GPIO IRQ path works;1is acceptable for first I2C proof but should be fixed before touch becomes user-facing.
Open Work
- Verify GT911 ID/version and config geometry on hardware.
- Confirm GPIO0_B0 interrupt delivery on RK3566.
- Map touch orientation against the BOE panel once DSI is enabled.
- Add suspend/resume power policy later; first bring-up keeps raw touch functionality ahead of power savings.