xref: /openbmc/qemu/hw/i2c/smbus_slave.c (revision b097ba37)
1 /*
2  * QEMU SMBus device emulation.
3  *
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.
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/hw.h"
18 #include "hw/i2c/i2c.h"
19 #include "hw/i2c/smbus_slave.h"
20 
21 //#define DEBUG_SMBUS 1
22 
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
33 
34 enum {
35     SMBUS_IDLE,
36     SMBUS_WRITE_DATA,
37     SMBUS_READ_DATA,
38     SMBUS_DONE,
39     SMBUS_CONFUSED = -1
40 };
41 
42 static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
43 {
44     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
45 
46     DPRINTF("Quick Command %d\n", recv);
47     if (sc->quick_cmd) {
48         sc->quick_cmd(dev, recv);
49     }
50 }
51 
52 static void smbus_do_write(SMBusDevice *dev)
53 {
54     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
55 
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);
59     }
60 }
61 
62 static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
63 {
64     SMBusDevice *dev = SMBUS_DEVICE(s);
65 
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;
73 
74         default:
75             BADF("Unexpected send start condition in state %d\n", dev->mode);
76             dev->mode = SMBUS_CONFUSED;
77             break;
78         }
79         break;
80 
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;
87 
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;
96             }
97             break;
98 
99         default:
100             BADF("Unexpected recv start condition in state %d\n", dev->mode);
101             dev->mode = SMBUS_CONFUSED;
102             break;
103         }
104         break;
105 
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);
110             }
111         } else {
112             switch (dev->mode) {
113             case SMBUS_WRITE_DATA:
114                 smbus_do_write(dev);
115                 break;
116 
117             case SMBUS_READ_DATA:
118                 BADF("Unexpected stop during receive\n");
119                 break;
120 
121             default:
122                 /* Nothing to do.  */
123                 break;
124             }
125         }
126         dev->mode = SMBUS_IDLE;
127         dev->data_len = 0;
128         break;
129 
130     case I2C_NACK:
131         switch (dev->mode) {
132         case SMBUS_DONE:
133             /* Nothing to do.  */
134             break;
135 
136         case SMBUS_READ_DATA:
137             dev->mode = SMBUS_DONE;
138             break;
139 
140         default:
141             BADF("Unexpected NACK in state %d\n", dev->mode);
142             dev->mode = SMBUS_CONFUSED;
143             break;
144         }
145     }
146 
147     return 0;
148 }
149 
150 static uint8_t smbus_i2c_recv(I2CSlave *s)
151 {
152     SMBusDevice *dev = SMBUS_DEVICE(s);
153     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
154     uint8_t ret = 0xff;
155 
156     switch (dev->mode) {
157     case SMBUS_READ_DATA:
158         if (sc->receive_byte) {
159             ret = sc->receive_byte(dev);
160         }
161         DPRINTF("Read data %02x\n", ret);
162         break;
163 
164     default:
165         BADF("Unexpected read in state %d\n", dev->mode);
166         dev->mode = SMBUS_CONFUSED;
167         break;
168     }
169 
170     return ret;
171 }
172 
173 static int smbus_i2c_send(I2CSlave *s, uint8_t data)
174 {
175     SMBusDevice *dev = SMBUS_DEVICE(s);
176 
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;
184         }
185         break;
186 
187     default:
188         BADF("Unexpected write in state %d\n", dev->mode);
189         break;
190     }
191 
192     return 0;
193 }
194 
195 static void smbus_device_class_init(ObjectClass *klass, void *data)
196 {
197     I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
198 
199     sc->event = smbus_i2c_event;
200     sc->recv = smbus_i2c_recv;
201     sc->send = smbus_i2c_send;
202 }
203 
204 bool smbus_vmstate_needed(SMBusDevice *dev)
205 {
206     return dev->mode != SMBUS_IDLE;
207 }
208 
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()
219     }
220 };
221 
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,
229 };
230 
231 static void smbus_device_register_types(void)
232 {
233     type_register_static(&smbus_device_type_info);
234 }
235 
236 type_init(smbus_device_register_types)
237