max111x.c (6243B)
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 35static 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 */ 51static 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 88static 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 95static const VMStateDescription vmstate_max111x = { 96 .name = "max111x", 97 .version_id = 1, 98 .minimum_version_id = 1, 99 .fields = (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 112static 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 120static 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 133static void max1110_realize(SSIPeripheral *dev, Error **errp) 134{ 135 max111x_init(dev, 8); 136} 137 138static void max1111_realize(SSIPeripheral *dev, Error **errp) 139{ 140 max111x_init(dev, 4); 141} 142 143static 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 158static 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 167static 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 180static 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 191static 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 199static 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 208static const TypeInfo max1110_info = { 209 .name = TYPE_MAX_1110, 210 .parent = TYPE_MAX_111X, 211 .class_init = max1110_class_init, 212}; 213 214static 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 223static const TypeInfo max1111_info = { 224 .name = TYPE_MAX_1111, 225 .parent = TYPE_MAX_111X, 226 .class_init = max1111_class_init, 227}; 228 229static 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 236type_init(max111x_register_types)