xref: /openbmc/qemu/hw/i2c/smbus_slave.c (revision a27bd6c7)
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/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     }
147 
148     return 0;
149 }
150 
151 static uint8_t smbus_i2c_recv(I2CSlave *s)
152 {
153     SMBusDevice *dev = SMBUS_DEVICE(s);
154     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
155     uint8_t ret = 0xff;
156 
157     switch (dev->mode) {
158     case SMBUS_READ_DATA:
159         if (sc->receive_byte) {
160             ret = sc->receive_byte(dev);
161         }
162         DPRINTF("Read data %02x\n", ret);
163         break;
164 
165     default:
166         BADF("Unexpected read in state %d\n", dev->mode);
167         dev->mode = SMBUS_CONFUSED;
168         break;
169     }
170 
171     return ret;
172 }
173 
174 static int smbus_i2c_send(I2CSlave *s, uint8_t data)
175 {
176     SMBusDevice *dev = SMBUS_DEVICE(s);
177 
178     switch (dev->mode) {
179     case SMBUS_WRITE_DATA:
180         DPRINTF("Write data %02x\n", data);
181         if (dev->data_len >= sizeof(dev->data_buf)) {
182             BADF("Too many bytes sent\n");
183         } else {
184             dev->data_buf[dev->data_len++] = data;
185         }
186         break;
187 
188     default:
189         BADF("Unexpected write in state %d\n", dev->mode);
190         break;
191     }
192 
193     return 0;
194 }
195 
196 static void smbus_device_class_init(ObjectClass *klass, void *data)
197 {
198     I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
199 
200     sc->event = smbus_i2c_event;
201     sc->recv = smbus_i2c_recv;
202     sc->send = smbus_i2c_send;
203 }
204 
205 bool smbus_vmstate_needed(SMBusDevice *dev)
206 {
207     return dev->mode != SMBUS_IDLE;
208 }
209 
210 const VMStateDescription vmstate_smbus_device = {
211     .name = TYPE_SMBUS_DEVICE,
212     .version_id = 1,
213     .minimum_version_id = 1,
214     .fields      = (VMStateField[]) {
215         VMSTATE_I2C_SLAVE(i2c, SMBusDevice),
216         VMSTATE_INT32(mode, SMBusDevice),
217         VMSTATE_INT32(data_len, SMBusDevice),
218         VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN),
219         VMSTATE_END_OF_LIST()
220     }
221 };
222 
223 static const TypeInfo smbus_device_type_info = {
224     .name = TYPE_SMBUS_DEVICE,
225     .parent = TYPE_I2C_SLAVE,
226     .instance_size = sizeof(SMBusDevice),
227     .abstract = true,
228     .class_size = sizeof(SMBusDeviceClass),
229     .class_init = smbus_device_class_init,
230 };
231 
232 static void smbus_device_register_types(void)
233 {
234     type_register_static(&smbus_device_type_info);
235 }
236 
237 type_init(smbus_device_register_types)
238