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