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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
}
|