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