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,6 +1500,12 @@ uint8_t nand_getio(struct nand_flash_s *s); | ||
1500 | 1500 | ||
1501 | #include "ecc.h" | 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 | /* PCMCIA/Cardbus */ | 1509 | /* PCMCIA/Cardbus */ |
1504 | 1510 | ||
1505 | struct pcmcia_socket_s { | 1511 | struct pcmcia_socket_s { |