Commit fd5a3b33d1f19b4859a8c528097abdbc4463e7e0
1 parent
3e3d5815
Texas Instruments ADS7846 ADC chip.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2754 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
137 additions
and
0 deletions
hw/ads7846.c
0 → 100644
1 | +/* | |
2 | + * TI ADS7846 chip emulation. | |
3 | + * | |
4 | + * Copyright (c) 2006 Openedhand Ltd. | |
5 | + * Written by Andrzej Zaborowski <balrog@zabor.org> | |
6 | + * | |
7 | + * This code is licensed under the GNU GPL v2. | |
8 | + */ | |
9 | + | |
10 | +#include <vl.h> | |
11 | + | |
12 | +struct ads7846_state_s { | |
13 | + qemu_irq interrupt; | |
14 | + | |
15 | + int input[8]; | |
16 | + int pressure; | |
17 | + int noise; | |
18 | + | |
19 | + int cycle; | |
20 | + int output; | |
21 | +}; | |
22 | + | |
23 | +/* Control-byte bitfields */ | |
24 | +#define CB_PD0 (1 << 0) | |
25 | +#define CB_PD1 (1 << 1) | |
26 | +#define CB_SER (1 << 2) | |
27 | +#define CB_MODE (1 << 3) | |
28 | +#define CB_A0 (1 << 4) | |
29 | +#define CB_A1 (1 << 5) | |
30 | +#define CB_A2 (1 << 6) | |
31 | +#define CB_START (1 << 7) | |
32 | + | |
33 | +#define X_AXIS_DMAX 3680 | |
34 | +#define X_AXIS_MIN 150 | |
35 | +#define Y_AXIS_DMAX 3640 | |
36 | +#define Y_AXIS_MIN 190 | |
37 | + | |
38 | +#define ADS_VBAT 2000 | |
39 | +#define ADS_VAUX 2000 | |
40 | +#define ADS_TEMP0 2000 | |
41 | +#define ADS_TEMP1 3000 | |
42 | +#define ADS_XPOS(x, y) (X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15)) | |
43 | +#define ADS_YPOS(x, y) (Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15)) | |
44 | +#define ADS_Z1POS(x, y) 600 | |
45 | +#define ADS_Z2POS(x, y) (600 + 6000 / ADS_XPOS(x, y)) | |
46 | + | |
47 | +static void ads7846_int_update(struct ads7846_state_s *s) | |
48 | +{ | |
49 | + if (s->interrupt) | |
50 | + qemu_set_irq(s->interrupt, s->pressure == 0); | |
51 | +} | |
52 | + | |
53 | +uint32_t ads7846_read(void *opaque) | |
54 | +{ | |
55 | + struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; | |
56 | + | |
57 | + return s->output; | |
58 | +} | |
59 | + | |
60 | +void ads7846_write(void *opaque, uint32_t value) | |
61 | +{ | |
62 | + struct ads7846_state_s *s = (struct ads7846_state_s *) opaque; | |
63 | + | |
64 | + switch (s->cycle ++) { | |
65 | + case 0: | |
66 | + if (!(value & CB_START)) { | |
67 | + s->cycle = 0; | |
68 | + break; | |
69 | + } | |
70 | + | |
71 | + s->output = s->input[(value >> 4) & 7]; | |
72 | + | |
73 | + /* Imitate the ADC noise, some drivers expect this. */ | |
74 | + s->noise = (s->noise + 3) & 7; | |
75 | + switch ((value >> 4) & 7) { | |
76 | + case 1: s->output += s->noise ^ 2; break; | |
77 | + case 3: s->output += s->noise ^ 0; break; | |
78 | + case 4: s->output += s->noise ^ 7; break; | |
79 | + case 5: s->output += s->noise ^ 5; break; | |
80 | + } | |
81 | + | |
82 | + if (value & CB_MODE) | |
83 | + s->output >>= 4; /* 8 bits instead of 12 */ | |
84 | + | |
85 | + break; | |
86 | + case 1: | |
87 | + s->cycle = 0; | |
88 | + break; | |
89 | + } | |
90 | +} | |
91 | + | |
92 | +static void ads7846_ts_event(void *opaque, | |
93 | + int x, int y, int z, int buttons_state) | |
94 | +{ | |
95 | + struct ads7846_state_s *s = opaque; | |
96 | + | |
97 | + if (buttons_state) { | |
98 | + s->input[1] = ADS_YPOS(x, y); | |
99 | + s->input[3] = ADS_Z1POS(x, y); | |
100 | + s->input[4] = ADS_Z2POS(x, y); | |
101 | + s->input[5] = ADS_XPOS(x, y); | |
102 | + } | |
103 | + | |
104 | + if (s->pressure == !buttons_state) { | |
105 | + s->pressure = !!buttons_state; | |
106 | + | |
107 | + ads7846_int_update(s); | |
108 | + } | |
109 | +} | |
110 | + | |
111 | +struct ads7846_state_s *ads7846_init(qemu_irq penirq) | |
112 | +{ | |
113 | + struct ads7846_state_s *s; | |
114 | + s = (struct ads7846_state_s *) | |
115 | + qemu_mallocz(sizeof(struct ads7846_state_s)); | |
116 | + memset(s, 0, sizeof(struct ads7846_state_s)); | |
117 | + | |
118 | + s->interrupt = penirq; | |
119 | + | |
120 | + s->input[0] = ADS_TEMP0; /* TEMP0 */ | |
121 | + s->input[2] = ADS_VBAT; /* VBAT */ | |
122 | + s->input[6] = ADS_VAUX; /* VAUX */ | |
123 | + s->input[7] = ADS_TEMP1; /* TEMP1 */ | |
124 | + | |
125 | + /* We want absolute coordinates */ | |
126 | + qemu_add_mouse_event_handler(ads7846_ts_event, s, 1, | |
127 | + "QEMU ADS7846-driven Touchscreen"); | |
128 | + | |
129 | + ads7846_int_update(s); | |
130 | + return s; | |
131 | +} | ... | ... |
vl.h
... | ... | @@ -1500,6 +1500,12 @@ uint8_t nand_getio(struct nand_flash_s *s); |
1500 | 1500 | |
1501 | 1501 | #include "ecc.h" |
1502 | 1502 | |
1503 | +/* ads7846.c */ | |
1504 | +struct ads7846_state_s; | |
1505 | +uint32_t ads7846_read(void *opaque); | |
1506 | +void ads7846_write(void *opaque, uint32_t value); | |
1507 | +struct ads7846_state_s *ads7846_init(qemu_irq penirq); | |
1508 | + | |
1503 | 1509 | /* PCMCIA/Cardbus */ |
1504 | 1510 | |
1505 | 1511 | struct pcmcia_socket_s { | ... | ... |