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