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