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