tsc2005.c (14951B)
1/* 2 * TI TSC2005 emulator. 3 * 4 * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org> 5 * Copyright (C) 2008 Nokia Corporation 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 or 10 * (at your option) version 3 of the License. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21#include "qemu/osdep.h" 22#include "qemu/log.h" 23#include "qemu/timer.h" 24#include "sysemu/reset.h" 25#include "ui/console.h" 26#include "hw/input/tsc2xxx.h" 27#include "hw/irq.h" 28#include "migration/vmstate.h" 29#include "trace.h" 30 31#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10))) 32 33typedef struct { 34 qemu_irq pint; /* Combination of the nPENIRQ and DAV signals */ 35 QEMUTimer *timer; 36 uint16_t model; 37 38 int32_t x, y; 39 bool pressure; 40 41 uint8_t reg, state; 42 bool irq, command; 43 uint16_t data, dav; 44 45 bool busy; 46 bool enabled; 47 bool host_mode; 48 int8_t function; 49 int8_t nextfunction; 50 bool precision; 51 bool nextprecision; 52 uint16_t filter; 53 uint8_t pin_func; 54 uint16_t timing[2]; 55 uint8_t noise; 56 bool reset; 57 bool pdst; 58 bool pnd0; 59 uint16_t temp_thr[2]; 60 uint16_t aux_thr[2]; 61 62 int32_t tr[8]; 63} TSC2005State; 64 65enum { 66 TSC_MODE_XYZ_SCAN = 0x0, 67 TSC_MODE_XY_SCAN, 68 TSC_MODE_X, 69 TSC_MODE_Y, 70 TSC_MODE_Z, 71 TSC_MODE_AUX, 72 TSC_MODE_TEMP1, 73 TSC_MODE_TEMP2, 74 TSC_MODE_AUX_SCAN, 75 TSC_MODE_X_TEST, 76 TSC_MODE_Y_TEST, 77 TSC_MODE_TS_TEST, 78 TSC_MODE_RESERVED, 79 TSC_MODE_XX_DRV, 80 TSC_MODE_YY_DRV, 81 TSC_MODE_YX_DRV, 82}; 83 84static const uint16_t mode_regs[16] = { 85 0xf000, /* X, Y, Z scan */ 86 0xc000, /* X, Y scan */ 87 0x8000, /* X */ 88 0x4000, /* Y */ 89 0x3000, /* Z */ 90 0x0800, /* AUX */ 91 0x0400, /* TEMP1 */ 92 0x0200, /* TEMP2 */ 93 0x0800, /* AUX scan */ 94 0x0040, /* X test */ 95 0x0020, /* Y test */ 96 0x0080, /* Short-circuit test */ 97 0x0000, /* Reserved */ 98 0x0000, /* X+, X- drivers */ 99 0x0000, /* Y+, Y- drivers */ 100 0x0000, /* Y+, X- drivers */ 101}; 102 103#define X_TRANSFORM(s) \ 104 ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3]) 105#define Y_TRANSFORM(s) \ 106 ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7]) 107#define Z1_TRANSFORM(s) \ 108 ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4) 109#define Z2_TRANSFORM(s) \ 110 ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4) 111 112#define AUX_VAL (700 << 4) /* +/- 3 at 12-bit */ 113#define TEMP1_VAL (1264 << 4) /* +/- 5 at 12-bit */ 114#define TEMP2_VAL (1531 << 4) /* +/- 5 at 12-bit */ 115 116static uint16_t tsc2005_read(TSC2005State *s, int reg) 117{ 118 uint16_t ret; 119 120 switch (reg) { 121 case 0x0: /* X */ 122 s->dav &= ~mode_regs[TSC_MODE_X]; 123 return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) + 124 (s->noise & 3); 125 case 0x1: /* Y */ 126 s->dav &= ~mode_regs[TSC_MODE_Y]; 127 s->noise ++; 128 return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^ 129 (s->noise & 3); 130 case 0x2: /* Z1 */ 131 s->dav &= 0xdfff; 132 return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) - 133 (s->noise & 3); 134 case 0x3: /* Z2 */ 135 s->dav &= 0xefff; 136 return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) | 137 (s->noise & 3); 138 139 case 0x4: /* AUX */ 140 s->dav &= ~mode_regs[TSC_MODE_AUX]; 141 return TSC_CUT_RESOLUTION(AUX_VAL, s->precision); 142 143 case 0x5: /* TEMP1 */ 144 s->dav &= ~mode_regs[TSC_MODE_TEMP1]; 145 return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) - 146 (s->noise & 5); 147 case 0x6: /* TEMP2 */ 148 s->dav &= 0xdfff; 149 s->dav &= ~mode_regs[TSC_MODE_TEMP2]; 150 return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^ 151 (s->noise & 3); 152 153 case 0x7: /* Status */ 154 ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0; 155 s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] | 156 mode_regs[TSC_MODE_TS_TEST]); 157 s->reset = true; 158 return ret; 159 160 case 0x8: /* AUX high treshold */ 161 return s->aux_thr[1]; 162 case 0x9: /* AUX low treshold */ 163 return s->aux_thr[0]; 164 165 case 0xa: /* TEMP high treshold */ 166 return s->temp_thr[1]; 167 case 0xb: /* TEMP low treshold */ 168 return s->temp_thr[0]; 169 170 case 0xc: /* CFR0 */ 171 return (s->pressure << 15) | ((!s->busy) << 14) | 172 (s->nextprecision << 13) | s->timing[0]; 173 case 0xd: /* CFR1 */ 174 return s->timing[1]; 175 case 0xe: /* CFR2 */ 176 return (s->pin_func << 14) | s->filter; 177 178 case 0xf: /* Function select status */ 179 return s->function >= 0 ? 1 << s->function : 0; 180 } 181 182 /* Never gets here */ 183 return 0xffff; 184} 185 186static void tsc2005_write(TSC2005State *s, int reg, uint16_t data) 187{ 188 switch (reg) { 189 case 0x8: /* AUX high treshold */ 190 s->aux_thr[1] = data; 191 break; 192 case 0x9: /* AUX low treshold */ 193 s->aux_thr[0] = data; 194 break; 195 196 case 0xa: /* TEMP high treshold */ 197 s->temp_thr[1] = data; 198 break; 199 case 0xb: /* TEMP low treshold */ 200 s->temp_thr[0] = data; 201 break; 202 203 case 0xc: /* CFR0 */ 204 s->host_mode = (data >> 15) != 0; 205 if (s->enabled != !(data & 0x4000)) { 206 s->enabled = !(data & 0x4000); 207 trace_tsc2005_sense(s->enabled ? "enabled" : "disabled"); 208 if (s->busy && !s->enabled) 209 timer_del(s->timer); 210 s->busy = s->busy && s->enabled; 211 } 212 s->nextprecision = (data >> 13) & 1; 213 s->timing[0] = data & 0x1fff; 214 if ((s->timing[0] >> 11) == 3) { 215 qemu_log_mask(LOG_GUEST_ERROR, 216 "tsc2005_write: illegal conversion clock setting\n"); 217 } 218 break; 219 case 0xd: /* CFR1 */ 220 s->timing[1] = data & 0xf07; 221 break; 222 case 0xe: /* CFR2 */ 223 s->pin_func = (data >> 14) & 3; 224 s->filter = data & 0x3fff; 225 break; 226 227 default: 228 qemu_log_mask(LOG_GUEST_ERROR, 229 "%s: write into read-only register 0x%x\n", 230 __func__, reg); 231 } 232} 233 234/* This handles most of the chip's logic. */ 235static void tsc2005_pin_update(TSC2005State *s) 236{ 237 int64_t expires; 238 bool pin_state; 239 240 switch (s->pin_func) { 241 case 0: 242 pin_state = !s->pressure && !!s->dav; 243 break; 244 case 1: 245 case 3: 246 default: 247 pin_state = !s->dav; 248 break; 249 case 2: 250 pin_state = !s->pressure; 251 } 252 253 if (pin_state != s->irq) { 254 s->irq = pin_state; 255 qemu_set_irq(s->pint, s->irq); 256 } 257 258 switch (s->nextfunction) { 259 case TSC_MODE_XYZ_SCAN: 260 case TSC_MODE_XY_SCAN: 261 if (!s->host_mode && s->dav) 262 s->enabled = false; 263 if (!s->pressure) 264 return; 265 /* Fall through */ 266 case TSC_MODE_AUX_SCAN: 267 break; 268 269 case TSC_MODE_X: 270 case TSC_MODE_Y: 271 case TSC_MODE_Z: 272 if (!s->pressure) 273 return; 274 /* Fall through */ 275 case TSC_MODE_AUX: 276 case TSC_MODE_TEMP1: 277 case TSC_MODE_TEMP2: 278 case TSC_MODE_X_TEST: 279 case TSC_MODE_Y_TEST: 280 case TSC_MODE_TS_TEST: 281 if (s->dav) 282 s->enabled = false; 283 break; 284 285 case TSC_MODE_RESERVED: 286 case TSC_MODE_XX_DRV: 287 case TSC_MODE_YY_DRV: 288 case TSC_MODE_YX_DRV: 289 default: 290 return; 291 } 292 293 if (!s->enabled || s->busy) 294 return; 295 296 s->busy = true; 297 s->precision = s->nextprecision; 298 s->function = s->nextfunction; 299 s->pdst = !s->pnd0; /* Synchronised on internal clock */ 300 expires = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 301 (NANOSECONDS_PER_SECOND >> 7); 302 timer_mod(s->timer, expires); 303} 304 305static void tsc2005_reset(TSC2005State *s) 306{ 307 s->state = 0; 308 s->pin_func = 0; 309 s->enabled = false; 310 s->busy = false; 311 s->nextprecision = false; 312 s->nextfunction = 0; 313 s->timing[0] = 0; 314 s->timing[1] = 0; 315 s->irq = false; 316 s->dav = 0; 317 s->reset = false; 318 s->pdst = true; 319 s->pnd0 = false; 320 s->function = -1; 321 s->temp_thr[0] = 0x000; 322 s->temp_thr[1] = 0xfff; 323 s->aux_thr[0] = 0x000; 324 s->aux_thr[1] = 0xfff; 325 326 tsc2005_pin_update(s); 327} 328 329static uint8_t tsc2005_txrx_word(void *opaque, uint8_t value) 330{ 331 TSC2005State *s = opaque; 332 uint32_t ret = 0; 333 334 switch (s->state ++) { 335 case 0: 336 if (value & 0x80) { 337 /* Command */ 338 if (value & (1 << 1)) 339 tsc2005_reset(s); 340 else { 341 s->nextfunction = (value >> 3) & 0xf; 342 s->nextprecision = (value >> 2) & 1; 343 if (s->enabled != !(value & 1)) { 344 s->enabled = !(value & 1); 345 trace_tsc2005_sense(s->enabled ? "enabled" : "disabled"); 346 if (s->busy && !s->enabled) 347 timer_del(s->timer); 348 s->busy = s->busy && s->enabled; 349 } 350 tsc2005_pin_update(s); 351 } 352 353 s->state = 0; 354 } else if (value) { 355 /* Data transfer */ 356 s->reg = (value >> 3) & 0xf; 357 s->pnd0 = (value >> 1) & 1; 358 s->command = value & 1; 359 360 if (s->command) { 361 /* Read */ 362 s->data = tsc2005_read(s, s->reg); 363 tsc2005_pin_update(s); 364 } else 365 s->data = 0; 366 } else 367 s->state = 0; 368 break; 369 370 case 1: 371 if (s->command) 372 ret = (s->data >> 8) & 0xff; 373 else 374 s->data |= value << 8; 375 break; 376 377 case 2: 378 if (s->command) 379 ret = s->data & 0xff; 380 else { 381 s->data |= value; 382 tsc2005_write(s, s->reg, s->data); 383 tsc2005_pin_update(s); 384 } 385 386 s->state = 0; 387 break; 388 } 389 390 return ret; 391} 392 393uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len) 394{ 395 uint32_t ret = 0; 396 397 len &= ~7; 398 while (len > 0) { 399 len -= 8; 400 ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len; 401 } 402 403 return ret; 404} 405 406static void tsc2005_timer_tick(void *opaque) 407{ 408 TSC2005State *s = opaque; 409 410 /* Timer ticked -- a set of conversions has been finished. */ 411 412 if (!s->busy) 413 return; 414 415 s->busy = false; 416 s->dav |= mode_regs[s->function]; 417 s->function = -1; 418 tsc2005_pin_update(s); 419} 420 421static void tsc2005_touchscreen_event(void *opaque, 422 int x, int y, int z, int buttons_state) 423{ 424 TSC2005State *s = opaque; 425 int p = s->pressure; 426 427 if (buttons_state) { 428 s->x = x; 429 s->y = y; 430 } 431 s->pressure = !!buttons_state; 432 433 /* 434 * Note: We would get better responsiveness in the guest by 435 * signaling TS events immediately, but for now we simulate 436 * the first conversion delay for sake of correctness. 437 */ 438 if (p != s->pressure) 439 tsc2005_pin_update(s); 440} 441 442static int tsc2005_post_load(void *opaque, int version_id) 443{ 444 TSC2005State *s = (TSC2005State *) opaque; 445 446 s->busy = timer_pending(s->timer); 447 tsc2005_pin_update(s); 448 449 return 0; 450} 451 452static const VMStateDescription vmstate_tsc2005 = { 453 .name = "tsc2005", 454 .version_id = 2, 455 .minimum_version_id = 2, 456 .post_load = tsc2005_post_load, 457 .fields = (VMStateField []) { 458 VMSTATE_BOOL(pressure, TSC2005State), 459 VMSTATE_BOOL(irq, TSC2005State), 460 VMSTATE_BOOL(command, TSC2005State), 461 VMSTATE_BOOL(enabled, TSC2005State), 462 VMSTATE_BOOL(host_mode, TSC2005State), 463 VMSTATE_BOOL(reset, TSC2005State), 464 VMSTATE_BOOL(pdst, TSC2005State), 465 VMSTATE_BOOL(pnd0, TSC2005State), 466 VMSTATE_BOOL(precision, TSC2005State), 467 VMSTATE_BOOL(nextprecision, TSC2005State), 468 VMSTATE_UINT8(reg, TSC2005State), 469 VMSTATE_UINT8(state, TSC2005State), 470 VMSTATE_UINT16(data, TSC2005State), 471 VMSTATE_UINT16(dav, TSC2005State), 472 VMSTATE_UINT16(filter, TSC2005State), 473 VMSTATE_INT8(nextfunction, TSC2005State), 474 VMSTATE_INT8(function, TSC2005State), 475 VMSTATE_INT32(x, TSC2005State), 476 VMSTATE_INT32(y, TSC2005State), 477 VMSTATE_TIMER_PTR(timer, TSC2005State), 478 VMSTATE_UINT8(pin_func, TSC2005State), 479 VMSTATE_UINT16_ARRAY(timing, TSC2005State, 2), 480 VMSTATE_UINT8(noise, TSC2005State), 481 VMSTATE_UINT16_ARRAY(temp_thr, TSC2005State, 2), 482 VMSTATE_UINT16_ARRAY(aux_thr, TSC2005State, 2), 483 VMSTATE_INT32_ARRAY(tr, TSC2005State, 8), 484 VMSTATE_END_OF_LIST() 485 } 486}; 487 488void *tsc2005_init(qemu_irq pintdav) 489{ 490 TSC2005State *s; 491 492 s = (TSC2005State *) 493 g_malloc0(sizeof(TSC2005State)); 494 s->x = 400; 495 s->y = 240; 496 s->pressure = false; 497 s->precision = s->nextprecision = false; 498 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, tsc2005_timer_tick, s); 499 s->pint = pintdav; 500 s->model = 0x2005; 501 502 s->tr[0] = 0; 503 s->tr[1] = 1; 504 s->tr[2] = 1; 505 s->tr[3] = 0; 506 s->tr[4] = 1; 507 s->tr[5] = 0; 508 s->tr[6] = 1; 509 s->tr[7] = 0; 510 511 tsc2005_reset(s); 512 513 qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1, 514 "QEMU TSC2005-driven Touchscreen"); 515 516 qemu_register_reset((void *) tsc2005_reset, s); 517 vmstate_register(NULL, 0, &vmstate_tsc2005, s); 518 519 return s; 520} 521 522/* 523 * Use tslib generated calibration data to generate ADC input values 524 * from the touchscreen. Assuming 12-bit precision was used during 525 * tslib calibration. 526 */ 527void tsc2005_set_transform(void *opaque, MouseTransformInfo *info) 528{ 529 TSC2005State *s = (TSC2005State *) opaque; 530 531 /* This version assumes touchscreen X & Y axis are parallel or 532 * perpendicular to LCD's X & Y axis in some way. */ 533 if (abs(info->a[0]) > abs(info->a[1])) { 534 s->tr[0] = 0; 535 s->tr[1] = -info->a[6] * info->x; 536 s->tr[2] = info->a[0]; 537 s->tr[3] = -info->a[2] / info->a[0]; 538 s->tr[4] = info->a[6] * info->y; 539 s->tr[5] = 0; 540 s->tr[6] = info->a[4]; 541 s->tr[7] = -info->a[5] / info->a[4]; 542 } else { 543 s->tr[0] = info->a[6] * info->y; 544 s->tr[1] = 0; 545 s->tr[2] = info->a[1]; 546 s->tr[3] = -info->a[2] / info->a[1]; 547 s->tr[4] = 0; 548 s->tr[5] = -info->a[6] * info->x; 549 s->tr[6] = info->a[3]; 550 s->tr[7] = -info->a[5] / info->a[3]; 551 } 552 553 s->tr[0] >>= 11; 554 s->tr[1] >>= 11; 555 s->tr[3] <<= 4; 556 s->tr[4] >>= 11; 557 s->tr[5] >>= 11; 558 s->tr[7] <<= 4; 559}