1 /* $NetBSD: ztp.c,v 1.17 2023/12/20 15:34:46 thorpej Exp $ */
2 /* $OpenBSD: zts.c,v 1.9 2005/04/24 18:55:49 uwe Exp $ */
3
4 /*
5 * Copyright (c) 2005 Dale Rahn <drahn@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/cdefs.h>
21 __KERNEL_RCSID(0, "$NetBSD: ztp.c,v 1.17 2023/12/20 15:34:46 thorpej Exp $");
22
23 #include "lcd.h"
24 #include "w100lcd.h"
25
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/device.h>
30 #include <sys/kernel.h>
31 #include <sys/callout.h>
32
33 #include <dev/wscons/wsconsio.h>
34 #include <dev/wscons/wsmousevar.h>
35 #include <dev/wscons/wsdisplayvar.h>
36
37 #include <dev/hpc/hpcfbio.h> /* XXX: for tpctl */
38 #include <dev/hpc/hpctpanelvar.h>
39
40 #include <arm/xscale/pxa2x0cpu.h>
41 #include <arm/xscale/pxa2x0reg.h>
42 #include <arm/xscale/pxa2x0var.h>
43 #include <arm/xscale/xscalereg.h>
44 #include <arm/xscale/pxa2x0_gpio.h>
45 #if NLCD > 0
46 #include <arm/xscale/pxa2x0_lcd.h>
47 #endif
48 #if NW100LCD > 0
49 #include <zaurus/dev/w100var.h>
50 #endif
51
52 #include <zaurus/zaurus/zaurus_var.h>
53 #include <zaurus/dev/zsspvar.h>
54 #ifdef ZTP_DEBUG
55 #define DPRINTF(s) printf s
56 #else
57 #define DPRINTF(s)
58 #endif
59
60 /*
61 * ADS784x touch screen controller
62 */
63 #define ADSCTRL_PD0_SH 0 /* PD0 bit */
64 #define ADSCTRL_PD1_SH 1 /* PD1 bit */
65 #define ADSCTRL_DFR_SH 2 /* SER/DFR bit */
66 #define ADSCTRL_MOD_SH 3 /* Mode bit */
67 #define ADSCTRL_ADR_SH 4 /* Address setting */
68 #define ADSCTRL_STS_SH 7 /* Start bit */
69
70 #define GPIO_TP_INT_C3K 11
71 #define GPIO_HSYNC_C3K 22
72 #define GPIO_TP_INT_C860 5
73 #define GPIO_HSYNC_C860 44
74
75 #define POLL_TIMEOUT_RATE0 ((hz * 150)/1000)
76 #define POLL_TIMEOUT_RATE1 (hz / 100) /* XXX every tick */
77
78 #define CCNT_HS_400_VGA_C3K 6250 /* 15.024us */
79 #define CCNT_HS_400_VGA_C860 7013 /* 17.615us */
80
81 /* XXX need to ask lcd drivers for the screen dimension */
82 #if NLCD > 0
83 extern const struct lcd_panel_geometry lcd_panel_geometry_c3000;
84 #endif
85 #if NW100LCD > 0
86 extern const struct w100_panel_geometry lcd_panel_geometry_c700;
87 #endif
88
89 /* Settable via sysctl. */
90 int ztp_rawmode;
91
92 static const struct wsmouse_calibcoords ztp_default_calib = {
93 0, 0, 479, 639, /* minx, miny, maxx, maxy */
94 5, /* samplelen */
95 {
96 { 1929, 2021, 240, 320 }, /* rawx, rawy, x, y */
97 { 545, 3464, 48, 64 },
98 { 3308, 3452, 48, 576 },
99 { 2854, 768, 432, 576 },
100 { 542, 593, 432, 64 }
101 }
102 };
103
104 struct ztp_pos {
105 int x;
106 int y;
107 int z; /* touch pressure */
108 };
109
110 struct ztp_softc {
111 device_t sc_dev;
112 struct callout sc_tp_poll;
113 void *sc_gh;
114 int sc_enabled;
115 int sc_buttons; /* button emulation ? */
116 device_t sc_wsmousedev;
117 struct ztp_pos sc_oldpos;
118 int sc_resx;
119 int sc_resy;
120 struct tpcalib_softc sc_tpcalib;
121
122 u_int sc_tp_int_pin;
123 u_int sc_hsync_pin;
124 u_int sc_ccnt_hs;
125 };
126
127 static int ztp_match(device_t, cfdata_t, void *);
128 static void ztp_attach(device_t, device_t, void *);
129
130 CFATTACH_DECL_NEW(ztp, sizeof(struct ztp_softc),
131 ztp_match, ztp_attach, NULL, NULL);
132
133 static int ztp_finalize(device_t);
134 static int ztp_enable(void *);
135 static void ztp_disable(void *);
136 static bool ztp_suspend(device_t dv, const pmf_qual_t *);
137 static bool ztp_resume(device_t dv, const pmf_qual_t *);
138 static void ztp_poll(void *);
139 static int ztp_irq(void *);
140 static int ztp_ioctl(void *, u_long, void *, int, struct lwp *);
141
142 static const struct wsmouse_accessops ztp_accessops = {
143 ztp_enable,
144 ztp_ioctl,
145 ztp_disable
146 };
147
148 static int
ztp_match(device_t parent,cfdata_t cf,void * aux)149 ztp_match(device_t parent, cfdata_t cf, void *aux)
150 {
151 struct zssp_attach_args *aa = aux;
152
153 if (strcmp("ztp", aa->zaa_name))
154 return 0;
155 return 1;
156 }
157
158 static void
ztp_attach(device_t parent,device_t self,void * aux)159 ztp_attach(device_t parent, device_t self, void *aux)
160 {
161 struct ztp_softc *sc = device_private(self);
162 struct wsmousedev_attach_args a;
163
164 sc->sc_dev = self;
165
166 aprint_normal("\n");
167 aprint_naive("\n");
168
169 callout_init(&sc->sc_tp_poll, 0);
170 callout_setfunc(&sc->sc_tp_poll, ztp_poll, sc);
171
172 /* defer initialization until all other devices are attached */
173 config_finalize_register(self, ztp_finalize);
174
175 a.accessops = &ztp_accessops;
176 a.accesscookie = sc;
177
178 #if NLCD > 0 || NW100LCD > 0 /* XXX */
179 #if NLCD > 0
180 if (ZAURUS_ISC1000 || ZAURUS_ISC3000) {
181 sc->sc_resx = lcd_panel_geometry_c3000.panel_height;
182 sc->sc_resy = lcd_panel_geometry_c3000.panel_width;
183 } else
184 #endif
185 #if NW100LCD > 0
186 if (ZAURUS_ISC860) {
187 sc->sc_resx = lcd_panel_geometry_c700.panel_height;
188 sc->sc_resy = lcd_panel_geometry_c700.panel_width;
189 } else
190 #endif
191 #endif
192 {
193 sc->sc_resx = 480; /* XXX */
194 sc->sc_resy = 640; /* XXX */
195 }
196
197 if (ZAURUS_ISC1000 || ZAURUS_ISC3000) {
198 sc->sc_tp_int_pin = GPIO_TP_INT_C3K;
199 sc->sc_hsync_pin = GPIO_HSYNC_C3K;
200 sc->sc_ccnt_hs = CCNT_HS_400_VGA_C3K;
201 } else {
202 /* C7x0/C860 */
203 sc->sc_tp_int_pin = GPIO_TP_INT_C860;
204 sc->sc_hsync_pin = GPIO_HSYNC_C860;
205 sc->sc_ccnt_hs = CCNT_HS_400_VGA_C860;
206 }
207
208 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint, CFARGS_NONE);
209
210 /* Initialize calibration, set default parameters. */
211 tpcalib_init(&sc->sc_tpcalib);
212 tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
213 __UNCONST(&ztp_default_calib), 0, 0);
214 }
215
216 static int
ztp_finalize(device_t dv)217 ztp_finalize(device_t dv)
218 {
219
220 /* Initialize ADS7846 Difference Reference mode */
221 (void)zssp_ic_send(ZSSP_IC_ADS7846,
222 (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
223 delay(5000);
224 (void)zssp_ic_send(ZSSP_IC_ADS7846,
225 (3<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
226 delay(5000);
227 (void)zssp_ic_send(ZSSP_IC_ADS7846,
228 (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
229 delay(5000);
230 (void)zssp_ic_send(ZSSP_IC_ADS7846,
231 (5<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
232 delay(5000);
233
234 return 0;
235 }
236
237 static int
ztp_enable(void * v)238 ztp_enable(void *v)
239 {
240 struct ztp_softc *sc = (struct ztp_softc *)v;
241
242 DPRINTF(("%s: ztp_enable()\n", device_xname(sc->sc_dev)));
243
244 if (sc->sc_enabled) {
245 DPRINTF(("%s: already enabled\n", device_xname(sc->sc_dev)));
246 return EBUSY;
247 }
248
249 callout_stop(&sc->sc_tp_poll);
250
251 if (!pmf_device_register(sc->sc_dev, ztp_suspend, ztp_resume))
252 aprint_error_dev(sc->sc_dev,
253 "couldn't establish power handler\n");
254
255 pxa2x0_gpio_set_function(sc->sc_tp_int_pin, GPIO_IN);
256
257 /* XXX */
258 if (sc->sc_gh == NULL) {
259 sc->sc_gh = pxa2x0_gpio_intr_establish(sc->sc_tp_int_pin,
260 IST_EDGE_FALLING, IPL_TTY, ztp_irq, sc);
261 } else {
262 pxa2x0_gpio_intr_unmask(sc->sc_gh);
263 }
264
265 /* enable interrupts */
266 sc->sc_enabled = 1;
267 sc->sc_buttons = 0;
268
269 return 0;
270 }
271
272 static void
ztp_disable(void * v)273 ztp_disable(void *v)
274 {
275 struct ztp_softc *sc = (struct ztp_softc *)v;
276
277 DPRINTF(("%s: ztp_disable()\n", device_xname(sc->sc_dev)));
278
279 callout_stop(&sc->sc_tp_poll);
280
281 pmf_device_deregister(sc->sc_dev);
282
283 if (sc->sc_gh) {
284 pxa2x0_gpio_intr_mask(sc->sc_gh);
285 }
286
287 /* disable interrupts */
288 sc->sc_enabled = 0;
289 }
290
291 static bool
ztp_suspend(device_t dv,const pmf_qual_t * qual)292 ztp_suspend(device_t dv, const pmf_qual_t *qual)
293 {
294 struct ztp_softc *sc = device_private(dv);
295
296 DPRINTF(("%s: ztp_suspend()\n", device_xname(sc->sc_dev)));
297
298 sc->sc_enabled = 0;
299 pxa2x0_gpio_intr_mask(sc->sc_gh);
300
301 callout_stop(&sc->sc_tp_poll);
302
303 /* Turn off reference voltage but leave ADC on. */
304 (void)zssp_ic_send(ZSSP_IC_ADS7846, (1 << ADSCTRL_PD1_SH) |
305 (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH));
306
307 pxa2x0_gpio_set_function(sc->sc_tp_int_pin, GPIO_OUT | GPIO_SET);
308
309 return true;
310 }
311
312 static bool
ztp_resume(device_t dv,const pmf_qual_t * qual)313 ztp_resume(device_t dv, const pmf_qual_t *qual)
314 {
315 struct ztp_softc *sc = device_private(dv);
316
317 DPRINTF(("%s: ztp_resume()\n", device_xname(sc->sc_dev)));
318
319 pxa2x0_gpio_set_function(sc->sc_tp_int_pin, GPIO_IN);
320 pxa2x0_gpio_intr_mask(sc->sc_gh);
321
322 /* Enable automatic low power mode. */
323 (void)zssp_ic_send(ZSSP_IC_ADS7846,
324 (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH));
325
326 pxa2x0_gpio_intr_unmask(sc->sc_gh);
327 sc->sc_enabled = 1;
328
329 return true;
330 }
331
332 #define HSYNC() \
333 do { \
334 while (pxa2x0_gpio_get_bit(sc->sc_hsync_pin) == 0) \
335 continue; \
336 while (pxa2x0_gpio_get_bit(sc->sc_hsync_pin) != 0) \
337 continue; \
338 } while (/*CONSTCOND*/0)
339
340 static inline uint32_t pxa2x0_ccnt_enable(uint32_t);
341 static inline uint32_t pxa2x0_read_ccnt(void);
342 static uint32_t ztp_sync_ads784x(struct ztp_softc *, int, int, uint32_t);
343 static void ztp_sync_send(struct ztp_softc *, uint32_t);
344 static int ztp_readpos(struct ztp_softc *, struct ztp_pos *);
345
346 static inline uint32_t
pxa2x0_ccnt_enable(uint32_t reg)347 pxa2x0_ccnt_enable(uint32_t reg)
348 {
349 uint32_t rv;
350
351 __asm volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (rv));
352 __asm volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (reg));
353
354 return rv;
355 }
356
357 static inline uint32_t
pxa2x0_read_ccnt(void)358 pxa2x0_read_ccnt(void)
359 {
360 uint32_t rv;
361
362 __asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (rv));
363
364 return rv;
365 }
366
367 /*
368 * Communicate synchronously with the ADS784x touch screen controller.
369 */
370 static uint32_t
ztp_sync_ads784x(struct ztp_softc * sc,int dorecv,int dosend,uint32_t cmd)371 ztp_sync_ads784x(struct ztp_softc *sc, int dorecv/* XXX */,
372 int dosend/* XXX */, uint32_t cmd)
373 {
374 uint32_t ccen;
375 uint32_t rv = 0;
376
377 /* XXX poll hsync only if LCD is enabled */
378
379 /* start clock counter */
380 ccen = pxa2x0_ccnt_enable(PMNC_E);
381
382 HSYNC();
383
384 if (dorecv) {
385 /* read SSDR and disable ADS784x */
386 rv = zssp_ic_stop(ZSSP_IC_ADS7846);
387 }
388
389 if (dosend) {
390 ztp_sync_send(sc, cmd);
391 }
392
393 /* stop clock counter */
394 pxa2x0_ccnt_enable(ccen);
395
396 return rv;
397 }
398
399 void
ztp_sync_send(struct ztp_softc * sc,uint32_t cmd)400 ztp_sync_send(struct ztp_softc *sc, uint32_t cmd)
401 {
402 volatile uint32_t base, now;
403 uint32_t tck;
404
405 /* XXX */
406 tck = sc->sc_ccnt_hs - 151;
407 /* XXX: for one more delay(1) */
408 tck -= 400;
409
410 /* send dummy command; discard SSDR */
411 (void)zssp_ic_send(ZSSP_IC_ADS7846, cmd);
412
413 /* wait for refresh */
414 HSYNC();
415
416 /* wait after refresh */
417 base = pxa2x0_read_ccnt();
418 now = pxa2x0_read_ccnt();
419 while ((now - base) < tck)
420 now = pxa2x0_read_ccnt();
421
422 /* send the actual command; keep ADS784x enabled */
423 zssp_ic_start(ZSSP_IC_ADS7846, cmd);
424 }
425
426 static int
ztp_readpos(struct ztp_softc * sc,struct ztp_pos * pos)427 ztp_readpos(struct ztp_softc *sc, struct ztp_pos *pos)
428 {
429 int cmd;
430 int t0, t1;
431 int down;
432
433 /* XXX */
434 pxa2x0_gpio_set_function(sc->sc_hsync_pin, GPIO_IN);
435
436 /* check that pen is down */
437 cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
438 (3 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
439 t0 = zssp_ic_send(ZSSP_IC_ADS7846, cmd);
440 DPRINTF(("ztp_readpos(): t0 = %d\n", t0));
441
442 down = (t0 >= 10);
443 if (down == 0)
444 goto out;
445
446 /* Y */
447 cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
448 (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
449 (void)ztp_sync_ads784x(sc, 0, 1, cmd);
450
451 /* Y */
452 cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
453 (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
454 (void)ztp_sync_ads784x(sc, 1, 1, cmd);
455
456 /* X */
457 cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
458 (5 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
459 pos->y = ztp_sync_ads784x(sc, 1, 1, cmd);
460 DPRINTF(("ztp_readpos(): y = %d\n", pos->y));
461
462 /* T0 */
463 cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
464 (3 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
465 pos->x = ztp_sync_ads784x(sc, 1, 1, cmd);
466 DPRINTF(("ztp_readpos(): x = %d\n", pos->x));
467
468 /* T1 */
469 cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
470 (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
471 t0 = ztp_sync_ads784x(sc, 1, 1, cmd);
472 t1 = ztp_sync_ads784x(sc, 1, 0, cmd);
473 DPRINTF(("ztp_readpos(): t0 = %d, t1 = %d\n", t0, t1));
474
475 /* check that pen is still down */
476 /* XXX pressure sensitivity varies with X or what? */
477 if (t0 == 0 || (pos->x * (t1 - t0) / t0) >= 15000)
478 down = 0;
479 pos->z = down;
480
481 out:
482 /* Enable automatic low power mode. */
483 cmd = (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
484 (void)zssp_ic_send(ZSSP_IC_ADS7846, cmd);
485
486 return down;
487 }
488
489 static void
ztp_poll(void * v)490 ztp_poll(void *v)
491 {
492 int s;
493
494 s = spltty();
495 (void)ztp_irq(v);
496 splx(s);
497 }
498
499 static int
ztp_irq(void * v)500 ztp_irq(void *v)
501 {
502 extern int zkbd_modstate;
503 struct ztp_softc *sc = (struct ztp_softc *)v;
504 struct ztp_pos tp = { 0, 0, 0 };
505 int pindown;
506 int down;
507 int x, y;
508 int s;
509
510 if (!sc->sc_enabled)
511 return 0;
512
513 s = splhigh();
514
515 pindown = pxa2x0_gpio_get_bit(sc->sc_tp_int_pin) ? 0 : 1;
516 DPRINTF(("%s: pindown = %d\n", device_xname(sc->sc_dev), pindown));
517 if (pindown) {
518 pxa2x0_gpio_intr_mask(sc->sc_gh);
519 callout_schedule(&sc->sc_tp_poll, POLL_TIMEOUT_RATE1);
520 }
521
522 down = ztp_readpos(sc, &tp);
523 DPRINTF(("%s: x = %d, y = %d, z = %d, down = %d\n",
524 device_xname(sc->sc_dev), tp.x, tp.y, tp.z, down));
525
526 if (!pindown) {
527 pxa2x0_gpio_intr_unmask(sc->sc_gh);
528 callout_schedule(&sc->sc_tp_poll, POLL_TIMEOUT_RATE0);
529 }
530 pxa2x0_gpio_clear_intr(sc->sc_tp_int_pin);
531
532 splx(s);
533
534 if (down) {
535 if (!ztp_rawmode) {
536 tpcalib_trans(&sc->sc_tpcalib, tp.x, tp.y, &x, &y);
537 DPRINTF(("%s: x = %d, y = %d\n",
538 device_xname(sc->sc_dev), x, y));
539 tp.x = x;
540 tp.y = y;
541 }
542 }
543
544 if (zkbd_modstate != 0 && down) {
545 if (zkbd_modstate & (1 << 1)) {
546 /* Fn */
547 down = 2;
548 } else if (zkbd_modstate & (1 << 2)) {
549 /* 'Alt' */
550 down = 4;
551 }
552 }
553 if (!down) {
554 /* x/y values are not reliable when pen is up */
555 tp = sc->sc_oldpos;
556 }
557
558 if (down || sc->sc_buttons != down) {
559 wsmouse_input(sc->sc_wsmousedev, down, tp.x, tp.y, 0, 0,
560 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
561 sc->sc_buttons = down;
562 sc->sc_oldpos = tp;
563 }
564
565 return 1;
566 }
567
568 static int
ztp_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)569 ztp_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
570 {
571 struct ztp_softc *sc = (struct ztp_softc *)v;
572 struct wsmouse_id *id;
573
574 switch (cmd) {
575 case WSMOUSEIO_GTYPE:
576 *(u_int *)data = WSMOUSE_TYPE_TPANEL;
577 return 0;
578
579 case WSMOUSEIO_GETID:
580 /*
581 * return unique ID string,
582 * "<vendor> <model> <serial number>"
583 */
584 id = (struct wsmouse_id *)data;
585 if (id->type != WSMOUSE_ID_TYPE_UIDSTR)
586 return EINVAL;
587 strlcpy(id->data, "Sharp SL-C3x00 SN000000", WSMOUSE_ID_MAXLEN);
588 id->length = strlen(id->data);
589 return 0;
590
591 case WSMOUSEIO_SCALIBCOORDS:
592 case WSMOUSEIO_GCALIBCOORDS:
593 return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
594 }
595
596 return EPASSTHROUGH;
597 }
598