These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / hw / misc / 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  * Contributions after 2012-01-13 are licensed under the terms of the
10  * GNU GPL, version 2 or (at your option) any later version.
11  */
12
13 #include "qemu/osdep.h"
14 #include "hw/ssi/ssi.h"
15
16 typedef struct {
17     SSISlave parent_obj;
18
19     qemu_irq interrupt;
20     uint8_t tb1, rb2, rb3;
21     int cycle;
22
23     uint8_t input[8];
24     int inputs, com;
25 } MAX111xState;
26
27 #define TYPE_MAX_111X "max111x"
28
29 #define MAX_111X(obj) \
30     OBJECT_CHECK(MAX111xState, (obj), TYPE_MAX_111X)
31
32 #define TYPE_MAX_1110 "max1110"
33 #define TYPE_MAX_1111 "max1111"
34
35 /* Control-byte bitfields */
36 #define CB_PD0          (1 << 0)
37 #define CB_PD1          (1 << 1)
38 #define CB_SGL          (1 << 2)
39 #define CB_UNI          (1 << 3)
40 #define CB_SEL0         (1 << 4)
41 #define CB_SEL1         (1 << 5)
42 #define CB_SEL2         (1 << 6)
43 #define CB_START        (1 << 7)
44
45 #define CHANNEL_NUM(v, b0, b1, b2)      \
46                         ((((v) >> (2 + (b0))) & 4) |    \
47                          (((v) >> (3 + (b1))) & 2) |    \
48                          (((v) >> (4 + (b2))) & 1))
49
50 static uint32_t max111x_read(MAX111xState *s)
51 {
52     if (!s->tb1)
53         return 0;
54
55     switch (s->cycle ++) {
56     case 1:
57         return s->rb2;
58     case 2:
59         return s->rb3;
60     }
61
62     return 0;
63 }
64
65 /* Interpret a control-byte */
66 static void max111x_write(MAX111xState *s, uint32_t value)
67 {
68     int measure, chan;
69
70     /* Ignore the value if START bit is zero */
71     if (!(value & CB_START))
72         return;
73
74     s->cycle = 0;
75
76     if (!(value & CB_PD1)) {
77         s->tb1 = 0;
78         return;
79     }
80
81     s->tb1 = value;
82
83     if (s->inputs == 8)
84         chan = CHANNEL_NUM(value, 1, 0, 2);
85     else
86         chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2);
87
88     if (value & CB_SGL)
89         measure = s->input[chan] - s->com;
90     else
91         measure = s->input[chan] - s->input[chan ^ 1];
92
93     if (!(value & CB_UNI))
94         measure ^= 0x80;
95
96     s->rb2 = (measure >> 2) & 0x3f;
97     s->rb3 = (measure << 6) & 0xc0;
98
99     /* FIXME: When should the IRQ be lowered?  */
100     qemu_irq_raise(s->interrupt);
101 }
102
103 static uint32_t max111x_transfer(SSISlave *dev, uint32_t value)
104 {
105     MAX111xState *s = MAX_111X(dev);
106     max111x_write(s, value);
107     return max111x_read(s);
108 }
109
110 static const VMStateDescription vmstate_max111x = {
111     .name = "max111x",
112     .version_id = 1,
113     .minimum_version_id = 1,
114     .fields = (VMStateField[]) {
115         VMSTATE_SSI_SLAVE(parent_obj, MAX111xState),
116         VMSTATE_UINT8(tb1, MAX111xState),
117         VMSTATE_UINT8(rb2, MAX111xState),
118         VMSTATE_UINT8(rb3, MAX111xState),
119         VMSTATE_INT32_EQUAL(inputs, MAX111xState),
120         VMSTATE_INT32(com, MAX111xState),
121         VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs,
122                                    vmstate_info_uint8, uint8_t),
123         VMSTATE_END_OF_LIST()
124     }
125 };
126
127 static int max111x_init(SSISlave *d, int inputs)
128 {
129     DeviceState *dev = DEVICE(d);
130     MAX111xState *s = MAX_111X(dev);
131
132     qdev_init_gpio_out(dev, &s->interrupt, 1);
133
134     s->inputs = inputs;
135     /* TODO: add a user interface for setting these */
136     s->input[0] = 0xf0;
137     s->input[1] = 0xe0;
138     s->input[2] = 0xd0;
139     s->input[3] = 0xc0;
140     s->input[4] = 0xb0;
141     s->input[5] = 0xa0;
142     s->input[6] = 0x90;
143     s->input[7] = 0x80;
144     s->com = 0;
145
146     vmstate_register(dev, -1, &vmstate_max111x, s);
147     return 0;
148 }
149
150 static int max1110_init(SSISlave *dev)
151 {
152     return max111x_init(dev, 8);
153 }
154
155 static int max1111_init(SSISlave *dev)
156 {
157     return max111x_init(dev, 4);
158 }
159
160 void max111x_set_input(DeviceState *dev, int line, uint8_t value)
161 {
162     MAX111xState *s = MAX_111X(dev);
163     assert(line >= 0 && line < s->inputs);
164     s->input[line] = value;
165 }
166
167 static void max111x_class_init(ObjectClass *klass, void *data)
168 {
169     SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
170
171     k->transfer = max111x_transfer;
172 }
173
174 static const TypeInfo max111x_info = {
175     .name          = TYPE_MAX_111X,
176     .parent        = TYPE_SSI_SLAVE,
177     .instance_size = sizeof(MAX111xState),
178     .class_init    = max111x_class_init,
179     .abstract      = true,
180 };
181
182 static void max1110_class_init(ObjectClass *klass, void *data)
183 {
184     SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
185
186     k->init = max1110_init;
187 }
188
189 static const TypeInfo max1110_info = {
190     .name          = TYPE_MAX_1110,
191     .parent        = TYPE_MAX_111X,
192     .class_init    = max1110_class_init,
193 };
194
195 static void max1111_class_init(ObjectClass *klass, void *data)
196 {
197     SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
198
199     k->init = max1111_init;
200 }
201
202 static const TypeInfo max1111_info = {
203     .name          = TYPE_MAX_1111,
204     .parent        = TYPE_MAX_111X,
205     .class_init    = max1111_class_init,
206 };
207
208 static void max111x_register_types(void)
209 {
210     type_register_static(&max111x_info);
211     type_register_static(&max1110_info);
212     type_register_static(&max1111_info);
213 }
214
215 type_init(max111x_register_types)