|
|
1.1 root 1: /*
2: * TI ADS7846 / TSC2046 chip emulation.
3: *
4: * Copyright (c) 2006 Openedhand Ltd.
5: * Written by Andrzej Zaborowski <[email protected]>
6: *
7: * This code is licensed under the GNU GPL v2.
8: */
9:
10: #include "hw.h"
11: #include "devices.h"
12: #include "console.h"
13:
14: struct ads7846_state_s {
15: qemu_irq interrupt;
16:
17: int input[8];
18: int pressure;
19: int noise;
20:
21: int cycle;
22: int output;
23: };
24:
25: /* Control-byte bitfields */
26: #define CB_PD0 (1 << 0)
27: #define CB_PD1 (1 << 1)
28: #define CB_SER (1 << 2)
29: #define CB_MODE (1 << 3)
30: #define CB_A0 (1 << 4)
31: #define CB_A1 (1 << 5)
32: #define CB_A2 (1 << 6)
33: #define CB_START (1 << 7)
34:
35: #define X_AXIS_DMAX 3470
36: #define X_AXIS_MIN 290
37: #define Y_AXIS_DMAX 3450
38: #define Y_AXIS_MIN 200
39:
40: #define ADS_VBAT 2000
41: #define ADS_VAUX 2000
42: #define ADS_TEMP0 2000
43: #define ADS_TEMP1 3000
44: #define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
45: #define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
46: #define ADS_Z1POS(x, y) 600
47: #define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y))
48:
49: static void ads7846_int_update(struct ads7846_state_s *s)
50: {
51: if (s->interrupt)
52: qemu_set_irq(s->interrupt, s->pressure == 0);
53: }
54:
55: uint32_t ads7846_read(void *opaque)
56: {
57: struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
58:
59: return s->output;
60: }
61:
62: void ads7846_write(void *opaque, uint32_t value)
63: {
64: struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
65:
66: switch (s->cycle ++) {
67: case 0:
68: if (!(value & CB_START)) {
69: s->cycle = 0;
70: break;
71: }
72:
73: s->output = s->input[(value >> 4) & 7];
74:
75: /* Imitate the ADC noise, some drivers expect this. */
76: s->noise = (s->noise + 3) & 7;
77: switch ((value >> 4) & 7) {
78: case 1: s->output += s->noise ^ 2; break;
79: case 3: s->output += s->noise ^ 0; break;
80: case 4: s->output += s->noise ^ 7; break;
81: case 5: s->output += s->noise ^ 5; break;
82: }
83:
84: if (value & CB_MODE)
85: s->output >>= 4; /* 8 bits instead of 12 */
86:
87: break;
88: case 1:
89: s->cycle = 0;
90: break;
91: }
92: }
93:
94: static void ads7846_ts_event(void *opaque,
95: int x, int y, int z, int buttons_state)
96: {
97: struct ads7846_state_s *s = opaque;
98:
99: if (buttons_state) {
100: x = 0x7fff - x;
101: s->input[1] = ADS_XPOS(x, y);
102: s->input[3] = ADS_Z1POS(x, y);
103: s->input[4] = ADS_Z2POS(x, y);
104: s->input[5] = ADS_YPOS(x, y);
105: }
106:
107: if (s->pressure == !buttons_state) {
108: s->pressure = !!buttons_state;
109:
110: ads7846_int_update(s);
111: }
112: }
113:
114: static void ads7846_save(QEMUFile *f, void *opaque)
115: {
116: struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
117: int i;
118:
119: for (i = 0; i < 8; i ++)
120: qemu_put_be32(f, s->input[i]);
121: qemu_put_be32(f, s->noise);
122: qemu_put_be32(f, s->cycle);
123: qemu_put_be32(f, s->output);
124: }
125:
126: static int ads7846_load(QEMUFile *f, void *opaque, int version_id)
127: {
128: struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
129: int i;
130:
131: for (i = 0; i < 8; i ++)
132: s->input[i] = qemu_get_be32(f);
133: s->noise = qemu_get_be32(f);
134: s->cycle = qemu_get_be32(f);
135: s->output = qemu_get_be32(f);
136:
137: s->pressure = 0;
138: ads7846_int_update(s);
139:
140: return 0;
141: }
142:
143: static int ads7846_iid = 0;
144:
145: struct ads7846_state_s *ads7846_init(qemu_irq penirq)
146: {
147: struct ads7846_state_s *s;
148: s = (struct ads7846_state_s *)
149: qemu_mallocz(sizeof(struct ads7846_state_s));
150: memset(s, 0, sizeof(struct ads7846_state_s));
151:
152: s->interrupt = penirq;
153:
154: s->input[0] = ADS_TEMP0; /* TEMP0 */
155: s->input[2] = ADS_VBAT; /* VBAT */
156: s->input[6] = ADS_VAUX; /* VAUX */
157: s->input[7] = ADS_TEMP1; /* TEMP1 */
158:
159: /* We want absolute coordinates */
160: qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
161: "QEMU ADS7846-driven Touchscreen");
162:
163: ads7846_int_update(s);
164:
165: register_savevm("ads7846", ads7846_iid ++, 0,
166: ads7846_save, ads7846_load, s);
167:
168: return s;
169: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.