158f3e3feSCorey Minyard /* 258f3e3feSCorey Minyard * Maxim MAX1110/1111 ADC chip emulation. 358f3e3feSCorey Minyard * 458f3e3feSCorey Minyard * Copyright (c) 2006 Openedhand Ltd. 558f3e3feSCorey Minyard * Written by Andrzej Zaborowski <balrog@zabor.org> 658f3e3feSCorey Minyard * 758f3e3feSCorey Minyard * This code is licensed under the GNU GPLv2. 858f3e3feSCorey Minyard * 958f3e3feSCorey Minyard * Contributions after 2012-01-13 are licensed under the terms of the 1058f3e3feSCorey Minyard * GNU GPL, version 2 or (at your option) any later version. 1158f3e3feSCorey Minyard */ 1258f3e3feSCorey Minyard 1358f3e3feSCorey Minyard #include "qemu/osdep.h" 1458f3e3feSCorey Minyard #include "hw/adc/max111x.h" 1558f3e3feSCorey Minyard #include "hw/irq.h" 1658f3e3feSCorey Minyard #include "migration/vmstate.h" 1758f3e3feSCorey Minyard #include "qemu/module.h" 1858f3e3feSCorey Minyard #include "hw/qdev-properties.h" 1958f3e3feSCorey Minyard 2058f3e3feSCorey Minyard /* Control-byte bitfields */ 2158f3e3feSCorey Minyard #define CB_PD0 (1 << 0) 2258f3e3feSCorey Minyard #define CB_PD1 (1 << 1) 2358f3e3feSCorey Minyard #define CB_SGL (1 << 2) 2458f3e3feSCorey Minyard #define CB_UNI (1 << 3) 2558f3e3feSCorey Minyard #define CB_SEL0 (1 << 4) 2658f3e3feSCorey Minyard #define CB_SEL1 (1 << 5) 2758f3e3feSCorey Minyard #define CB_SEL2 (1 << 6) 2858f3e3feSCorey Minyard #define CB_START (1 << 7) 2958f3e3feSCorey Minyard 3058f3e3feSCorey Minyard #define CHANNEL_NUM(v, b0, b1, b2) \ 3158f3e3feSCorey Minyard ((((v) >> (2 + (b0))) & 4) | \ 3258f3e3feSCorey Minyard (((v) >> (3 + (b1))) & 2) | \ 3358f3e3feSCorey Minyard (((v) >> (4 + (b2))) & 1)) 3458f3e3feSCorey Minyard 3558f3e3feSCorey Minyard static uint32_t max111x_read(MAX111xState *s) 3658f3e3feSCorey Minyard { 3758f3e3feSCorey Minyard if (!s->tb1) 3858f3e3feSCorey Minyard return 0; 3958f3e3feSCorey Minyard 4058f3e3feSCorey Minyard switch (s->cycle ++) { 4158f3e3feSCorey Minyard case 1: 4258f3e3feSCorey Minyard return s->rb2; 4358f3e3feSCorey Minyard case 2: 4458f3e3feSCorey Minyard return s->rb3; 4558f3e3feSCorey Minyard } 4658f3e3feSCorey Minyard 4758f3e3feSCorey Minyard return 0; 4858f3e3feSCorey Minyard } 4958f3e3feSCorey Minyard 5058f3e3feSCorey Minyard /* Interpret a control-byte */ 5158f3e3feSCorey Minyard static void max111x_write(MAX111xState *s, uint32_t value) 5258f3e3feSCorey Minyard { 5358f3e3feSCorey Minyard int measure, chan; 5458f3e3feSCorey Minyard 5558f3e3feSCorey Minyard /* Ignore the value if START bit is zero */ 5658f3e3feSCorey Minyard if (!(value & CB_START)) 5758f3e3feSCorey Minyard return; 5858f3e3feSCorey Minyard 5958f3e3feSCorey Minyard s->cycle = 0; 6058f3e3feSCorey Minyard 6158f3e3feSCorey Minyard if (!(value & CB_PD1)) { 6258f3e3feSCorey Minyard s->tb1 = 0; 6358f3e3feSCorey Minyard return; 6458f3e3feSCorey Minyard } 6558f3e3feSCorey Minyard 6658f3e3feSCorey Minyard s->tb1 = value; 6758f3e3feSCorey Minyard 6858f3e3feSCorey Minyard if (s->inputs == 8) 6958f3e3feSCorey Minyard chan = CHANNEL_NUM(value, 1, 0, 2); 7058f3e3feSCorey Minyard else 7158f3e3feSCorey Minyard chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2); 7258f3e3feSCorey Minyard 7358f3e3feSCorey Minyard if (value & CB_SGL) 7458f3e3feSCorey Minyard measure = s->input[chan] - s->com; 7558f3e3feSCorey Minyard else 7658f3e3feSCorey Minyard measure = s->input[chan] - s->input[chan ^ 1]; 7758f3e3feSCorey Minyard 7858f3e3feSCorey Minyard if (!(value & CB_UNI)) 7958f3e3feSCorey Minyard measure ^= 0x80; 8058f3e3feSCorey Minyard 8158f3e3feSCorey Minyard s->rb2 = (measure >> 2) & 0x3f; 8258f3e3feSCorey Minyard s->rb3 = (measure << 6) & 0xc0; 8358f3e3feSCorey Minyard 8458f3e3feSCorey Minyard /* FIXME: When should the IRQ be lowered? */ 8558f3e3feSCorey Minyard qemu_irq_raise(s->interrupt); 8658f3e3feSCorey Minyard } 8758f3e3feSCorey Minyard 8858f3e3feSCorey Minyard static uint32_t max111x_transfer(SSIPeripheral *dev, uint32_t value) 8958f3e3feSCorey Minyard { 9058f3e3feSCorey Minyard MAX111xState *s = MAX_111X(dev); 9158f3e3feSCorey Minyard max111x_write(s, value); 9258f3e3feSCorey Minyard return max111x_read(s); 9358f3e3feSCorey Minyard } 9458f3e3feSCorey Minyard 9558f3e3feSCorey Minyard static const VMStateDescription vmstate_max111x = { 9658f3e3feSCorey Minyard .name = "max111x", 9758f3e3feSCorey Minyard .version_id = 1, 9858f3e3feSCorey Minyard .minimum_version_id = 1, 99*99367627SRichard Henderson .fields = (const VMStateField[]) { 10058f3e3feSCorey Minyard VMSTATE_SSI_PERIPHERAL(parent_obj, MAX111xState), 10158f3e3feSCorey Minyard VMSTATE_UINT8(tb1, MAX111xState), 10258f3e3feSCorey Minyard VMSTATE_UINT8(rb2, MAX111xState), 10358f3e3feSCorey Minyard VMSTATE_UINT8(rb3, MAX111xState), 10458f3e3feSCorey Minyard VMSTATE_INT32_EQUAL(inputs, MAX111xState, NULL), 10558f3e3feSCorey Minyard VMSTATE_INT32(com, MAX111xState), 10658f3e3feSCorey Minyard VMSTATE_ARRAY_INT32_UNSAFE(input, MAX111xState, inputs, 10758f3e3feSCorey Minyard vmstate_info_uint8, uint8_t), 10858f3e3feSCorey Minyard VMSTATE_END_OF_LIST() 10958f3e3feSCorey Minyard } 11058f3e3feSCorey Minyard }; 11158f3e3feSCorey Minyard 11258f3e3feSCorey Minyard static void max111x_input_set(void *opaque, int line, int value) 11358f3e3feSCorey Minyard { 11458f3e3feSCorey Minyard MAX111xState *s = MAX_111X(opaque); 11558f3e3feSCorey Minyard 11658f3e3feSCorey Minyard assert(line >= 0 && line < s->inputs); 11758f3e3feSCorey Minyard s->input[line] = value; 11858f3e3feSCorey Minyard } 11958f3e3feSCorey Minyard 12058f3e3feSCorey Minyard static int max111x_init(SSIPeripheral *d, int inputs) 12158f3e3feSCorey Minyard { 12258f3e3feSCorey Minyard DeviceState *dev = DEVICE(d); 12358f3e3feSCorey Minyard MAX111xState *s = MAX_111X(dev); 12458f3e3feSCorey Minyard 12558f3e3feSCorey Minyard qdev_init_gpio_out(dev, &s->interrupt, 1); 12658f3e3feSCorey Minyard qdev_init_gpio_in(dev, max111x_input_set, inputs); 12758f3e3feSCorey Minyard 12858f3e3feSCorey Minyard s->inputs = inputs; 12958f3e3feSCorey Minyard 13058f3e3feSCorey Minyard return 0; 13158f3e3feSCorey Minyard } 13258f3e3feSCorey Minyard 13358f3e3feSCorey Minyard static void max1110_realize(SSIPeripheral *dev, Error **errp) 13458f3e3feSCorey Minyard { 13558f3e3feSCorey Minyard max111x_init(dev, 8); 13658f3e3feSCorey Minyard } 13758f3e3feSCorey Minyard 13858f3e3feSCorey Minyard static void max1111_realize(SSIPeripheral *dev, Error **errp) 13958f3e3feSCorey Minyard { 14058f3e3feSCorey Minyard max111x_init(dev, 4); 14158f3e3feSCorey Minyard } 14258f3e3feSCorey Minyard 14358f3e3feSCorey Minyard static void max111x_reset(DeviceState *dev) 14458f3e3feSCorey Minyard { 14558f3e3feSCorey Minyard MAX111xState *s = MAX_111X(dev); 14658f3e3feSCorey Minyard int i; 14758f3e3feSCorey Minyard 14858f3e3feSCorey Minyard for (i = 0; i < s->inputs; i++) { 14958f3e3feSCorey Minyard s->input[i] = s->reset_input[i]; 15058f3e3feSCorey Minyard } 15158f3e3feSCorey Minyard s->com = 0; 15258f3e3feSCorey Minyard s->tb1 = 0; 15358f3e3feSCorey Minyard s->rb2 = 0; 15458f3e3feSCorey Minyard s->rb3 = 0; 15558f3e3feSCorey Minyard s->cycle = 0; 15658f3e3feSCorey Minyard } 15758f3e3feSCorey Minyard 15858f3e3feSCorey Minyard static Property max1110_properties[] = { 15958f3e3feSCorey Minyard /* Reset values for ADC inputs */ 16058f3e3feSCorey Minyard DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0), 16158f3e3feSCorey Minyard DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0), 16258f3e3feSCorey Minyard DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0), 16358f3e3feSCorey Minyard DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0), 16458f3e3feSCorey Minyard DEFINE_PROP_END_OF_LIST(), 16558f3e3feSCorey Minyard }; 16658f3e3feSCorey Minyard 16758f3e3feSCorey Minyard static Property max1111_properties[] = { 16858f3e3feSCorey Minyard /* Reset values for ADC inputs */ 16958f3e3feSCorey Minyard DEFINE_PROP_UINT8("input0", MAX111xState, reset_input[0], 0xf0), 17058f3e3feSCorey Minyard DEFINE_PROP_UINT8("input1", MAX111xState, reset_input[1], 0xe0), 17158f3e3feSCorey Minyard DEFINE_PROP_UINT8("input2", MAX111xState, reset_input[2], 0xd0), 17258f3e3feSCorey Minyard DEFINE_PROP_UINT8("input3", MAX111xState, reset_input[3], 0xc0), 17358f3e3feSCorey Minyard DEFINE_PROP_UINT8("input4", MAX111xState, reset_input[4], 0xb0), 17458f3e3feSCorey Minyard DEFINE_PROP_UINT8("input5", MAX111xState, reset_input[5], 0xa0), 17558f3e3feSCorey Minyard DEFINE_PROP_UINT8("input6", MAX111xState, reset_input[6], 0x90), 17658f3e3feSCorey Minyard DEFINE_PROP_UINT8("input7", MAX111xState, reset_input[7], 0x80), 17758f3e3feSCorey Minyard DEFINE_PROP_END_OF_LIST(), 17858f3e3feSCorey Minyard }; 17958f3e3feSCorey Minyard 18058f3e3feSCorey Minyard static void max111x_class_init(ObjectClass *klass, void *data) 18158f3e3feSCorey Minyard { 18258f3e3feSCorey Minyard SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); 18358f3e3feSCorey Minyard DeviceClass *dc = DEVICE_CLASS(klass); 18458f3e3feSCorey Minyard 18558f3e3feSCorey Minyard k->transfer = max111x_transfer; 18658f3e3feSCorey Minyard dc->reset = max111x_reset; 18758f3e3feSCorey Minyard dc->vmsd = &vmstate_max111x; 18858f3e3feSCorey Minyard set_bit(DEVICE_CATEGORY_MISC, dc->categories); 18958f3e3feSCorey Minyard } 19058f3e3feSCorey Minyard 19158f3e3feSCorey Minyard static const TypeInfo max111x_info = { 19258f3e3feSCorey Minyard .name = TYPE_MAX_111X, 19358f3e3feSCorey Minyard .parent = TYPE_SSI_PERIPHERAL, 19458f3e3feSCorey Minyard .instance_size = sizeof(MAX111xState), 19558f3e3feSCorey Minyard .class_init = max111x_class_init, 19658f3e3feSCorey Minyard .abstract = true, 19758f3e3feSCorey Minyard }; 19858f3e3feSCorey Minyard 19958f3e3feSCorey Minyard static void max1110_class_init(ObjectClass *klass, void *data) 20058f3e3feSCorey Minyard { 20158f3e3feSCorey Minyard SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); 20258f3e3feSCorey Minyard DeviceClass *dc = DEVICE_CLASS(klass); 20358f3e3feSCorey Minyard 20458f3e3feSCorey Minyard k->realize = max1110_realize; 20558f3e3feSCorey Minyard device_class_set_props(dc, max1110_properties); 20658f3e3feSCorey Minyard } 20758f3e3feSCorey Minyard 20858f3e3feSCorey Minyard static const TypeInfo max1110_info = { 20958f3e3feSCorey Minyard .name = TYPE_MAX_1110, 21058f3e3feSCorey Minyard .parent = TYPE_MAX_111X, 21158f3e3feSCorey Minyard .class_init = max1110_class_init, 21258f3e3feSCorey Minyard }; 21358f3e3feSCorey Minyard 21458f3e3feSCorey Minyard static void max1111_class_init(ObjectClass *klass, void *data) 21558f3e3feSCorey Minyard { 21658f3e3feSCorey Minyard SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); 21758f3e3feSCorey Minyard DeviceClass *dc = DEVICE_CLASS(klass); 21858f3e3feSCorey Minyard 21958f3e3feSCorey Minyard k->realize = max1111_realize; 22058f3e3feSCorey Minyard device_class_set_props(dc, max1111_properties); 22158f3e3feSCorey Minyard } 22258f3e3feSCorey Minyard 22358f3e3feSCorey Minyard static const TypeInfo max1111_info = { 22458f3e3feSCorey Minyard .name = TYPE_MAX_1111, 22558f3e3feSCorey Minyard .parent = TYPE_MAX_111X, 22658f3e3feSCorey Minyard .class_init = max1111_class_init, 22758f3e3feSCorey Minyard }; 22858f3e3feSCorey Minyard 22958f3e3feSCorey Minyard static void max111x_register_types(void) 23058f3e3feSCorey Minyard { 23158f3e3feSCorey Minyard type_register_static(&max111x_info); 23258f3e3feSCorey Minyard type_register_static(&max1110_info); 23358f3e3feSCorey Minyard type_register_static(&max1111_info); 23458f3e3feSCorey Minyard } 23558f3e3feSCorey Minyard 23658f3e3feSCorey Minyard type_init(max111x_register_types) 237