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