10
#include "hw/i2c/i2c.h"
11
#include "hw/gpio/pcf8574.h"
13
#include "migration/vmstate.h"
15
#include "qemu/module.h"
16
#include "qom/object.h"
37
OBJECT_DECLARE_SIMPLE_TYPE(PCF8574State, PCF8574)
39
#define PORTS_COUNT (8)
46
qemu_irq handler[PORTS_COUNT];
50
static void pcf8574_reset(DeviceState *dev)
52
PCF8574State *s = PCF8574(dev);
53
s->lastrq = MAKE_64BIT_MASK(0, PORTS_COUNT);
54
s->input = MAKE_64BIT_MASK(0, PORTS_COUNT);
55
s->output = MAKE_64BIT_MASK(0, PORTS_COUNT);
58
static inline uint8_t pcf8574_line_state(PCF8574State *s)
61
return s->input & s->output;
64
static uint8_t pcf8574_rx(I2CSlave *i2c)
66
PCF8574State *s = PCF8574(i2c);
67
uint8_t linestate = pcf8574_line_state(s);
68
if (s->lastrq != linestate) {
69
s->lastrq = linestate;
71
qemu_set_irq(s->intrq, 1);
77
static int pcf8574_tx(I2CSlave *i2c, uint8_t data)
79
PCF8574State *s = PCF8574(i2c);
85
prev = pcf8574_line_state(s);
87
actual = pcf8574_line_state(s);
89
for (diff = (actual ^ prev); diff; diff &= ~(1 << line)) {
91
if (s->handler[line]) {
92
qemu_set_irq(s->handler[line], (actual >> line) & 1);
97
qemu_set_irq(s->intrq, actual == s->lastrq);
103
static const VMStateDescription vmstate_pcf8574 = {
106
.minimum_version_id = 0,
107
.fields = (VMStateField[]) {
108
VMSTATE_I2C_SLAVE(parent_obj, PCF8574State),
109
VMSTATE_UINT8(lastrq, PCF8574State),
110
VMSTATE_UINT8(input, PCF8574State),
111
VMSTATE_UINT8(output, PCF8574State),
112
VMSTATE_END_OF_LIST()
116
static void pcf8574_gpio_set(void *opaque, int line, int level)
118
PCF8574State *s = (PCF8574State *) opaque;
119
assert(line >= 0 && line < ARRAY_SIZE(s->handler));
122
s->input |= (1 << line);
124
s->input &= ~(1 << line);
127
if (pcf8574_line_state(s) != s->lastrq && s->intrq) {
128
qemu_set_irq(s->intrq, 0);
132
static void pcf8574_realize(DeviceState *dev, Error **errp)
134
PCF8574State *s = PCF8574(dev);
136
qdev_init_gpio_in(dev, pcf8574_gpio_set, ARRAY_SIZE(s->handler));
137
qdev_init_gpio_out(dev, s->handler, ARRAY_SIZE(s->handler));
138
qdev_init_gpio_out_named(dev, &s->intrq, "nINT", 1);
141
static void pcf8574_class_init(ObjectClass *klass, void *data)
143
DeviceClass *dc = DEVICE_CLASS(klass);
144
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
146
k->recv = pcf8574_rx;
147
k->send = pcf8574_tx;
148
dc->realize = pcf8574_realize;
149
dc->reset = pcf8574_reset;
150
dc->vmsd = &vmstate_pcf8574;
153
static const TypeInfo pcf8574_infos[] = {
155
.name = TYPE_PCF8574,
156
.parent = TYPE_I2C_SLAVE,
157
.instance_size = sizeof(PCF8574State),
158
.class_init = pcf8574_class_init,
162
DEFINE_TYPES(pcf8574_infos);