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