]> git.proxmox.com Git - qemu.git/blame - hw/i2c.c
qdev: Move SysBus initialization to sysbus.c
[qemu.git] / hw / i2c.c
CommitLineData
5fafdf24 1/*
0ff596d0
PB
2 * QEMU I2C bus interface.
3 *
4 * Copyright (c) 2007 CodeSourcery.
5 * Written by Paul Brook
6 *
8e31bf38 7 * This code is licensed under the LGPL.
0ff596d0
PB
8 */
9
87ecb68b 10#include "i2c.h"
0ff596d0
PB
11
12struct i2c_bus
13{
02e2da45 14 BusState qbus;
9e07bdf8
AL
15 I2CSlave *current_dev;
16 I2CSlave *dev;
5b7f5327 17 uint8_t saved_address;
0ff596d0
PB
18};
19
3cb75a7c
PB
20static Property i2c_props[] = {
21 DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
22 DEFINE_PROP_END_OF_LIST(),
23};
24
10c4c98a
GH
25static struct BusInfo i2c_bus_info = {
26 .name = "I2C",
27 .size = sizeof(i2c_bus),
28};
29
8d0eb050 30static void i2c_bus_pre_save(void *opaque)
c701b35b 31{
8d0eb050 32 i2c_bus *bus = opaque;
c701b35b 33
8d0eb050 34 bus->saved_address = bus->current_dev ? bus->current_dev->address : -1;
c701b35b
PB
35}
36
8d0eb050 37static int i2c_bus_post_load(void *opaque, int version_id)
c701b35b 38{
8d0eb050 39 i2c_bus *bus = opaque;
c701b35b
PB
40
41 /* The bus is loaded before attached devices, so load and save the
42 current device id. Devices will check themselves as loaded. */
c701b35b 43 bus->current_dev = NULL;
c701b35b
PB
44 return 0;
45}
46
8d0eb050
JQ
47static const VMStateDescription vmstate_i2c_bus = {
48 .name = "i2c_bus",
49 .version_id = 1,
50 .minimum_version_id = 1,
51 .minimum_version_id_old = 1,
52 .pre_save = i2c_bus_pre_save,
53 .post_load = i2c_bus_post_load,
54 .fields = (VMStateField []) {
55 VMSTATE_UINT8(saved_address, i2c_bus),
56 VMSTATE_END_OF_LIST()
57 }
58};
59
0ff596d0 60/* Create a new I2C bus. */
02e2da45 61i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
0ff596d0
PB
62{
63 i2c_bus *bus;
64
10c4c98a 65 bus = FROM_QBUS(i2c_bus, qbus_create(&i2c_bus_info, parent, name));
0be71e32 66 vmstate_register(NULL, -1, &vmstate_i2c_bus, bus);
0ff596d0
PB
67 return bus;
68}
69
9e07bdf8 70void i2c_set_slave_address(I2CSlave *dev, uint8_t address)
0ff596d0
PB
71{
72 dev->address = address;
73}
74
75/* Return nonzero if bus is busy. */
76int i2c_bus_busy(i2c_bus *bus)
77{
78 return bus->current_dev != NULL;
79}
80
4a2c8ac2 81/* Returns non-zero if the address is not valid. */
0ff596d0 82/* TODO: Make this handle multiple masters. */
5b7f5327 83int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
0ff596d0 84{
02e2da45 85 DeviceState *qdev;
9e07bdf8 86 I2CSlave *slave = NULL;
b5ea9327 87 I2CSlaveClass *sc;
0ff596d0 88
d8bb00d6 89 QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
9e07bdf8 90 I2CSlave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
b3a21988
JR
91 if (candidate->address == address) {
92 slave = candidate;
0ff596d0 93 break;
b3a21988 94 }
0ff596d0
PB
95 }
96
b5ea9327 97 if (!slave) {
0ff596d0 98 return 1;
b5ea9327 99 }
0ff596d0 100
b5ea9327 101 sc = I2C_SLAVE_GET_CLASS(slave);
0ff596d0
PB
102 /* If the bus is already busy, assume this is a repeated
103 start condition. */
02e2da45 104 bus->current_dev = slave;
b5ea9327
AL
105 if (sc->event) {
106 sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
107 }
0ff596d0
PB
108 return 0;
109}
110
111void i2c_end_transfer(i2c_bus *bus)
112{
9e07bdf8 113 I2CSlave *dev = bus->current_dev;
b5ea9327 114 I2CSlaveClass *sc;
0ff596d0 115
b5ea9327 116 if (!dev) {
0ff596d0 117 return;
b5ea9327 118 }
0ff596d0 119
b5ea9327
AL
120 sc = I2C_SLAVE_GET_CLASS(dev);
121 if (sc->event) {
122 sc->event(dev, I2C_FINISH);
123 }
0ff596d0
PB
124
125 bus->current_dev = NULL;
126}
127
128int i2c_send(i2c_bus *bus, uint8_t data)
129{
9e07bdf8 130 I2CSlave *dev = bus->current_dev;
b5ea9327 131 I2CSlaveClass *sc;
0ff596d0 132
b5ea9327 133 if (!dev) {
0ff596d0 134 return -1;
b5ea9327 135 }
0ff596d0 136
b5ea9327
AL
137 sc = I2C_SLAVE_GET_CLASS(dev);
138 if (sc->send) {
139 return sc->send(dev, data);
140 }
141
142 return -1;
0ff596d0
PB
143}
144
145int i2c_recv(i2c_bus *bus)
146{
9e07bdf8 147 I2CSlave *dev = bus->current_dev;
b5ea9327 148 I2CSlaveClass *sc;
0ff596d0 149
b5ea9327 150 if (!dev) {
0ff596d0 151 return -1;
b5ea9327
AL
152 }
153
154 sc = I2C_SLAVE_GET_CLASS(dev);
155 if (sc->recv) {
156 return sc->recv(dev);
157 }
0ff596d0 158
b5ea9327 159 return -1;
0ff596d0
PB
160}
161
162void i2c_nack(i2c_bus *bus)
163{
9e07bdf8 164 I2CSlave *dev = bus->current_dev;
b5ea9327 165 I2CSlaveClass *sc;
0ff596d0 166
b5ea9327 167 if (!dev) {
0ff596d0 168 return;
b5ea9327 169 }
0ff596d0 170
b5ea9327
AL
171 sc = I2C_SLAVE_GET_CLASS(dev);
172 if (sc->event) {
173 sc->event(dev, I2C_NACK);
174 }
0ff596d0
PB
175}
176
bcbe8068 177static int i2c_slave_post_load(void *opaque, int version_id)
aa941b94 178{
9e07bdf8 179 I2CSlave *dev = opaque;
fe8de492 180 i2c_bus *bus;
02e2da45 181 bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev));
fe8de492
PB
182 if (bus->saved_address == dev->address) {
183 bus->current_dev = dev;
184 }
bcbe8068
JQ
185 return 0;
186}
187
1894839f 188const VMStateDescription vmstate_i2c_slave = {
9e07bdf8 189 .name = "I2CSlave",
bcbe8068
JQ
190 .version_id = 1,
191 .minimum_version_id = 1,
192 .minimum_version_id_old = 1,
193 .post_load = i2c_slave_post_load,
194 .fields = (VMStateField []) {
9e07bdf8 195 VMSTATE_UINT8(address, I2CSlave),
bcbe8068
JQ
196 VMSTATE_END_OF_LIST()
197 }
198};
199
d307af79 200static int i2c_slave_qdev_init(DeviceState *dev)
fe8de492 201{
9e07bdf8 202 I2CSlave *s = I2C_SLAVE_FROM_QDEV(dev);
b5ea9327 203 I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
fe8de492 204
b5ea9327
AL
205 return sc->init(s);
206}
fe8de492 207
5b7f5327 208DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
fe8de492
PB
209{
210 DeviceState *dev;
211
02e2da45 212 dev = qdev_create(&bus->qbus, name);
5b7f5327 213 qdev_prop_set_uint8(dev, "address", addr);
e23a1b33 214 qdev_init_nofail(dev);
fe8de492 215 return dev;
aa941b94 216}
b5ea9327 217
39bffca2
AL
218static void i2c_slave_class_init(ObjectClass *klass, void *data)
219{
220 DeviceClass *k = DEVICE_CLASS(klass);
221 k->init = i2c_slave_qdev_init;
222 k->bus_info = &i2c_bus_info;
bce54474 223 k->props = i2c_props;
39bffca2
AL
224}
225
b5ea9327
AL
226static TypeInfo i2c_slave_type_info = {
227 .name = TYPE_I2C_SLAVE,
228 .parent = TYPE_DEVICE,
229 .instance_size = sizeof(I2CSlave),
230 .abstract = true,
231 .class_size = sizeof(I2CSlaveClass),
39bffca2 232 .class_init = i2c_slave_class_init,
b5ea9327
AL
233};
234
83f7d43a 235static void i2c_slave_register_types(void)
b5ea9327
AL
236{
237 type_register_static(&i2c_slave_type_info);
238}
239
83f7d43a 240type_init(i2c_slave_register_types)