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