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