1 /* $NetBSD: wzero3_tp.c,v 1.11 2023/12/20 14:50:02 thorpej Exp $ */ 2 3 /*- 4 * Copyright (C) 2010 NONAKA Kimihiro <nonaka@netbsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: wzero3_tp.c,v 1.11 2023/12/20 14:50:02 thorpej Exp $"); 30 31 #include <sys/types.h> 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/device.h> 35 #include <sys/kernel.h> 36 #include <sys/callout.h> 37 38 #include <machine/bootinfo.h> 39 #include <machine/platid.h> 40 #include <machine/platid_mask.h> 41 42 #include <dev/wscons/wsconsio.h> 43 #include <dev/wscons/wsmousevar.h> 44 #include <dev/wscons/wsdisplayvar.h> 45 46 #include <dev/hpc/hpcfbio.h> 47 #include <dev/hpc/hpctpanelvar.h> 48 49 #include <arm/xscale/pxa2x0cpu.h> 50 #include <arm/xscale/pxa2x0reg.h> 51 #include <arm/xscale/pxa2x0var.h> 52 #include <arm/xscale/xscalereg.h> 53 #include <arm/xscale/pxa2x0_lcd.h> 54 #include <arm/xscale/pxa2x0_gpio.h> 55 56 #include <hpcarm/dev/wzero3_reg.h> 57 #include <hpcarm/dev/wzero3_sspvar.h> 58 59 #ifdef WZERO3TP_DEBUG 60 #define DPRINTF(s) printf s 61 #else 62 #define DPRINTF(s) 63 #endif 64 65 #define POLL_TIMEOUT_RATE0 ((hz * 150) / 1000) 66 #define POLL_TIMEOUT_RATE1 ((hz + 99) / 100) /* XXX every tick */ 67 68 /* Settable via sysctl. */ 69 int wzero3tp_rawmode; 70 71 static const struct wsmouse_calibcoords ws003sh_default_calib = { 72 0, 0, 479, 639, /* minx, miny, maxx, maxy */ 73 5, /* samplelen */ 74 { 75 { 2028, 2004, 240, 320 }, /* rawx, rawy, x, y */ 76 { 3312, 705, 48, 64 }, 77 { 3316, 3371, 48, 576 }, 78 { 739, 3392, 432, 576 }, 79 { 749, 673, 432, 64 }, 80 } 81 }; 82 83 static const struct wsmouse_calibcoords ws007sh_default_calib = { 84 0, 0, 479, 639, /* minx, miny, maxx, maxy */ 85 5, /* samplelen */ 86 { 87 { 2050, 2024, 240, 320 }, /* rawx, rawy, x, y */ 88 { 578, 3471, 48, 64 }, 89 { 578, 582, 48, 576 }, 90 { 3432, 582, 432, 576 }, 91 { 3432, 3471, 432, 64 }, 92 } 93 }; 94 95 static const struct wsmouse_calibcoords ws011sh_default_calib = { 96 0, 0, 479, 799, /* minx, miny, maxx, maxy */ 97 5, /* samplelen */ 98 { 99 { 2126, 2048, 240, 400 }, /* rawx, rawy, x, y */ 100 { 527, 3464, 48, 80 }, 101 { 3628, 3376, 48, 720 }, 102 { 3351, 595, 432, 720 }, 103 { 554, 562, 432, 80 }, 104 } 105 }; 106 107 struct wzero3tp_pos { 108 int x; 109 int y; 110 int z; /* touch pressure */ 111 }; 112 113 struct wzero3tp_model; 114 struct wzero3tp_softc { 115 device_t sc_dev; 116 const struct wzero3tp_model *sc_model; 117 void *sc_gh; 118 struct callout sc_tp_poll; 119 int sc_enabled; 120 int sc_buttons; /* button emulation ? */ 121 device_t sc_wsmousedev; 122 struct wzero3tp_pos sc_oldpos; 123 struct tpcalib_softc sc_tpcalib; 124 }; 125 126 static void nulldrv_init(void); 127 static int nulldrv_readpos(struct wzero3tp_pos *); 128 static void nulldrv_suspend(void); 129 static void nulldrv_resume(void); 130 131 static void ws007sh_wait_for_hsync(void); 132 133 void max1233_init(void); 134 int max1233_readpos(struct wzero3tp_pos *); 135 void max1233_suspend(void); 136 void max1233_resume(void); 137 138 void ads7846_init(void); 139 int ads7846_readpos(struct wzero3tp_pos *); 140 void ads7846_suspend(void); 141 void ads7846_resume(void); 142 extern void (*ads7846_wait_for_hsync)(void); 143 144 void ak4184_init(void); 145 int ak4184_readpos(struct wzero3tp_pos *); 146 void ak4184_suspend(void); 147 void ak4184_resume(void); 148 149 static int wzero3tp_match(device_t, cfdata_t, void *); 150 static void wzero3tp_attach(device_t, device_t, void *); 151 152 CFATTACH_DECL_NEW(wzero3tp, sizeof(struct wzero3tp_softc), 153 wzero3tp_match, wzero3tp_attach, NULL, NULL); 154 155 static int wzero3tp_enable(void *); 156 static void wzero3tp_disable(void *); 157 static bool wzero3tp_suspend(device_t dv, const pmf_qual_t *); 158 static bool wzero3tp_resume(device_t dv, const pmf_qual_t *); 159 static void wzero3tp_poll(void *); 160 static int wzero3tp_irq(void *); 161 static int wzero3tp_ioctl(void *, u_long, void *, int, struct lwp *); 162 163 static const struct wsmouse_accessops wzero3tp_accessops = { 164 wzero3tp_enable, 165 wzero3tp_ioctl, 166 wzero3tp_disable 167 }; 168 169 struct wzero3tp_model { 170 platid_mask_t *platid; 171 const char *name; 172 int intr_pin; 173 const struct wsmouse_calibcoords *calib; 174 void (*wait_for_hsync)(void); 175 struct chip { 176 void (*init)(void); 177 int (*readpos)(struct wzero3tp_pos *); 178 void (*suspend)(void); 179 void (*resume)(void); 180 } chip; 181 } wzero3tp_table[] = { 182 /* WS003SH */ 183 { 184 &platid_mask_MACH_SHARP_WZERO3_WS003SH, 185 "WS003SH", 186 GPIO_WS003SH_TOUCH_PANEL, 187 &ws003sh_default_calib, 188 NULL, 189 { max1233_init, max1233_readpos, 190 max1233_suspend, max1233_resume, }, 191 }, 192 /* WS004SH */ 193 { 194 &platid_mask_MACH_SHARP_WZERO3_WS004SH, 195 "WS004SH", 196 GPIO_WS003SH_TOUCH_PANEL, 197 &ws003sh_default_calib, 198 NULL, 199 { max1233_init, max1233_readpos, 200 max1233_suspend, max1233_resume, }, 201 }, 202 /* WS007SH */ 203 { 204 &platid_mask_MACH_SHARP_WZERO3_WS007SH, 205 "WS007SH", 206 GPIO_WS007SH_TOUCH_PANEL, 207 &ws007sh_default_calib, 208 ws007sh_wait_for_hsync, 209 { ads7846_init, ads7846_readpos, 210 ads7846_suspend, ads7846_resume, }, 211 }, 212 /* WS011SH */ 213 { 214 &platid_mask_MACH_SHARP_WZERO3_WS011SH, 215 "WS011SH", 216 GPIO_WS011SH_TOUCH_PANEL, 217 &ws011sh_default_calib, 218 NULL, 219 { ak4184_init, ak4184_readpos, 220 ak4184_suspend, ak4184_resume, }, 221 }, 222 #if 0 223 /* WS0020H */ 224 { 225 &platid_mask_MACH_SHARP_WZERO3_WS020SH, 226 "WS020SH", 227 -1, 228 NULL, 229 NULL, 230 { nulldrv_init, nulldrv_readpos, 231 nulldrv_suspend, nulldrv_resume, }, 232 }, 233 #endif 234 { 235 NULL, NULL, -1, NULL, NULL, 236 { nulldrv_init, nulldrv_readpos, 237 nulldrv_suspend, nulldrv_resume, }, 238 }, 239 }; 240 241 static const struct wzero3tp_model * 242 wzero3tp_lookup(void) 243 { 244 const struct wzero3tp_model *model; 245 246 for (model = wzero3tp_table; model->platid != NULL; model++) { 247 if (platid_match(&platid, model->platid)) { 248 return model; 249 } 250 } 251 return NULL; 252 } 253 254 static int 255 wzero3tp_match(device_t parent, cfdata_t cf, void *aux) 256 { 257 258 if (strcmp(cf->cf_name, "wzero3tp") != 0) 259 return 0; 260 if (wzero3tp_lookup() == NULL) 261 return 0; 262 return 1; 263 } 264 265 static void 266 wzero3tp_attach(device_t parent, device_t self, void *aux) 267 { 268 struct wzero3tp_softc *sc = device_private(self); 269 struct wsmousedev_attach_args a; 270 271 sc->sc_dev = self; 272 273 aprint_normal(": touch panel\n"); 274 aprint_naive("\n"); 275 276 sc->sc_model = wzero3tp_lookup(); 277 if (sc->sc_model == NULL) { 278 aprint_error_dev(self, "unknown model\n"); 279 return; 280 } 281 282 callout_init(&sc->sc_tp_poll, 0); 283 callout_setfunc(&sc->sc_tp_poll, wzero3tp_poll, sc); 284 285 if (sc->sc_model->wait_for_hsync) 286 ads7846_wait_for_hsync = sc->sc_model->wait_for_hsync; 287 288 (*sc->sc_model->chip.init)(); 289 290 a.accessops = &wzero3tp_accessops; 291 a.accesscookie = sc; 292 293 sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint, CFARGS_NONE); 294 295 /* Initialize calibration, set default parameters. */ 296 tpcalib_init(&sc->sc_tpcalib); 297 if (sc->sc_model->calib) { 298 tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS, 299 __UNCONST(sc->sc_model->calib), 0, 0); 300 } 301 } 302 303 static int 304 wzero3tp_enable(void *v) 305 { 306 struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v; 307 308 DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__)); 309 310 if (sc->sc_enabled) { 311 DPRINTF(("%s: already enabled\n", device_xname(sc->sc_dev))); 312 return EBUSY; 313 } 314 315 callout_stop(&sc->sc_tp_poll); 316 317 if (!pmf_device_register(sc->sc_dev, wzero3tp_suspend, wzero3tp_resume)) 318 aprint_error_dev(sc->sc_dev, 319 "couldn't establish power handler\n"); 320 321 pxa2x0_gpio_set_function(sc->sc_model->intr_pin, GPIO_IN); 322 323 /* XXX */ 324 if (sc->sc_gh == NULL) { 325 sc->sc_gh = pxa2x0_gpio_intr_establish( 326 sc->sc_model->intr_pin, IST_EDGE_FALLING, IPL_TTY, 327 wzero3tp_irq, sc); 328 } else { 329 pxa2x0_gpio_intr_unmask(sc->sc_gh); 330 } 331 332 /* enable interrupts */ 333 sc->sc_enabled = 1; 334 sc->sc_buttons = 0; 335 336 return 0; 337 } 338 339 static void 340 wzero3tp_disable(void *v) 341 { 342 struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v; 343 344 DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__)); 345 346 callout_stop(&sc->sc_tp_poll); 347 348 pmf_device_deregister(sc->sc_dev); 349 350 pxa2x0_gpio_intr_mask(sc->sc_gh); 351 352 /* disable interrupts */ 353 sc->sc_enabled = 0; 354 } 355 356 static bool 357 wzero3tp_suspend(device_t dv, const pmf_qual_t *qual) 358 { 359 struct wzero3tp_softc *sc = device_private(dv); 360 361 DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__)); 362 363 sc->sc_enabled = 0; 364 pxa2x0_gpio_intr_mask(sc->sc_gh); 365 366 callout_stop(&sc->sc_tp_poll); 367 368 (*sc->sc_model->chip.suspend)(); 369 370 pxa2x0_gpio_set_function(sc->sc_model->intr_pin, GPIO_OUT|GPIO_SET); 371 372 return true; 373 } 374 375 static bool 376 wzero3tp_resume(device_t dv, const pmf_qual_t *qual) 377 { 378 struct wzero3tp_softc *sc = device_private(dv); 379 380 DPRINTF(("%s: %s\n", device_xname(sc->sc_dev), __func__)); 381 382 pxa2x0_gpio_set_function(sc->sc_model->intr_pin, GPIO_IN); 383 pxa2x0_gpio_intr_mask(sc->sc_gh); 384 385 (*sc->sc_model->chip.resume)(); 386 387 pxa2x0_gpio_intr_unmask(sc->sc_gh); 388 sc->sc_enabled = 1; 389 390 return true; 391 } 392 393 static void 394 wzero3tp_poll(void *v) 395 { 396 int s; 397 398 s = spltty(); 399 (void)wzero3tp_irq(v); 400 splx(s); 401 } 402 403 static int 404 wzero3tp_irq(void *v) 405 { 406 struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v; 407 struct wzero3tp_pos tp = { 0, 0, 0 }; 408 int pindown; 409 int down; 410 int x, y; 411 int s; 412 413 if (!sc->sc_enabled) 414 return 0; 415 416 s = splhigh(); 417 418 pindown = pxa2x0_gpio_get_bit(sc->sc_model->intr_pin) ? 0 : 1; 419 DPRINTF(("%s: pindown = %d\n", device_xname(sc->sc_dev), pindown)); 420 if (pindown) { 421 pxa2x0_gpio_intr_mask(sc->sc_gh); 422 callout_schedule(&sc->sc_tp_poll, POLL_TIMEOUT_RATE1); 423 } 424 425 down = (*sc->sc_model->chip.readpos)(&tp); 426 DPRINTF(("%s: x = %d, y = %d, z = %d, down = %d\n", 427 device_xname(sc->sc_dev), tp.x, tp.y, tp.z, down)); 428 429 if (!pindown) { 430 pxa2x0_gpio_intr_unmask(sc->sc_gh); 431 callout_schedule(&sc->sc_tp_poll, POLL_TIMEOUT_RATE0); 432 } 433 pxa2x0_gpio_clear_intr(sc->sc_model->intr_pin); 434 435 splx(s); 436 437 if (down) { 438 if (!wzero3tp_rawmode) { 439 tpcalib_trans(&sc->sc_tpcalib, tp.x, tp.y, &x, &y); 440 DPRINTF(("%s: x = %d, y = %d\n", 441 device_xname(sc->sc_dev), x, y)); 442 tp.x = x; 443 tp.y = y; 444 } 445 } 446 447 if (!down) { 448 /* x/y values are not reliable when pen is up */ 449 tp = sc->sc_oldpos; 450 } 451 452 if (down || sc->sc_buttons != down) { 453 wsmouse_input(sc->sc_wsmousedev, down, tp.x, tp.y, 0, 0, 454 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y); 455 sc->sc_buttons = down; 456 sc->sc_oldpos = tp; 457 } 458 459 return 1; 460 } 461 462 static int 463 wzero3tp_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 464 { 465 struct wzero3tp_softc *sc = (struct wzero3tp_softc *)v; 466 struct wsmouse_id *id; 467 468 switch (cmd) { 469 case WSMOUSEIO_GTYPE: 470 *(u_int *)data = WSMOUSE_TYPE_TPANEL; 471 return 0; 472 473 case WSMOUSEIO_GETID: 474 /* 475 * return unique ID string, 476 * "<vendor> <model> <serial number>" 477 */ 478 id = (struct wsmouse_id *)data; 479 if (id->type != WSMOUSE_ID_TYPE_UIDSTR) 480 return EINVAL; 481 snprintf(id->data, WSMOUSE_ID_MAXLEN, "Sharp %s SN000000", 482 sc->sc_model->name); 483 id->length = strlen(id->data); 484 return 0; 485 486 case WSMOUSEIO_SCALIBCOORDS: 487 case WSMOUSEIO_GCALIBCOORDS: 488 return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l); 489 } 490 491 return EPASSTHROUGH; 492 } 493 494 /*---------------------------------------------------------------------------- 495 * null driver 496 */ 497 static void 498 nulldrv_init(void) 499 { 500 501 /* Nothing to do */ 502 } 503 504 static int 505 nulldrv_readpos(struct wzero3tp_pos *pos) 506 { 507 508 pos->x = 0; 509 pos->y = 0; 510 pos->z = 0; 511 512 return 0; 513 } 514 515 static void 516 nulldrv_suspend(void) 517 { 518 519 /* Nothing to do */ 520 } 521 522 static void 523 nulldrv_resume(void) 524 { 525 526 /* Nothing to do */ 527 } 528 529 /*---------------------------------------------------------------------------- 530 * model specific functions 531 */ 532 static void 533 ws007sh_wait_for_hsync(void) 534 { 535 536 while (pxa2x0_gpio_get_bit(GPIO_WS007SH_HSYNC) == 0) 537 continue; 538 while (pxa2x0_gpio_get_bit(GPIO_WS007SH_HSYNC) != 0) 539 continue; 540 } 541 542 /*---------------------------------------------------------------------------- 543 * MAX1233 touch screen controller for WS003SH/WS004SH 544 */ 545 #define MAXCTRL_ADDR_SH 0 /* Address bit[5:0] */ 546 #define MAXCTRL_PAGE_SH 6 /* Page bit (0:Data/1:Control) */ 547 #define MAXCTRL_RW_SH 15 /* R/W bit (0:Write/1:Read) */ 548 549 /* VREF=2.5V, sets interrupt initiated touch-screen scans 550 * 3.5us/sample, 16 data ave., 12 bit, settling time: 100us */ 551 #define MAX1233_ADCCTRL 0x8be3 552 553 void 554 max1233_init(void) 555 { 556 557 /* Enable automatic low power mode. */ 558 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 559 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH), 560 0x0001); 561 /* Wait for touch */ 562 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 563 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH), 564 MAX1233_ADCCTRL); 565 /* DAC on */ 566 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 567 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH), 568 0x0000); 569 } 570 571 void 572 max1233_suspend(void) 573 { 574 575 /* power down. */ 576 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 577 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH), 578 0xc000); 579 /* DAC off */ 580 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 581 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH), 582 0x8000); 583 } 584 585 void 586 max1233_resume(void) 587 { 588 589 /* Enable automatic low power mode. */ 590 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 591 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH), 592 0x0001); 593 /* Wait for touch */ 594 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 595 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH), 596 MAX1233_ADCCTRL); 597 /* DAC on */ 598 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 599 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH), 600 0x0000); 601 } 602 603 int 604 max1233_readpos(struct wzero3tp_pos *pos) 605 { 606 uint32_t x, y, z1 = 0, z2 = 0, rt; 607 uint32_t status; 608 int down; 609 610 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 611 (0<<MAXCTRL_RW_SH) | (1<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH), 612 0x0bf3); 613 DELAY(300); 614 615 while ((status = (wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 616 (1<<MAXCTRL_RW_SH) 617 | (1<<MAXCTRL_PAGE_SH) 618 | (0<<MAXCTRL_ADDR_SH), 0) & 0x4000)) != 0x4000) { 619 DPRINTF(("%s: status=%#x\n", __func__, status)); 620 DELAY(10); 621 } 622 DPRINTF(("%s: status=%#x\n", __func__, status)); 623 624 x = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 625 (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (0<<MAXCTRL_ADDR_SH),0); 626 DPRINTF(("%s: x=%d\n", __func__, x)); 627 y = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 628 (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (1<<MAXCTRL_ADDR_SH),0); 629 DPRINTF(("%s: y=%d\n", __func__, y)); 630 z1 = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 631 (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (2<<MAXCTRL_ADDR_SH),0); 632 DPRINTF(("%s: z1=%d\n", __func__, z1)); 633 z2 = wzero3ssp_ic_send(WZERO3_SSP_IC_MAX1233, 634 (1<<MAXCTRL_RW_SH) | (0<<MAXCTRL_PAGE_SH) | (3<<MAXCTRL_ADDR_SH),0); 635 DPRINTF(("%s: z2=%d\n", __func__, z2)); 636 637 if (z1 >= 10) { 638 rt = 400 /* XXX: X plate ohms */; 639 rt *= x; 640 rt *= (z2 / z1) - 1; 641 rt >>= 12; 642 } else 643 rt = 0; 644 DPRINTF(("%s: rt=%d\n", __func__, rt)); 645 646 down = (rt != 0); 647 if (down) { 648 pos->x = x; 649 pos->y = y; 650 } 651 pos->z = down; 652 653 return down; 654 } 655 656 /*---------------------------------------------------------------------------- 657 * ADS7846/TSC2046 touch screen controller for WS007SH 658 */ 659 #define ADSCTRL_PD0_SH 0 /* PD0 bit */ 660 #define ADSCTRL_PD1_SH 1 /* PD1 bit */ 661 #define ADSCTRL_DFR_SH 2 /* SER/DFR bit */ 662 #define ADSCTRL_MOD_SH 3 /* Mode bit */ 663 #define ADSCTRL_ADR_SH 4 /* Address setting */ 664 #define ADSCTRL_STS_SH 7 /* Start bit */ 665 666 static uint32_t ads7846_sync(int, int, uint32_t); 667 668 void 669 ads7846_init(void) 670 { 671 672 /* Enable automatic low power mode. */ 673 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, 674 (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0); 675 } 676 677 void 678 ads7846_suspend(void) 679 { 680 681 /* Turn off reference voltage but leave ADC on. */ 682 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, 683 (1<<ADSCTRL_PD1_SH) | (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0); 684 } 685 686 void 687 ads7846_resume(void) 688 { 689 690 /* Enable automatic low power mode. */ 691 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, 692 (4<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH), 0); 693 } 694 695 int 696 ads7846_readpos(struct wzero3tp_pos *pos) 697 { 698 int cmd, cmd0; 699 int z0, z1; 700 int down; 701 702 cmd0 = (1<<ADSCTRL_STS_SH) | (1<<ADSCTRL_PD0_SH) | (1<<ADSCTRL_PD1_SH); 703 704 /* check that pen is down */ 705 cmd = cmd0 | (3<<ADSCTRL_ADR_SH); 706 z0 = wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0); 707 DPRINTF(("%s: first z0 = %d\n", __func__, z0)); 708 709 down = (z0 >= 10); 710 if (!down) 711 goto out; 712 713 /* Y (discard) */ 714 cmd = cmd0 | (1<<ADSCTRL_ADR_SH); 715 (void)ads7846_sync(0, 1, cmd); 716 717 /* Y */ 718 cmd = cmd0 | (1<<ADSCTRL_ADR_SH); 719 (void)ads7846_sync(1, 1, cmd); 720 721 /* X */ 722 cmd = cmd0 | (5<<ADSCTRL_ADR_SH); 723 pos->y = ads7846_sync(1, 1, cmd); 724 DPRINTF(("%s: y = %d\n", __func__, pos->y)); 725 726 /* Z0 */ 727 cmd = cmd0 | (3<<ADSCTRL_ADR_SH); 728 pos->x = ads7846_sync(1, 1, cmd); 729 DPRINTF(("%s: x = %d\n", __func__, pos->x)); 730 731 /* Z1 */ 732 cmd = cmd0 | (4<<ADSCTRL_ADR_SH); 733 z0 = ads7846_sync(1, 1, cmd); 734 z1 = ads7846_sync(1, 0, cmd); 735 DPRINTF(("%s: z0 = %d, z1 = %d\n", __func__, z0, z1)); 736 737 /* check that pen is still down */ 738 if (z0 == 0 || (pos->x * (z1 - z0) / z0) >= 15000) 739 down = 0; 740 pos->z = down; 741 742 out: 743 /* Enable automatic low power mode. */ 744 cmd = (1<<ADSCTRL_ADR_SH) | (1<<ADSCTRL_STS_SH); 745 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0); 746 747 return down; 748 } 749 750 void (*ads7846_wait_for_hsync)(void); 751 752 /* 753 * Communicate synchronously with the ADS784x touch screen controller. 754 */ 755 static uint32_t 756 ads7846_sync(int dorecv, int dosend, uint32_t cmd) 757 { 758 uint32_t rv = 0; 759 760 if (ads7846_wait_for_hsync) 761 (*ads7846_wait_for_hsync)(); 762 763 if (dorecv) 764 rv = wzero3ssp_ic_stop(WZERO3_SSP_IC_ADS7846); 765 766 if (dosend) { 767 /* send dummy command; discard SSDR */ 768 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_ADS7846, cmd, 0); 769 770 /* wait for refresh */ 771 if (ads7846_wait_for_hsync) 772 (*ads7846_wait_for_hsync)(); 773 774 /* send the actual command; keep ADS784x enabled */ 775 wzero3ssp_ic_start(WZERO3_SSP_IC_ADS7846, cmd); 776 } 777 778 return rv; 779 } 780 781 /*---------------------------------------------------------------------------- 782 * AK4184 touch screen controller for WS011SH 783 */ 784 #define AKMCTRL_PD_SH 12 /* Power down bit */ 785 #define AKMCTRL_ADR_SH 13 /* Address setting bits */ 786 #define AKMCTRL_STS_SH 15 /* Start bit */ 787 788 static uint32_t ak4184_sync(int, int, uint32_t); 789 790 void 791 ak4184_init(void) 792 { 793 794 /* Enable automatic low power mode. */ 795 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP, 796 (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (0<<AKMCTRL_PD_SH), 0); 797 } 798 799 int 800 ak4184_readpos(struct wzero3tp_pos *pos) 801 { 802 u_int rt; 803 int z1, z2; 804 805 /* X (discard) */ 806 (void)ak4184_sync(0, 1, 807 (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH)); 808 809 /* X */ 810 (void)ak4184_sync(1, 1, 811 (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH)); 812 813 /* Y */ 814 pos->x = ak4184_sync(1, 1, 815 (1<<AKMCTRL_STS_SH) | (1<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH)); 816 DPRINTF(("%s: x=%d\n", __func__, pos->x)); 817 pos->y = ak4184_sync(1, 1, 818 (1<<AKMCTRL_STS_SH) | (2<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH)); 819 DPRINTF(("%s: y=%d\n", __func__, pos->y)); 820 z1 = ak4184_sync(1, 1, 821 (1<<AKMCTRL_STS_SH) | (3<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH)); 822 DPRINTF(("%s: z1=%d\n", __func__, z1)); 823 z2 = ak4184_sync(1, 0, 824 (1<<AKMCTRL_STS_SH) | (3<<AKMCTRL_ADR_SH) | (1<<AKMCTRL_PD_SH)); 825 DPRINTF(("%s: z2=%d\n", __func__, z2)); 826 827 if (z1 >= 10) { 828 rt = 400 /* XXX: X plate ohms */; 829 rt *= pos->x; 830 rt *= (z2 / z1) - 1; 831 rt >>= 12; 832 } else 833 rt = 0; 834 DPRINTF(("%s: rt=%d\n", __func__, rt)); 835 836 /* check that pen is still down */ 837 if (z1 == 0 || rt == 0) 838 pos->z = 0; 839 else 840 pos->z = 1; 841 842 /* Enable automatic low power mode. */ 843 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP, 844 (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (0<<AKMCTRL_PD_SH), 0); 845 846 return pos->z; 847 } 848 849 void 850 ak4184_suspend(void) 851 { 852 853 /* Nothing to do */ 854 } 855 856 void 857 ak4184_resume(void) 858 { 859 860 /* Enable automatic low power mode. */ 861 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP, 862 (1<<AKMCTRL_STS_SH) | (0<<AKMCTRL_ADR_SH) | (0<<AKMCTRL_PD_SH), 0); 863 } 864 865 static uint32_t 866 ak4184_sync(int dorecv, int dosend, uint32_t cmd) 867 { 868 uint32_t rv = 0; 869 870 if (dorecv) 871 rv = wzero3ssp_ic_stop(WZERO3_SSP_IC_AK4184_TP); 872 873 if (dosend) { 874 /* send dummy command; discard SSDR */ 875 (void)wzero3ssp_ic_send(WZERO3_SSP_IC_AK4184_TP, cmd, 0); 876 877 /* send the actual command; keep AK4184 enabled */ 878 wzero3ssp_ic_start(WZERO3_SSP_IC_AK4184_TP, cmd); 879 } 880 881 return rv; 882 } 883