|
1 /* |
|
2 * Maxim MAX1110/1111 ADC 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 GPLv2. |
|
8 */ |
|
9 |
|
10 #include "hw.h" |
|
11 #include "i2c.h" |
|
12 |
|
13 struct max111x_s { |
|
14 qemu_irq interrupt; |
|
15 uint8_t tb1, rb2, rb3; |
|
16 int cycle; |
|
17 |
|
18 int input[8]; |
|
19 int inputs, com; |
|
20 }; |
|
21 |
|
22 /* Control-byte bitfields */ |
|
23 #define CB_PD0 (1 << 0) |
|
24 #define CB_PD1 (1 << 1) |
|
25 #define CB_SGL (1 << 2) |
|
26 #define CB_UNI (1 << 3) |
|
27 #define CB_SEL0 (1 << 4) |
|
28 #define CB_SEL1 (1 << 5) |
|
29 #define CB_SEL2 (1 << 6) |
|
30 #define CB_START (1 << 7) |
|
31 |
|
32 #define CHANNEL_NUM(v, b0, b1, b2) \ |
|
33 ((((v) >> (2 + (b0))) & 4) | \ |
|
34 (((v) >> (3 + (b1))) & 2) | \ |
|
35 (((v) >> (4 + (b2))) & 1)) |
|
36 |
|
37 uint32_t max111x_read(void *opaque) |
|
38 { |
|
39 struct max111x_s *s = (struct max111x_s *) opaque; |
|
40 |
|
41 if (!s->tb1) |
|
42 return 0; |
|
43 |
|
44 switch (s->cycle ++) { |
|
45 case 1: |
|
46 return s->rb2; |
|
47 case 2: |
|
48 return s->rb3; |
|
49 } |
|
50 |
|
51 return 0; |
|
52 } |
|
53 |
|
54 /* Interpret a control-byte */ |
|
55 void max111x_write(void *opaque, uint32_t value) |
|
56 { |
|
57 struct max111x_s *s = (struct max111x_s *) opaque; |
|
58 int measure, chan; |
|
59 |
|
60 /* Ignore the value if START bit is zero */ |
|
61 if (!(value & CB_START)) |
|
62 return; |
|
63 |
|
64 s->cycle = 0; |
|
65 |
|
66 if (!(value & CB_PD1)) { |
|
67 s->tb1 = 0; |
|
68 return; |
|
69 } |
|
70 |
|
71 s->tb1 = value; |
|
72 |
|
73 if (s->inputs == 8) |
|
74 chan = CHANNEL_NUM(value, 1, 0, 2); |
|
75 else |
|
76 chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2); |
|
77 |
|
78 if (value & CB_SGL) |
|
79 measure = s->input[chan] - s->com; |
|
80 else |
|
81 measure = s->input[chan] - s->input[chan ^ 1]; |
|
82 |
|
83 if (!(value & CB_UNI)) |
|
84 measure ^= 0x80; |
|
85 |
|
86 s->rb2 = (measure >> 2) & 0x3f; |
|
87 s->rb3 = (measure << 6) & 0xc0; |
|
88 |
|
89 if (s->interrupt) |
|
90 qemu_irq_raise(s->interrupt); |
|
91 } |
|
92 |
|
93 static void max111x_save(QEMUFile *f, void *opaque) |
|
94 { |
|
95 struct max111x_s *s = (struct max111x_s *) opaque; |
|
96 int i; |
|
97 |
|
98 qemu_put_8s(f, &s->tb1); |
|
99 qemu_put_8s(f, &s->rb2); |
|
100 qemu_put_8s(f, &s->rb3); |
|
101 qemu_put_be32(f, s->inputs); |
|
102 qemu_put_be32(f, s->com); |
|
103 for (i = 0; i < s->inputs; i ++) |
|
104 qemu_put_byte(f, s->input[i]); |
|
105 } |
|
106 |
|
107 static int max111x_load(QEMUFile *f, void *opaque, int version_id) |
|
108 { |
|
109 struct max111x_s *s = (struct max111x_s *) opaque; |
|
110 int i; |
|
111 |
|
112 qemu_get_8s(f, &s->tb1); |
|
113 qemu_get_8s(f, &s->rb2); |
|
114 qemu_get_8s(f, &s->rb3); |
|
115 if (s->inputs != qemu_get_be32(f)) |
|
116 return -EINVAL; |
|
117 s->com = qemu_get_be32(f); |
|
118 for (i = 0; i < s->inputs; i ++) |
|
119 s->input[i] = qemu_get_byte(f); |
|
120 |
|
121 return 0; |
|
122 } |
|
123 |
|
124 static struct max111x_s *max111x_init(qemu_irq cb) |
|
125 { |
|
126 struct max111x_s *s; |
|
127 s = (struct max111x_s *) |
|
128 qemu_mallocz(sizeof(struct max111x_s)); |
|
129 memset(s, 0, sizeof(struct max111x_s)); |
|
130 |
|
131 s->interrupt = cb; |
|
132 |
|
133 /* TODO: add a user interface for setting these */ |
|
134 s->input[0] = 0xf0; |
|
135 s->input[1] = 0xe0; |
|
136 s->input[2] = 0xd0; |
|
137 s->input[3] = 0xc0; |
|
138 s->input[4] = 0xb0; |
|
139 s->input[5] = 0xa0; |
|
140 s->input[6] = 0x90; |
|
141 s->input[7] = 0x80; |
|
142 s->com = 0; |
|
143 |
|
144 register_savevm("max111x", -1, 0, max111x_save, max111x_load, s); |
|
145 |
|
146 return s; |
|
147 } |
|
148 |
|
149 struct max111x_s *max1110_init(qemu_irq cb) |
|
150 { |
|
151 struct max111x_s *s = max111x_init(cb); |
|
152 s->inputs = 8; |
|
153 return s; |
|
154 } |
|
155 |
|
156 struct max111x_s *max1111_init(qemu_irq cb) |
|
157 { |
|
158 struct max111x_s *s = max111x_init(cb); |
|
159 s->inputs = 4; |
|
160 return s; |
|
161 } |
|
162 |
|
163 void max111x_set_input(struct max111x_s *s, int line, uint8_t value) |
|
164 { |
|
165 if (line >= s->inputs) { |
|
166 printf("%s: There's no input %i\n", __FUNCTION__, line); |
|
167 return; |
|
168 } |
|
169 |
|
170 s->input[line] = value; |
|
171 } |