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