qemu/hw/adc/max111x.c
<<
>>
Prefs
   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)
 237