Merge remote-tracking branch 'remotes/rth/tags/pull-hppa-20190307' into staging
[qemu/ar7.git] / hw / i2c / smbus_slave.c
blob9a2d314d1a9596797becea61deae52ed59b6c296
1 /*
2 * QEMU SMBus device emulation.
4 * This code is a helper for SMBus device emulation. It implements an
5 * I2C device inteface and runs the SMBus protocol from the device
6 * point of view and maps those to simple calls to emulate.
8 * Copyright (c) 2007 CodeSourcery.
9 * Written by Paul Brook
11 * This code is licensed under the LGPL.
14 /* TODO: Implement PEC. */
16 #include "qemu/osdep.h"
17 #include "hw/hw.h"
18 #include "hw/i2c/i2c.h"
19 #include "hw/i2c/smbus_slave.h"
21 //#define DEBUG_SMBUS 1
23 #ifdef DEBUG_SMBUS
24 #define DPRINTF(fmt, ...) \
25 do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
26 #define BADF(fmt, ...) \
27 do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
28 #else
29 #define DPRINTF(fmt, ...) do {} while(0)
30 #define BADF(fmt, ...) \
31 do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
32 #endif
34 enum {
35 SMBUS_IDLE,
36 SMBUS_WRITE_DATA,
37 SMBUS_READ_DATA,
38 SMBUS_DONE,
39 SMBUS_CONFUSED = -1
42 static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
44 SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
46 DPRINTF("Quick Command %d\n", recv);
47 if (sc->quick_cmd) {
48 sc->quick_cmd(dev, recv);
52 static void smbus_do_write(SMBusDevice *dev)
54 SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
56 DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len);
57 if (sc->write_data) {
58 sc->write_data(dev, dev->data_buf, dev->data_len);
62 static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
64 SMBusDevice *dev = SMBUS_DEVICE(s);
66 switch (event) {
67 case I2C_START_SEND:
68 switch (dev->mode) {
69 case SMBUS_IDLE:
70 DPRINTF("Incoming data\n");
71 dev->mode = SMBUS_WRITE_DATA;
72 break;
74 default:
75 BADF("Unexpected send start condition in state %d\n", dev->mode);
76 dev->mode = SMBUS_CONFUSED;
77 break;
79 break;
81 case I2C_START_RECV:
82 switch (dev->mode) {
83 case SMBUS_IDLE:
84 DPRINTF("Read mode\n");
85 dev->mode = SMBUS_READ_DATA;
86 break;
88 case SMBUS_WRITE_DATA:
89 if (dev->data_len == 0) {
90 BADF("Read after write with no data\n");
91 dev->mode = SMBUS_CONFUSED;
92 } else {
93 smbus_do_write(dev);
94 DPRINTF("Read mode\n");
95 dev->mode = SMBUS_READ_DATA;
97 break;
99 default:
100 BADF("Unexpected recv start condition in state %d\n", dev->mode);
101 dev->mode = SMBUS_CONFUSED;
102 break;
104 break;
106 case I2C_FINISH:
107 if (dev->data_len == 0) {
108 if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) {
109 smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA);
111 } else {
112 switch (dev->mode) {
113 case SMBUS_WRITE_DATA:
114 smbus_do_write(dev);
115 break;
117 case SMBUS_READ_DATA:
118 BADF("Unexpected stop during receive\n");
119 break;
121 default:
122 /* Nothing to do. */
123 break;
126 dev->mode = SMBUS_IDLE;
127 dev->data_len = 0;
128 break;
130 case I2C_NACK:
131 switch (dev->mode) {
132 case SMBUS_DONE:
133 /* Nothing to do. */
134 break;
136 case SMBUS_READ_DATA:
137 dev->mode = SMBUS_DONE;
138 break;
140 default:
141 BADF("Unexpected NACK in state %d\n", dev->mode);
142 dev->mode = SMBUS_CONFUSED;
143 break;
147 return 0;
150 static uint8_t smbus_i2c_recv(I2CSlave *s)
152 SMBusDevice *dev = SMBUS_DEVICE(s);
153 SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
154 uint8_t ret = 0xff;
156 switch (dev->mode) {
157 case SMBUS_READ_DATA:
158 if (sc->receive_byte) {
159 ret = sc->receive_byte(dev);
161 DPRINTF("Read data %02x\n", ret);
162 break;
164 default:
165 BADF("Unexpected read in state %d\n", dev->mode);
166 dev->mode = SMBUS_CONFUSED;
167 break;
170 return ret;
173 static int smbus_i2c_send(I2CSlave *s, uint8_t data)
175 SMBusDevice *dev = SMBUS_DEVICE(s);
177 switch (dev->mode) {
178 case SMBUS_WRITE_DATA:
179 DPRINTF("Write data %02x\n", data);
180 if (dev->data_len >= sizeof(dev->data_buf)) {
181 BADF("Too many bytes sent\n");
182 } else {
183 dev->data_buf[dev->data_len++] = data;
185 break;
187 default:
188 BADF("Unexpected write in state %d\n", dev->mode);
189 break;
192 return 0;
195 static void smbus_device_class_init(ObjectClass *klass, void *data)
197 I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
199 sc->event = smbus_i2c_event;
200 sc->recv = smbus_i2c_recv;
201 sc->send = smbus_i2c_send;
204 bool smbus_vmstate_needed(SMBusDevice *dev)
206 return dev->mode != SMBUS_IDLE;
209 const VMStateDescription vmstate_smbus_device = {
210 .name = TYPE_SMBUS_DEVICE,
211 .version_id = 1,
212 .minimum_version_id = 1,
213 .fields = (VMStateField[]) {
214 VMSTATE_I2C_SLAVE(i2c, SMBusDevice),
215 VMSTATE_INT32(mode, SMBusDevice),
216 VMSTATE_INT32(data_len, SMBusDevice),
217 VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN),
218 VMSTATE_END_OF_LIST()
222 static const TypeInfo smbus_device_type_info = {
223 .name = TYPE_SMBUS_DEVICE,
224 .parent = TYPE_I2C_SLAVE,
225 .instance_size = sizeof(SMBusDevice),
226 .abstract = true,
227 .class_size = sizeof(SMBusDeviceClass),
228 .class_init = smbus_device_class_init,
231 static void smbus_device_register_types(void)
233 type_register_static(&smbus_device_type_info);
236 type_init(smbus_device_register_types)