xref: /openbmc/qemu/hw/i2c/smbus_slave.c (revision 3d54cbf2)
1 /*
2  * QEMU SMBus device emulation.
3  *
4  * This code is a helper for SMBus device emulation.  It implements an
5  * I2C device interface and runs the SMBus protocol from the device
6  * point of view and maps those to simple calls to emulate.
7  *
8  * Copyright (c) 2007 CodeSourcery.
9  * Written by Paul Brook
10  *
11  * This code is licensed under the LGPL.
12  */
13 
14 /* TODO: Implement PEC.  */
15 
16 #include "qemu/osdep.h"
17 #include "hw/i2c/i2c.h"
18 #include "hw/i2c/smbus_slave.h"
19 #include "migration/vmstate.h"
20 #include "qemu/module.h"
21 
22 //#define DEBUG_SMBUS 1
23 
24 #ifdef DEBUG_SMBUS
25 #define DPRINTF(fmt, ...) \
26 do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
27 #define BADF(fmt, ...) \
28 do { g_autofree char *qom_path = object_get_canonical_path(OBJECT(dev));  \
29     fprintf(stderr, "%s: smbus: error: " fmt , qom_path, ## __VA_ARGS__); \
30             exit(1); } while (0)
31 #else
32 #define DPRINTF(fmt, ...) do {} while(0)
33 #define BADF(fmt, ...) \
34 do { g_autofree char *qom_path = object_get_canonical_path(OBJECT(dev));  \
35     fprintf(stderr, "%s: smbus: error: " fmt , qom_path, ## __VA_ARGS__); \
36              } while (0)
37 #endif
38 
39 enum {
40     SMBUS_IDLE,
41     SMBUS_WRITE_DATA,
42     SMBUS_READ_DATA,
43     SMBUS_DONE,
44     SMBUS_CONFUSED = -1
45 };
46 
47 static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
48 {
49     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
50 
51     DPRINTF("Quick Command %d\n", recv);
52     if (sc->quick_cmd) {
53         sc->quick_cmd(dev, recv);
54     }
55 }
56 
57 static void smbus_do_write(SMBusDevice *dev)
58 {
59     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
60 
61     DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len);
62     if (sc->write_data) {
63         sc->write_data(dev, dev->data_buf, dev->data_len);
64     }
65 }
66 
67 static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
68 {
69     SMBusDevice *dev = SMBUS_DEVICE(s);
70 
71     switch (event) {
72     case I2C_START_SEND:
73         switch (dev->mode) {
74         case SMBUS_IDLE:
75             DPRINTF("Incoming data\n");
76             dev->mode = SMBUS_WRITE_DATA;
77             break;
78 
79         default:
80             BADF("Unexpected send start condition in state %d\n", dev->mode);
81             dev->mode = SMBUS_CONFUSED;
82             break;
83         }
84         break;
85 
86     case I2C_START_RECV:
87         switch (dev->mode) {
88         case SMBUS_IDLE:
89             DPRINTF("Read mode\n");
90             dev->mode = SMBUS_READ_DATA;
91             break;
92 
93         case SMBUS_WRITE_DATA:
94             if (dev->data_len == 0) {
95                 BADF("Read after write with no data\n");
96                 dev->mode = SMBUS_CONFUSED;
97             } else {
98                 smbus_do_write(dev);
99                 DPRINTF("Read mode\n");
100                 dev->mode = SMBUS_READ_DATA;
101             }
102             break;
103 
104         default:
105             BADF("Unexpected recv start condition in state %d\n", dev->mode);
106             dev->mode = SMBUS_CONFUSED;
107             break;
108         }
109         break;
110 
111     case I2C_FINISH:
112         if (dev->data_len == 0) {
113             if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) {
114                 smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA);
115             }
116         } else {
117             switch (dev->mode) {
118             case SMBUS_WRITE_DATA:
119                 smbus_do_write(dev);
120                 break;
121 
122             case SMBUS_READ_DATA:
123                 BADF("Unexpected stop during receive\n");
124                 break;
125 
126             default:
127                 /* Nothing to do.  */
128                 break;
129             }
130         }
131         dev->mode = SMBUS_IDLE;
132         dev->data_len = 0;
133         break;
134 
135     case I2C_NACK:
136         switch (dev->mode) {
137         case SMBUS_DONE:
138             /* Nothing to do.  */
139             break;
140 
141         case SMBUS_READ_DATA:
142             dev->mode = SMBUS_DONE;
143             break;
144 
145         default:
146             BADF("Unexpected NACK in state %d\n", dev->mode);
147             dev->mode = SMBUS_CONFUSED;
148             break;
149         }
150         break;
151 
152     default:
153         return -1;
154     }
155 
156     return 0;
157 }
158 
159 static uint8_t smbus_i2c_recv(I2CSlave *s)
160 {
161     SMBusDevice *dev = SMBUS_DEVICE(s);
162     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
163     uint8_t ret = 0xff;
164 
165     switch (dev->mode) {
166     case SMBUS_READ_DATA:
167         if (sc->receive_byte) {
168             ret = sc->receive_byte(dev);
169         }
170         DPRINTF("Read data %02x\n", ret);
171         break;
172 
173     default:
174         BADF("Unexpected read in state %d\n", dev->mode);
175         dev->mode = SMBUS_CONFUSED;
176         break;
177     }
178 
179     return ret;
180 }
181 
182 static int smbus_i2c_send(I2CSlave *s, uint8_t data)
183 {
184     SMBusDevice *dev = SMBUS_DEVICE(s);
185 
186     switch (dev->mode) {
187     case SMBUS_WRITE_DATA:
188         DPRINTF("Write data %02x\n", data);
189         if (dev->data_len >= sizeof(dev->data_buf)) {
190             BADF("Too many bytes sent\n");
191         } else {
192             dev->data_buf[dev->data_len++] = data;
193         }
194         break;
195 
196     default:
197         BADF("Unexpected write in state %d\n", dev->mode);
198         break;
199     }
200 
201     return 0;
202 }
203 
204 static void smbus_device_class_init(ObjectClass *klass, void *data)
205 {
206     I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
207 
208     sc->event = smbus_i2c_event;
209     sc->recv = smbus_i2c_recv;
210     sc->send = smbus_i2c_send;
211 }
212 
213 bool smbus_vmstate_needed(SMBusDevice *dev)
214 {
215     return dev->mode != SMBUS_IDLE;
216 }
217 
218 const VMStateDescription vmstate_smbus_device = {
219     .name = TYPE_SMBUS_DEVICE,
220     .version_id = 1,
221     .minimum_version_id = 1,
222     .fields = (const VMStateField[]) {
223         VMSTATE_I2C_SLAVE(i2c, SMBusDevice),
224         VMSTATE_INT32(mode, SMBusDevice),
225         VMSTATE_INT32(data_len, SMBusDevice),
226         VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN),
227         VMSTATE_END_OF_LIST()
228     }
229 };
230 
231 static const TypeInfo smbus_device_type_info = {
232     .name = TYPE_SMBUS_DEVICE,
233     .parent = TYPE_I2C_SLAVE,
234     .instance_size = sizeof(SMBusDevice),
235     .abstract = true,
236     .class_size = sizeof(SMBusDeviceClass),
237     .class_init = smbus_device_class_init,
238 };
239 
240 static void smbus_device_register_types(void)
241 {
242     type_register_static(&smbus_device_type_info);
243 }
244 
245 type_init(smbus_device_register_types)
246