TOSC DAC i2c qdev voncersion
[qemu] / hw / max111x.c
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 MAX111xState {
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     MAX111xState *s = (MAX111xState *) 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     MAX111xState *s = (MAX111xState *) 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     MAX111xState *s = (MAX111xState *) 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     MAX111xState *s = (MAX111xState *) 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 MAX111xState *max111x_init(qemu_irq cb)
125 {
126     MAX111xState *s;
127     s = (MAX111xState *)
128             qemu_mallocz(sizeof(MAX111xState));
129     memset(s, 0, sizeof(MAX111xState));
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 MAX111xState *max1110_init(qemu_irq cb)
150 {
151     MAX111xState *s = max111x_init(cb);
152     s->inputs = 8;
153     return s;
154 }
155
156 MAX111xState *max1111_init(qemu_irq cb)
157 {
158     MAX111xState *s = max111x_init(cb);
159     s->inputs = 4;
160     return s;
161 }
162
163 void max111x_set_input(MAX111xState *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 }