]> git.proxmox.com Git - qemu.git/blame - hw/i2c.c
i2c: addresses are load/save as uint8_t values, change types to reflect this
[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 *
7 * This code is licenced under the LGPL.
8 */
9
87ecb68b 10#include "i2c.h"
0ff596d0
PB
11
12struct i2c_bus
13{
02e2da45 14 BusState qbus;
0ff596d0
PB
15 i2c_slave *current_dev;
16 i2c_slave *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[]) {
5b7f5327 24 DEFINE_PROP_UINT8("address", struct i2c_slave, address, 0),
368eb5d4 25 DEFINE_PROP_END_OF_LIST(),
ee6847d1 26 }
10c4c98a
GH
27};
28
c701b35b
PB
29static void i2c_bus_save(QEMUFile *f, void *opaque)
30{
31 i2c_bus *bus = (i2c_bus *)opaque;
5b7f5327 32 bus->saved_address = bus->current_dev ? bus->current_dev->address : -1;
c701b35b 33
5b7f5327 34 qemu_put_8s(f, &bus->saved_address);
c701b35b
PB
35}
36
37static int i2c_bus_load(QEMUFile *f, void *opaque, int version_id)
38{
39 i2c_bus *bus = (i2c_bus *)opaque;
40
41 if (version_id != 1)
42 return -EINVAL;
43
44 /* The bus is loaded before attached devices, so load and save the
45 current device id. Devices will check themselves as loaded. */
5b7f5327 46 qemu_get_8s(f, &bus->saved_address);
c701b35b
PB
47 bus->current_dev = NULL;
48
49 return 0;
50}
51
0ff596d0 52/* Create a new I2C bus. */
02e2da45 53i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
0ff596d0
PB
54{
55 i2c_bus *bus;
56
10c4c98a 57 bus = FROM_QBUS(i2c_bus, qbus_create(&i2c_bus_info, parent, name));
c701b35b 58 register_savevm("i2c_bus", -1, 1, i2c_bus_save, i2c_bus_load, bus);
0ff596d0
PB
59 return bus;
60}
61
5b7f5327 62void i2c_set_slave_address(i2c_slave *dev, uint8_t address)
0ff596d0
PB
63{
64 dev->address = address;
65}
66
67/* Return nonzero if bus is busy. */
68int i2c_bus_busy(i2c_bus *bus)
69{
70 return bus->current_dev != NULL;
71}
72
4a2c8ac2 73/* Returns non-zero if the address is not valid. */
0ff596d0 74/* TODO: Make this handle multiple masters. */
5b7f5327 75int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
0ff596d0 76{
02e2da45
PB
77 DeviceState *qdev;
78 i2c_slave *slave = NULL;
0ff596d0 79
72cf2d4f 80 QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
02e2da45
PB
81 slave = I2C_SLAVE_FROM_QDEV(qdev);
82 if (slave->address == address)
0ff596d0
PB
83 break;
84 }
85
02e2da45 86 if (!slave)
0ff596d0
PB
87 return 1;
88
89 /* If the bus is already busy, assume this is a repeated
90 start condition. */
02e2da45
PB
91 bus->current_dev = slave;
92 slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
0ff596d0
PB
93 return 0;
94}
95
96void i2c_end_transfer(i2c_bus *bus)
97{
98 i2c_slave *dev = bus->current_dev;
99
100 if (!dev)
101 return;
102
fe8de492 103 dev->info->event(dev, I2C_FINISH);
0ff596d0
PB
104
105 bus->current_dev = NULL;
106}
107
108int i2c_send(i2c_bus *bus, uint8_t data)
109{
110 i2c_slave *dev = bus->current_dev;
111
112 if (!dev)
113 return -1;
114
fe8de492 115 return dev->info->send(dev, data);
0ff596d0
PB
116}
117
118int i2c_recv(i2c_bus *bus)
119{
120 i2c_slave *dev = bus->current_dev;
121
122 if (!dev)
123 return -1;
124
fe8de492 125 return dev->info->recv(dev);
0ff596d0
PB
126}
127
128void i2c_nack(i2c_bus *bus)
129{
130 i2c_slave *dev = bus->current_dev;
131
132 if (!dev)
133 return;
134
fe8de492 135 dev->info->event(dev, I2C_NACK);
0ff596d0
PB
136}
137
aa941b94
AZ
138void i2c_slave_save(QEMUFile *f, i2c_slave *dev)
139{
5b7f5327 140 qemu_put_8s(f, &dev->address);
aa941b94
AZ
141}
142
143void i2c_slave_load(QEMUFile *f, i2c_slave *dev)
144{
fe8de492 145 i2c_bus *bus;
02e2da45 146 bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev));
5b7f5327 147 qemu_get_8s(f, &dev->address);
fe8de492
PB
148 if (bus->saved_address == dev->address) {
149 bus->current_dev = dev;
150 }
151}
152
81a322d4 153static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
fe8de492 154{
02e2da45 155 I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev);
fe8de492
PB
156 i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev);
157
158 s->info = info;
fe8de492 159
81a322d4 160 return info->init(s);
fe8de492
PB
161}
162
074f2fff 163void i2c_register_slave(I2CSlaveInfo *info)
fe8de492 164{
074f2fff 165 assert(info->qdev.size >= sizeof(i2c_slave));
02e2da45 166 info->qdev.init = i2c_slave_qdev_init;
10c4c98a 167 info->qdev.bus_info = &i2c_bus_info;
074f2fff 168 qdev_register(&info->qdev);
fe8de492
PB
169}
170
5b7f5327 171DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
fe8de492
PB
172{
173 DeviceState *dev;
174
02e2da45 175 dev = qdev_create(&bus->qbus, name);
5b7f5327 176 qdev_prop_set_uint8(dev, "address", addr);
fe8de492
PB
177 qdev_init(dev);
178 return dev;
aa941b94 179}