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