Annotation of sys/arch/zaurus/dev/zts.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: zts.c,v 1.11 2007/05/29 21:09:43 robert Exp $ */
2: /*
3: * Copyright (c) 2005 Dale Rahn <drahn@openbsd.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: #include <sys/types.h>
19: #include <sys/param.h>
20: #include <sys/systm.h>
21: #include <sys/device.h>
22: #include <sys/malloc.h>
23: #include <sys/timeout.h>
24: #include <sys/kernel.h>
25:
26: #include <arm/xscale/pxa2x0reg.h>
27: #include <arm/xscale/pxa2x0_gpio.h>
28:
29: #include <zaurus/dev/zaurus_sspvar.h>
30:
31: #include <dev/wscons/wsconsio.h>
32: #include <dev/wscons/wsmousevar.h>
33:
34: #include <dev/wscons/wsdisplayvar.h>
35: #include <arm/xscale/pxa2x0var.h>
36: #include <arm/xscale/pxa2x0_lcd.h>
37:
38: #ifdef ZTS_DEBUG
39: #define DPRINTF(x) do { printf x; } while (0)
40: #else
41: #define DPRINTF(x)
42: #endif
43:
44: /*
45: * ADS784x touch screen controller
46: */
47: #define ADSCTRL_PD0_SH 0 /* PD0 bit */
48: #define ADSCTRL_PD1_SH 1 /* PD1 bit */
49: #define ADSCTRL_DFR_SH 2 /* SER/DFR bit */
50: #define ADSCTRL_MOD_SH 3 /* Mode bit */
51: #define ADSCTRL_ADR_SH 4 /* Address setting */
52: #define ADSCTRL_STS_SH 7 /* Start bit */
53:
54: #define GPIO_TP_INT_C3K 11
55: #define GPIO_HSYNC_C3K 22
56:
57: #define POLL_TIMEOUT_RATE0 ((hz * 150)/1000)
58: #define POLL_TIMEOUT_RATE1 (hz / 100) /* XXX every tick */
59:
60: #define CCNT_HS_400_VGA_C3K 6250 /* 15.024us */
61:
62: struct tsscale {
63: int minx, maxx;
64: int miny, maxy;
65: int swapxy;
66: int resx, resy;
67: } zts_scale = {
68: /* C3000 */
69: 209, 3620, 312, 3780, 0, 640, 480
70: };
71:
72: int zts_match(struct device *, void *, void *);
73: void zts_attach(struct device *, struct device *, void *);
74: int zts_enable(void *);
75: void zts_disable(void *);
76: void zts_power(int, void *);
77: void zts_poll(void *);
78: int zts_irq(void *);
79: int zts_ioctl(void *, u_long, caddr_t, int, struct proc *);
80:
81: struct zts_softc {
82: struct device sc_dev;
83: struct timeout sc_ts_poll;
84: void *sc_gh;
85: void *sc_powerhook;
86: int sc_enabled;
87: int sc_buttons; /* button emulation ? */
88: struct device *sc_wsmousedev;
89: int sc_oldx;
90: int sc_oldy;
91: int sc_rawmode;
92:
93: struct tsscale sc_tsscale;
94: };
95:
96: struct cfattach zts_ca = {
97: sizeof(struct zts_softc), zts_match, zts_attach
98: };
99:
100: struct cfdriver zts_cd = {
101: NULL, "zts", DV_DULL
102: };
103:
104: int
105: zts_match(struct device *parent, void *cf, void *aux)
106: {
107: return 1;
108: }
109:
110: const struct wsmouse_accessops zts_accessops = {
111: zts_enable,
112: zts_ioctl,
113: zts_disable
114: };
115:
116: void
117: zts_attach(struct device *parent, struct device *self, void *aux)
118: {
119: struct zts_softc *sc = (struct zts_softc *)self;
120: struct wsmousedev_attach_args a;
121:
122: timeout_set(&sc->sc_ts_poll, zts_poll, sc);
123:
124: /* Initialize ADS7846 Difference Reference mode */
125: (void)zssp_ic_send(ZSSP_IC_ADS7846,
126: (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
127: delay(5000);
128: (void)zssp_ic_send(ZSSP_IC_ADS7846,
129: (3<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
130: delay(5000);
131: (void)zssp_ic_send(ZSSP_IC_ADS7846,
132: (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
133: delay(5000);
134: (void)zssp_ic_send(ZSSP_IC_ADS7846,
135: (5<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH));
136: delay(5000);
137:
138: a.accessops = &zts_accessops;
139: a.accesscookie = sc;
140: printf("\n");
141:
142: /* Copy the default scalue values to each softc */
143: bcopy(&zts_scale, &sc->sc_tsscale, sizeof(sc->sc_tsscale));
144:
145: sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
146: }
147:
148: int
149: zts_enable(void *v)
150: {
151: struct zts_softc *sc = v;
152:
153: if (sc->sc_enabled)
154: return EBUSY;
155:
156: timeout_del(&sc->sc_ts_poll);
157:
158: sc->sc_powerhook = powerhook_establish(zts_power, sc);
159: if (sc->sc_powerhook == NULL) {
160: printf("%s: enable failed\n", sc->sc_dev.dv_xname);
161: return ENOMEM;
162: }
163:
164: pxa2x0_gpio_set_function(GPIO_TP_INT_C3K, GPIO_IN);
165:
166: /* XXX */
167: if (sc->sc_gh == NULL)
168: sc->sc_gh = pxa2x0_gpio_intr_establish(GPIO_TP_INT_C3K,
169: IST_EDGE_FALLING, IPL_TTY, zts_irq, sc,
170: sc->sc_dev.dv_xname);
171: else
172: pxa2x0_gpio_intr_unmask(sc->sc_gh);
173:
174: /* enable interrupts */
175: sc->sc_enabled = 1;
176: sc->sc_buttons = 0;
177:
178: return 0;
179: }
180:
181: void
182: zts_disable(void *v)
183: {
184: struct zts_softc *sc = v;
185:
186: timeout_del(&sc->sc_ts_poll);
187:
188: if (sc->sc_powerhook != NULL) {
189: powerhook_disestablish(sc->sc_powerhook);
190: sc->sc_powerhook = NULL;
191: }
192:
193: if (sc->sc_gh != NULL) {
194: #if 0
195: pxa2x0_gpio_intr_disestablish(sc->sc_gh);
196: sc->sc_gh = NULL;
197: #endif
198: }
199:
200: /* disable interrupts */
201: sc->sc_enabled = 0;
202: }
203:
204: void
205: zts_power(int why, void *v)
206: {
207: struct zts_softc *sc = v;
208:
209: switch (why) {
210: case PWR_STANDBY:
211: case PWR_SUSPEND:
212: sc->sc_enabled = 0;
213: #if 0
214: pxa2x0_gpio_intr_disestablish(sc->sc_gh);
215: #endif
216: timeout_del(&sc->sc_ts_poll);
217:
218: pxa2x0_gpio_intr_mask(sc->sc_gh);
219:
220: /* Turn off reference voltage but leave ADC on. */
221: (void)zssp_ic_send(ZSSP_IC_ADS7846, (1 << ADSCTRL_PD1_SH) |
222: (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH));
223:
224: pxa2x0_gpio_set_function(GPIO_TP_INT_C3K,
225: GPIO_OUT | GPIO_SET);
226: break;
227:
228: case PWR_RESUME:
229: pxa2x0_gpio_set_function(GPIO_TP_INT_C3K, GPIO_IN);
230: pxa2x0_gpio_intr_mask(sc->sc_gh);
231:
232: /* Enable automatic low power mode. */
233: (void)zssp_ic_send(ZSSP_IC_ADS7846,
234: (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH));
235:
236: #if 0
237: sc->sc_gh = pxa2x0_gpio_intr_establish(GPIO_TP_INT_C3K,
238: IST_EDGE_FALLING, IPL_TTY, zts_irq, sc,
239: sc->sc_dev.dv_xname);
240: #else
241: pxa2x0_gpio_intr_unmask(sc->sc_gh);
242: #endif
243: sc->sc_enabled = 1;
244: break;
245: }
246: }
247:
248: struct zts_pos {
249: int x;
250: int y;
251: int z; /* touch pressure */
252: };
253:
254: #define NSAMPLES 3
255: struct zts_pos zts_samples[NSAMPLES];
256: int ztsavgloaded = 0;
257:
258: int zts_readpos(struct zts_pos *);
259: void zts_avgpos(struct zts_pos *);
260:
261: #define HSYNC() \
262: do { \
263: while (pxa2x0_gpio_get_bit(GPIO_HSYNC_C3K) == 0); \
264: while (pxa2x0_gpio_get_bit(GPIO_HSYNC_C3K) != 0); \
265: } while (0)
266:
267: int pxa2x0_ccnt_enable(int);
268: u_int32_t pxa2x0_read_ccnt(void);
269: u_int32_t zts_sync_ads784x(int, int, u_int32_t);
270: void zts_sync_send(u_int32_t);
271:
272: int
273: pxa2x0_ccnt_enable(int on)
274: {
275: u_int32_t rv;
276:
277: on = on ? 0x1 : 0x0;
278: __asm __volatile("mrc p14, 0, %0, c0, c1, 0" : "=r" (rv));
279: __asm __volatile("mcr p14, 0, %0, c0, c1, 0" : : "r" (on));
280: return ((int)(rv & 0x1));
281: }
282:
283: u_int32_t
284: pxa2x0_read_ccnt(void)
285: {
286: u_int32_t rv;
287:
288: __asm __volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (rv));
289: return (rv);
290: }
291:
292: /*
293: * Communicate synchronously with the ADS784x touch screen controller.
294: */
295: u_int32_t
296: zts_sync_ads784x(int dorecv/* XXX */, int dosend/* XXX */, u_int32_t cmd)
297: {
298: int ccen;
299: u_int32_t rv;
300:
301: /* XXX poll hsync only if LCD is enabled */
302:
303: /* start clock counter */
304: ccen = pxa2x0_ccnt_enable(1);
305:
306: HSYNC();
307:
308: if (dorecv)
309: /* read SSDR and disable ADS784x */
310: rv = zssp_ic_stop(ZSSP_IC_ADS7846);
311: else
312: rv = 0;
313:
314: if (dosend)
315: zts_sync_send(cmd);
316:
317: /* stop clock counter */
318: pxa2x0_ccnt_enable(ccen);
319:
320: return (rv);
321: }
322:
323: void
324: zts_sync_send(u_int32_t cmd)
325: {
326: u_int32_t tck;
327: u_int32_t a, b;
328:
329: /* XXX */
330: tck = CCNT_HS_400_VGA_C3K - 151;
331:
332: /* send dummy command; discard SSDR */
333: (void)zssp_ic_send(ZSSP_IC_ADS7846, cmd);
334:
335: /* wait for refresh */
336: HSYNC();
337:
338: /* wait after refresh */
339: a = pxa2x0_read_ccnt();
340: b = pxa2x0_read_ccnt();
341: while ((b - a) < tck)
342: b = pxa2x0_read_ccnt();
343:
344: /* send the actual command; keep ADS784x enabled */
345: zssp_ic_start(ZSSP_IC_ADS7846, cmd);
346: }
347:
348: int
349: zts_readpos(struct zts_pos *pos)
350: {
351: int cmd;
352: int t0, t1;
353: int down;
354:
355: /* XXX */
356: pxa2x0_gpio_set_function(GPIO_HSYNC_C3K, GPIO_IN);
357:
358: /* check that pen is down */
359: cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
360: (3 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
361:
362: t0 = zssp_ic_send(ZSSP_IC_ADS7846, cmd);
363: down = !(t0 < 10);
364: if (down == 0)
365: goto out;
366:
367: /* Y */
368: cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
369: (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
370:
371: (void)zts_sync_ads784x(0, 1, cmd);
372:
373: /* Y */
374: cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
375: (1 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
376:
377: (void)zts_sync_ads784x(1, 1, cmd);
378:
379: /* X */
380: cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
381: (5 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
382:
383: pos->y = zts_sync_ads784x(1, 1, cmd);
384:
385: /* T0 */
386: cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
387: (3 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
388:
389: pos->x = zts_sync_ads784x(1, 1, cmd);
390:
391: /* T1 */
392: cmd = (1 << ADSCTRL_PD0_SH) | (1 << ADSCTRL_PD1_SH) |
393: (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
394:
395: t0 = zts_sync_ads784x(1, 1, cmd);
396: t1 = zts_sync_ads784x(1, 0, cmd);
397:
398: /* check that pen is still down */
399: /* XXX pressure sensitivity varies with X or what? */
400: if (t0 == 0 || (pos->x * (t1 - t0) / t0) >= 15000)
401: down = 0;
402: pos->z = down;
403:
404: out:
405: /* Enable automatic low power mode. */
406: cmd = (4 << ADSCTRL_ADR_SH) | (1 << ADSCTRL_STS_SH);
407: (void)zssp_ic_send(ZSSP_IC_ADS7846, cmd);
408:
409: return (down);
410: }
411:
412: #define NAVGSAMPLES (NSAMPLES < 3 ? NSAMPLES : 3)
413: void
414: zts_avgpos(struct zts_pos *pos)
415: {
416: struct zts_pos *tpp = zts_samples;
417: int diff[NAVGSAMPLES];
418: int mindiff, mindiffv;
419: int n;
420: int i;
421: static int tail;
422:
423: if (ztsavgloaded < NAVGSAMPLES) {
424: tpp[(tail + ztsavgloaded) % NSAMPLES] = *pos;
425: ztsavgloaded++;
426: return;
427: }
428:
429: tpp[tail] = *pos;
430: tail = (tail+1) % NSAMPLES;
431:
432: /* X */
433: i = tail;
434: for (n = 0 ; n < NAVGSAMPLES; n++) {
435: int alt;
436: alt = (i+1) % NSAMPLES;
437: diff[n] = tpp[i].x - tpp[alt].x;
438: if (diff[n] < 0)
439: diff[n] = - diff[n]; /* ABS */
440: i = alt;
441: }
442: mindiffv = diff[0];
443: mindiff = 0;
444: for (n = 1; n < NAVGSAMPLES; n++) {
445: if (diff[n] < mindiffv) {
446: mindiffv = diff[n];
447: mindiff = n;
448: }
449: }
450: pos->x = (tpp[(tail + mindiff) % NSAMPLES].x +
451: tpp[(tail + mindiff + 1) % NSAMPLES].x) / 2;
452:
453: /* Y */
454: i = tail;
455: for (n = 0 ; n < NAVGSAMPLES; n++) {
456: int alt;
457: alt = (i+1) % NSAMPLES;
458: diff[n] = tpp[i].y - tpp[alt].y;
459: if (diff[n] < 0)
460: diff[n] = - diff[n]; /* ABS */
461: i = alt;
462: }
463: mindiffv = diff[0];
464: mindiff = 0;
465: for (n = 1; n < NAVGSAMPLES; n++) {
466: if (diff[n] < mindiffv) {
467: mindiffv = diff[n];
468: mindiff = n;
469: }
470: }
471: pos->y = (tpp[(tail + mindiff) % NSAMPLES].y +
472: tpp[(tail + mindiff + 1) % NSAMPLES].y) / 2;
473: }
474:
475: void
476: zts_poll(void *v)
477: {
478: int s;
479:
480: s = spltty();
481: (void)zts_irq(v);
482: splx(s);
483: }
484:
485: #define TS_STABLE 8
486: int
487: zts_irq(void *v)
488: {
489: struct zts_softc *sc = v;
490: struct zts_pos tp;
491: int s;
492: int pindown;
493: int down;
494: extern int zkbd_modstate;
495:
496: if (!sc->sc_enabled)
497: return 0;
498:
499: s = splhigh();
500: pindown = pxa2x0_gpio_get_bit(GPIO_TP_INT_C3K) ? 0 : 1;
501: if (pindown) {
502: pxa2x0_gpio_intr_mask(sc->sc_gh);
503: timeout_add(&sc->sc_ts_poll, POLL_TIMEOUT_RATE1);
504: }
505:
506: down = zts_readpos(&tp);
507:
508: if (!pindown) {
509: pxa2x0_gpio_intr_unmask(sc->sc_gh);
510: timeout_add(&sc->sc_ts_poll, POLL_TIMEOUT_RATE0);
511: ztsavgloaded = 0;
512: }
513: pxa2x0_gpio_clear_intr(GPIO_TP_INT_C3K);
514: splx(s);
515:
516: if (down) {
517: zts_avgpos(&tp);
518: if (!sc->sc_rawmode) {
519: /* Scale down to the screen resolution. */
520: tp.x = ((tp.x - sc->sc_tsscale.minx) *
521: sc->sc_tsscale.resx) /
522: (sc->sc_tsscale.maxx - sc->sc_tsscale.minx);
523: tp.y = ((tp.y - sc->sc_tsscale.miny) *
524: sc->sc_tsscale.resy) /
525: (sc->sc_tsscale.maxy - sc->sc_tsscale.miny);
526: }
527: }
528:
529: if (zkbd_modstate != 0 && down) {
530: if(zkbd_modstate & (1 << 1)) {
531: /* Fn */
532: down = 2;
533: }
534: if(zkbd_modstate & (1 << 2)) {
535: /* 'Alt' */
536: down = 4;
537: }
538: }
539: if (!down) {
540: /* x/y values are not reliable when pen is up */
541: tp.x = sc->sc_oldx;
542: tp.y = sc->sc_oldy;
543: }
544:
545: if (down || sc->sc_buttons != down) {
546: DPRINTF(("%s: tp.z = %d, tp.x = %d, tp.y = %d\n",
547: sc->sc_dev.dv_xname, tp.z, tp.x, tp.y));
548:
549: wsmouse_input(sc->sc_wsmousedev, down, tp.x, tp.y,
550: 0 /* z */, 0 /* w */,
551: WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
552: WSMOUSE_INPUT_ABSOLUTE_Z);
553: sc->sc_buttons = down;
554: sc->sc_oldx = tp.x;
555: sc->sc_oldy = tp.y;
556: }
557:
558: return 1;
559: }
560:
561: int
562: zts_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
563: {
564: int error = 0;
565: struct zts_softc *sc = v;
566: struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
567:
568: DPRINTF(("zts_ioctl(%d, '%c', %d)\n",
569: IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd & 0xff));
570:
571: switch (cmd) {
572: case WSMOUSEIO_SCALIBCOORDS:
573: if (!(wsmc->minx >= 0 && wsmc->maxx >= 0 &&
574: wsmc->miny >= 0 && wsmc->maxy >= 0 &&
575: wsmc->resx >= 0 && wsmc->resy >= 0 &&
576: wsmc->minx < 32768 && wsmc->maxx < 32768 &&
577: wsmc->miny < 32768 && wsmc->maxy < 32768 &&
578: wsmc->resx < 32768 && wsmc->resy < 32768 &&
579: wsmc->swapxy >= 0 && wsmc->swapxy <= 1 &&
580: wsmc->samplelen >= 0 && wsmc->samplelen <= 1))
581: return (EINVAL);
582:
583: sc->sc_tsscale.minx = wsmc->minx;
584: sc->sc_tsscale.maxx = wsmc->maxx;
585: sc->sc_tsscale.miny = wsmc->miny;
586: sc->sc_tsscale.maxy = wsmc->maxy;
587: sc->sc_tsscale.swapxy = wsmc->swapxy;
588: sc->sc_tsscale.resx = wsmc->resx;
589: sc->sc_tsscale.resy = wsmc->resy;
590: sc->sc_rawmode = wsmc->samplelen;
591: break;
592: case WSMOUSEIO_GCALIBCOORDS:
593: wsmc->minx = sc->sc_tsscale.minx;
594: wsmc->maxx = sc->sc_tsscale.maxx;
595: wsmc->miny = sc->sc_tsscale.miny;
596: wsmc->maxy = sc->sc_tsscale.maxy;
597: wsmc->swapxy = sc->sc_tsscale.swapxy;
598: wsmc->resx = sc->sc_tsscale.resx;
599: wsmc->resy = sc->sc_tsscale.resy;
600: wsmc->samplelen = sc->sc_rawmode;
601: break;
602: case WSMOUSEIO_GTYPE:
603: *(u_int *)data = WSMOUSE_TYPE_TPANEL;
604: break;
605: default:
606: error = ENOTTY;
607: break;
608: }
609:
610: return (error);
611: }
CVSweb