Commit a5d7eb6534a091566d63f97c8b35c0ac9623d90b

Authored by balrog
1 parent 827df9f3

Add TSC2301 touchscreen & keypad controller.

Add also a facility for setting up touchscreen calibration data per-board
based on calibration data generated by tslib.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4214 c046a42c-6fe2-441c-8c8c-71466251a162
console.h
... ... @@ -32,6 +32,14 @@ void kbd_put_keycode(int keycode);
32 32 void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
33 33 int kbd_mouse_is_absolute(void);
34 34  
  35 +struct mouse_transform_info_s {
  36 + /* Touchscreen resolution */
  37 + int x;
  38 + int y;
  39 + /* Calibration values as used/generated by tslib */
  40 + int a[7];
  41 +};
  42 +
35 43 void do_info_mice(void);
36 44 void do_mouse_set(int index);
37 45  
... ...
hw/devices.h
... ... @@ -16,6 +16,18 @@ uint32_t ads7846_read(void *opaque);
16 16 void ads7846_write(void *opaque, uint32_t value);
17 17 struct ads7846_state_s *ads7846_init(qemu_irq penirq);
18 18  
  19 +/* tsc210x.c */
  20 +struct uwire_slave_s;
  21 +struct mouse_transform_info_s;
  22 +struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio);
  23 +struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq,
  24 + qemu_irq dav, AudioState *audio);
  25 +struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip);
  26 +uint32_t tsc210x_txrx(void *opaque, uint32_t value);
  27 +void tsc210x_set_transform(struct uwire_slave_s *chip,
  28 + struct mouse_transform_info_s *info);
  29 +void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down);
  30 +
19 31 /* stellaris_input.c */
20 32 void stellaris_gamepad_init(int n, qemu_irq *irq, const int *keycode);
21 33  
... ...
hw/omap.h
... ... @@ -1125,10 +1125,4 @@ inline static int debug_register_io_memory(int io_index,
1125 1125 # define cpu_register_io_memory debug_register_io_memory
1126 1126 # endif
1127 1127  
1128   -/* Not really omap specific, but is the only thing that uses the
1129   - uwire interface. */
1130   -/* tsc210x.c */
1131   -struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio);
1132   -struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip);
1133   -
1134 1128 #endif /* hw_omap_h */
... ...
hw/tsc210x.c
1 1 /*
2 2 * TI TSC2102 (touchscreen/sensors/audio controller) emulator.
  3 + * TI TSC2301 (touchscreen/sensors/keypad).
3 4 *
4 5 * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
  6 + * Copyright (C) 2008 Nokia Corporation
5 7 *
6 8 * This program is free software; you can redistribute it and/or
7 9 * modify it under the terms of the GNU General Public License as
8   - * published by the Free Software Foundation; either version 2 of
9   - * the License, or (at your option) any later version.
  10 + * published by the Free Software Foundation; either version 2 or
  11 + * (at your option) version 3 of the License.
10 12 *
11 13 * This program is distributed in the hope that it will be useful,
12 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
... ... @@ -35,12 +37,15 @@
35 37  
36 38 struct tsc210x_state_s {
37 39 qemu_irq pint;
  40 + qemu_irq kbint;
  41 + qemu_irq davint;
38 42 QEMUTimer *timer;
39 43 QEMUSoundCard card;
40 44 struct uwire_slave_s chip;
41 45 struct i2s_codec_s codec;
42 46 uint8_t in_fifo[16384];
43 47 uint8_t out_fifo[16384];
  48 + uint16_t model;
44 49  
45 50 int x, y;
46 51 int pressure;
... ... @@ -64,7 +69,7 @@ struct tsc210x_state_s {
64 69 uint16_t audio_ctrl1;
65 70 uint16_t audio_ctrl2;
66 71 uint16_t audio_ctrl3;
67   - uint16_t pll[2];
  72 + uint16_t pll[3];
68 73 uint16_t volume;
69 74 int64_t volume_change;
70 75 int softstep;
... ... @@ -78,6 +83,17 @@ struct tsc210x_state_s {
78 83 int i2s_rx_rate;
79 84 int i2s_tx_rate;
80 85 AudioState *audio;
  86 +
  87 + int tr[8];
  88 +
  89 + struct {
  90 + uint16_t down;
  91 + uint16_t mask;
  92 + int scan;
  93 + int debounce;
  94 + int mode;
  95 + int intr;
  96 + } kb;
81 97 };
82 98  
83 99 static const int resolution[4] = { 12, 8, 10, 12 };
... ... @@ -118,17 +134,10 @@ static const uint16_t mode_regs[16] = {
118 134 0x0000, /* Y+, X- drivers */
119 135 };
120 136  
121   -/*
122   - * Convert screen coordinates to arbitrary values that the
123   - * touchscreen in my Palm Tungsten E device returns.
124   - * This shouldn't really matter (because the guest system
125   - * should calibrate the touchscreen anyway), but let's
126   - * imitate some real hardware.
127   - */
128   -#define X_TRANSFORM(value) \
129   - ((3850 - ((int) (value) * (3850 - 250) / 32768)) << 4)
130   -#define Y_TRANSFORM(value) \
131   - ((150 + ((int) (value) * (3037 - 150) / 32768)) << 4)
  137 +#define X_TRANSFORM(s) \
  138 + ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
  139 +#define Y_TRANSFORM(s) \
  140 + ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
132 141 #define Z1_TRANSFORM(s) \
133 142 ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
134 143 #define Z2_TRANSFORM(s) \
... ... @@ -161,6 +170,7 @@ static void tsc210x_reset(struct tsc210x_state_s *s)
161 170 s->audio_ctrl3 = 0x0000;
162 171 s->pll[0] = 0x1004;
163 172 s->pll[1] = 0x0000;
  173 + s->pll[2] = 0x1fff;
164 174 s->volume = 0xffff;
165 175 s->dac_power = 0x8540;
166 176 s->softstep = 1;
... ... @@ -190,7 +200,15 @@ static void tsc210x_reset(struct tsc210x_state_s *s)
190 200 s->i2s_tx_rate = 0;
191 201 s->i2s_rx_rate = 0;
192 202  
  203 + s->kb.scan = 1;
  204 + s->kb.debounce = 0;
  205 + s->kb.mask = 0x0000;
  206 + s->kb.mode = 3;
  207 + s->kb.intr = 0;
  208 +
193 209 qemu_set_irq(s->pint, !s->irq);
  210 + qemu_set_irq(s->davint, !s->dav);
  211 + qemu_irq_raise(s->kbint);
194 212 }
195 213  
196 214 struct tsc210x_rate_info_s {
... ... @@ -344,13 +362,13 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg)
344 362 switch (reg) {
345 363 case 0x00: /* X */
346 364 s->dav &= 0xfbff;
347   - return TSC_CUT_RESOLUTION(X_TRANSFORM(s->x), s->precision) +
  365 + return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
348 366 (s->noise & 3);
349 367  
350 368 case 0x01: /* Y */
351 369 s->noise ++;
352 370 s->dav &= 0xfdff;
353   - return TSC_CUT_RESOLUTION(Y_TRANSFORM(s->y), s->precision) ^
  371 + return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
354 372 (s->noise & 3);
355 373  
356 374 case 0x02: /* Z1 */
... ... @@ -364,6 +382,14 @@ static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg)
364 382 (s->noise & 3);
365 383  
366 384 case 0x04: /* KPData */
  385 + if ((s->model & 0xff00) == 0x2300) {
  386 + if (s->kb.intr && (s->kb.mode & 2)) {
  387 + s->kb.intr = 0;
  388 + qemu_irq_raise(s->kbint);
  389 + }
  390 + return s->kb.down;
  391 + }
  392 +
367 393 return 0xffff;
368 394  
369 395 case 0x05: /* BAT1 */
... ... @@ -414,9 +440,19 @@ static uint16_t tsc2102_control_register_read(
414 440 return (s->pressure << 15) | ((!s->busy) << 14) |
415 441 (s->nextfunction << 10) | (s->nextprecision << 8) | s->filter;
416 442  
417   - case 0x01: /* Status */
418   - return (s->pin_func << 14) | ((!s->enabled) << 13) |
419   - (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav;
  443 + case 0x01: /* Status / Keypad Control */
  444 + if ((s->model & 0xff00) == 0x2100)
  445 + return (s->pin_func << 14) | ((!s->enabled) << 13) |
  446 + (s->host_mode << 12) | ((!!s->dav) << 11) | s->dav;
  447 + else
  448 + return (s->kb.intr << 15) | ((s->kb.scan || !s->kb.down) << 14) |
  449 + (s->kb.debounce << 11);
  450 +
  451 + case 0x02: /* DAC Control */
  452 + if ((s->model & 0xff00) == 0x2300)
  453 + return s->dac_power & 0x8000;
  454 + else
  455 + goto bad_reg;
420 456  
421 457 case 0x03: /* Reference */
422 458 return s->ref;
... ... @@ -427,7 +463,18 @@ static uint16_t tsc2102_control_register_read(
427 463 case 0x05: /* Configuration */
428 464 return s->timing;
429 465  
  466 + case 0x06: /* Secondary configuration */
  467 + if ((s->model & 0xff00) == 0x2100)
  468 + goto bad_reg;
  469 + return ((!s->dav) << 15) | ((s->kb.mode & 1) << 14) | s->pll[2];
  470 +
  471 + case 0x10: /* Keypad Mask */
  472 + if ((s->model & 0xff00) == 0x2100)
  473 + goto bad_reg;
  474 + return s->kb.mask;
  475 +
430 476 default:
  477 + bad_reg:
431 478 #ifdef TSC_VERBOSE
432 479 fprintf(stderr, "tsc2102_control_register_read: "
433 480 "no such register: 0x%02x\n", reg);
... ... @@ -556,10 +603,27 @@ static void tsc2102_control_register_write(
556 603 s->filter = value & 0xff;
557 604 return;
558 605  
559   - case 0x01: /* Status */
560   - s->pin_func = value >> 14;
  606 + case 0x01: /* Status / Keypad Control */
  607 + if ((s->model & 0xff00) == 0x2100)
  608 + s->pin_func = value >> 14;
  609 + else {
  610 + s->kb.scan = (value >> 14) & 1;
  611 + s->kb.debounce = (value >> 11) & 7;
  612 + if (s->kb.intr && s->kb.scan) {
  613 + s->kb.intr = 0;
  614 + qemu_irq_raise(s->kbint);
  615 + }
  616 + }
561 617 return;
562 618  
  619 + case 0x02: /* DAC Control */
  620 + if ((s->model & 0xff00) == 0x2300) {
  621 + s->dac_power &= 0x7fff;
  622 + s->dac_power |= 0x8000 & value;
  623 + } else
  624 + goto bad_reg;
  625 + break;
  626 +
563 627 case 0x03: /* Reference */
564 628 s->ref = value & 0x1f;
565 629 return;
... ... @@ -586,7 +650,21 @@ static void tsc2102_control_register_write(
586 650 #endif
587 651 return;
588 652  
  653 + case 0x06: /* Secondary configuration */
  654 + if ((s->model & 0xff00) == 0x2100)
  655 + goto bad_reg;
  656 + s->kb.mode = value >> 14;
  657 + s->pll[2] = value & 0x3ffff;
  658 + return;
  659 +
  660 + case 0x10: /* Keypad Mask */
  661 + if ((s->model & 0xff00) == 0x2100)
  662 + goto bad_reg;
  663 + s->kb.mask = value;
  664 + return;
  665 +
589 666 default:
  667 + bad_reg:
590 668 #ifdef TSC_VERBOSE
591 669 fprintf(stderr, "tsc2102_control_register_write: "
592 670 "no such register: 0x%02x\n", reg);
... ... @@ -785,7 +863,7 @@ static void tsc210x_pin_update(struct tsc210x_state_s *s)
785 863 return;
786 864 }
787 865  
788   - if (!s->enabled || s->busy)
  866 + if (!s->enabled || s->busy || s->dav)
789 867 return;
790 868  
791 869 s->busy = 1;
... ... @@ -805,6 +883,8 @@ static uint16_t tsc210x_read(struct tsc210x_state_s *s)
805 883 switch (s->page) {
806 884 case TSC_DATA_REGISTERS_PAGE:
807 885 ret = tsc2102_data_register_read(s, s->offset);
  886 + if (!s->dav)
  887 + qemu_irq_raise(s->davint);
808 888 break;
809 889 case TSC_CONTROL_REGISTERS_PAGE:
810 890 ret = tsc2102_control_register_read(s, s->offset);
... ... @@ -859,6 +939,22 @@ static void tsc210x_write(struct tsc210x_state_s *s, uint16_t value)
859 939 }
860 940 }
861 941  
  942 +uint32_t tsc210x_txrx(void *opaque, uint32_t value)
  943 +{
  944 + struct tsc210x_state_s *s = opaque;
  945 + uint32_t ret = 0;
  946 +
  947 + /* TODO: sequential reads etc - how do we make sure the host doesn't
  948 + * unintentionally read out a conversion result from a register while
  949 + * transmitting the command word of the next command? */
  950 + if (!value || (s->state && s->command))
  951 + ret = tsc210x_read(s);
  952 + if (value || (s->state && !s->command))
  953 + tsc210x_write(s, value);
  954 +
  955 + return ret;
  956 +}
  957 +
862 958 static void tsc210x_timer_tick(void *opaque)
863 959 {
864 960 struct tsc210x_state_s *s = opaque;
... ... @@ -871,6 +967,7 @@ static void tsc210x_timer_tick(void *opaque)
871 967 s->busy = 0;
872 968 s->dav |= mode_regs[s->function];
873 969 tsc210x_pin_update(s);
  970 + qemu_irq_lower(s->davint);
874 971 }
875 972  
876 973 static void tsc210x_touchscreen_event(void *opaque,
... ... @@ -1001,6 +1098,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id)
1001 1098  
1002 1099 s->busy = qemu_timer_pending(s->timer);
1003 1100 qemu_set_irq(s->pint, !s->irq);
  1101 + qemu_set_irq(s->davint, !s->dav);
1004 1102  
1005 1103 return 0;
1006 1104 }
... ... @@ -1020,9 +1118,19 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio)
1020 1118 s->precision = s->nextprecision = 0;
1021 1119 s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s);
1022 1120 s->pint = pint;
  1121 + s->model = 0x2102;
1023 1122 s->name = "tsc2102";
1024 1123 s->audio = audio;
1025 1124  
  1125 + s->tr[0] = 0;
  1126 + s->tr[1] = 1;
  1127 + s->tr[2] = 0;
  1128 + s->tr[3] = 1;
  1129 + s->tr[4] = 1;
  1130 + s->tr[5] = 0;
  1131 + s->tr[6] = 0;
  1132 + s->tr[7] = 1;
  1133 +
1026 1134 s->chip.opaque = s;
1027 1135 s->chip.send = (void *) tsc210x_write;
1028 1136 s->chip.receive = (void *) tsc210x_read;
... ... @@ -1048,9 +1156,149 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio)
1048 1156 return &s->chip;
1049 1157 }
1050 1158  
  1159 +struct uwire_slave_s *tsc2301_init(qemu_irq penirq, qemu_irq kbirq,
  1160 + qemu_irq dav, AudioState *audio)
  1161 +{
  1162 + struct tsc210x_state_s *s;
  1163 +
  1164 + s = (struct tsc210x_state_s *)
  1165 + qemu_mallocz(sizeof(struct tsc210x_state_s));
  1166 + memset(s, 0, sizeof(struct tsc210x_state_s));
  1167 + s->x = 400;
  1168 + s->y = 240;
  1169 + s->pressure = 0;
  1170 + s->precision = s->nextprecision = 0;
  1171 + s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s);
  1172 + s->pint = penirq;
  1173 + s->kbint = kbirq;
  1174 + s->davint = dav;
  1175 + s->model = 0x2301;
  1176 + s->name = "tsc2301";
  1177 + s->audio = audio;
  1178 +
  1179 + s->tr[0] = 0;
  1180 + s->tr[1] = 1;
  1181 + s->tr[2] = 0;
  1182 + s->tr[3] = 1;
  1183 + s->tr[4] = 1;
  1184 + s->tr[5] = 0;
  1185 + s->tr[6] = 0;
  1186 + s->tr[7] = 1;
  1187 +
  1188 + s->chip.opaque = s;
  1189 + s->chip.send = (void *) tsc210x_write;
  1190 + s->chip.receive = (void *) tsc210x_read;
  1191 +
  1192 + s->codec.opaque = s;
  1193 + s->codec.tx_swallow = (void *) tsc210x_i2s_swallow;
  1194 + s->codec.set_rate = (void *) tsc210x_i2s_set_rate;
  1195 + s->codec.in.fifo = s->in_fifo;
  1196 + s->codec.out.fifo = s->out_fifo;
  1197 +
  1198 + tsc210x_reset(s);
  1199 +
  1200 + qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1,
  1201 + "QEMU TSC2301-driven Touchscreen");
  1202 +
  1203 + if (s->audio)
  1204 + AUD_register_card(s->audio, s->name, &s->card);
  1205 +
  1206 + qemu_register_reset((void *) tsc210x_reset, s);
  1207 + register_savevm(s->name, tsc2102_iid ++, 0,
  1208 + tsc210x_save, tsc210x_load, s);
  1209 +
  1210 + return &s->chip;
  1211 +}
  1212 +
1051 1213 struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip)
1052 1214 {
1053 1215 struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque;
1054 1216  
1055 1217 return &s->codec;
1056 1218 }
  1219 +
  1220 +/*
  1221 + * Use tslib generated calibration data to generate ADC input values
  1222 + * from the touchscreen. Assuming 12-bit precision was used during
  1223 + * tslib calibration.
  1224 + */
  1225 +void tsc210x_set_transform(struct uwire_slave_s *chip,
  1226 + struct mouse_transform_info_s *info)
  1227 +{
  1228 + struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque;
  1229 +#if 0
  1230 + int64_t ltr[8];
  1231 +
  1232 + ltr[0] = (int64_t) info->a[1] * info->y;
  1233 + ltr[1] = (int64_t) info->a[4] * info->x;
  1234 + ltr[2] = (int64_t) info->a[1] * info->a[3] -
  1235 + (int64_t) info->a[4] * info->a[0];
  1236 + ltr[3] = (int64_t) info->a[2] * info->a[4] -
  1237 + (int64_t) info->a[5] * info->a[1];
  1238 + ltr[4] = (int64_t) info->a[0] * info->y;
  1239 + ltr[5] = (int64_t) info->a[3] * info->x;
  1240 + ltr[6] = (int64_t) info->a[4] * info->a[0] -
  1241 + (int64_t) info->a[1] * info->a[3];
  1242 + ltr[7] = (int64_t) info->a[2] * info->a[3] -
  1243 + (int64_t) info->a[5] * info->a[0];
  1244 +
  1245 + /* Avoid integer overflow */
  1246 + s->tr[0] = ltr[0] >> 11;
  1247 + s->tr[1] = ltr[1] >> 11;
  1248 + s->tr[2] = muldiv64(ltr[2], 1, info->a[6]);
  1249 + s->tr[3] = muldiv64(ltr[3], 1 << 4, ltr[2]);
  1250 + s->tr[4] = ltr[4] >> 11;
  1251 + s->tr[5] = ltr[5] >> 11;
  1252 + s->tr[6] = muldiv64(ltr[6], 1, info->a[6]);
  1253 + s->tr[7] = muldiv64(ltr[7], 1 << 4, ltr[6]);
  1254 +#else
  1255 +
  1256 + /* This version assumes touchscreen X & Y axis are parallel or
  1257 + * perpendicular to LCD's X & Y axis in some way. */
  1258 + if (abs(info->a[0]) > abs(info->a[1])) {
  1259 + s->tr[0] = 0;
  1260 + s->tr[1] = -info->a[6] * info->x;
  1261 + s->tr[2] = info->a[0];
  1262 + s->tr[3] = -info->a[2] / info->a[0];
  1263 + s->tr[4] = info->a[6] * info->y;
  1264 + s->tr[5] = 0;
  1265 + s->tr[6] = info->a[4];
  1266 + s->tr[7] = -info->a[5] / info->a[4];
  1267 + } else {
  1268 + s->tr[0] = info->a[6] * info->y;
  1269 + s->tr[1] = 0;
  1270 + s->tr[2] = info->a[1];
  1271 + s->tr[3] = -info->a[2] / info->a[1];
  1272 + s->tr[4] = 0;
  1273 + s->tr[5] = -info->a[6] * info->x;
  1274 + s->tr[6] = info->a[3];
  1275 + s->tr[7] = -info->a[5] / info->a[3];
  1276 + }
  1277 +
  1278 + s->tr[0] >>= 11;
  1279 + s->tr[1] >>= 11;
  1280 + s->tr[3] <<= 4;
  1281 + s->tr[4] >>= 11;
  1282 + s->tr[5] >>= 11;
  1283 + s->tr[7] <<= 4;
  1284 +#endif
  1285 +}
  1286 +
  1287 +void tsc210x_key_event(struct uwire_slave_s *chip, int key, int down)
  1288 +{
  1289 + struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque;
  1290 +
  1291 + if (down)
  1292 + s->kb.down |= 1 << key;
  1293 + else
  1294 + s->kb.down &= ~(1 << key);
  1295 +
  1296 + if (down && (s->kb.down & ~s->kb.mask) && !s->kb.intr) {
  1297 + s->kb.intr = 1;
  1298 + qemu_irq_lower(s->kbint);
  1299 + } else if (s->kb.intr && !(s->kb.down & ~s->kb.mask) &&
  1300 + !(s->kb.mode & 1)) {
  1301 + s->kb.intr = 0;
  1302 + qemu_irq_raise(s->kbint);
  1303 + }
  1304 +}
... ...