xref: /openbmc/qemu/hw/i2c/smbus_slave.c (revision 031ac49886684ae6d6b88f37779cad2ffd1e4d9b)
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         default:
74             BADF("Unexpected send start condition in state %d\n", dev->mode);
75             dev->mode = SMBUS_CONFUSED;
76             break;
77         }
78         break;
79 
80     case I2C_START_RECV:
81         switch (dev->mode) {
82         case SMBUS_IDLE:
83             DPRINTF("Read mode\n");
84             dev->mode = SMBUS_READ_DATA;
85             break;
86         case SMBUS_WRITE_DATA:
87             if (dev->data_len == 0) {
88                 BADF("Read after write with no data\n");
89                 dev->mode = SMBUS_CONFUSED;
90             } else {
91                 smbus_do_write(dev);
92                 DPRINTF("Read mode\n");
93                 dev->mode = SMBUS_READ_DATA;
94             }
95             break;
96         default:
97             BADF("Unexpected recv start condition in state %d\n", dev->mode);
98             dev->mode = SMBUS_CONFUSED;
99             break;
100         }
101         break;
102 
103     case I2C_FINISH:
104         if (dev->data_len == 0) {
105             if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) {
106                 smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA);
107             }
108         } else {
109             switch (dev->mode) {
110             case SMBUS_WRITE_DATA:
111                 smbus_do_write(dev);
112                 break;
113 
114             case SMBUS_READ_DATA:
115                 BADF("Unexpected stop during receive\n");
116                 break;
117 
118             default:
119                 /* Nothing to do.  */
120                 break;
121             }
122         }
123         dev->mode = SMBUS_IDLE;
124         dev->data_len = 0;
125         break;
126 
127     case I2C_NACK:
128         switch (dev->mode) {
129         case SMBUS_DONE:
130             /* Nothing to do.  */
131             break;
132         case SMBUS_READ_DATA:
133             dev->mode = SMBUS_DONE;
134             break;
135         default:
136             BADF("Unexpected NACK in state %d\n", dev->mode);
137             dev->mode = SMBUS_CONFUSED;
138             break;
139         }
140     }
141 
142     return 0;
143 }
144 
145 static uint8_t smbus_i2c_recv(I2CSlave *s)
146 {
147     SMBusDevice *dev = SMBUS_DEVICE(s);
148     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
149     uint8_t ret = 0xff;
150 
151     switch (dev->mode) {
152     case SMBUS_READ_DATA:
153         if (sc->receive_byte) {
154             ret = sc->receive_byte(dev);
155         }
156         DPRINTF("Read data %02x\n", ret);
157         break;
158     default:
159         BADF("Unexpected read in state %d\n", dev->mode);
160         dev->mode = SMBUS_CONFUSED;
161         break;
162     }
163     return ret;
164 }
165 
166 static int smbus_i2c_send(I2CSlave *s, uint8_t data)
167 {
168     SMBusDevice *dev = SMBUS_DEVICE(s);
169 
170     switch (dev->mode) {
171     case SMBUS_WRITE_DATA:
172         DPRINTF("Write data %02x\n", data);
173         if (dev->data_len >= sizeof(dev->data_buf)) {
174             BADF("Too many bytes sent\n");
175         } else {
176             dev->data_buf[dev->data_len++] = data;
177         }
178         break;
179     default:
180         BADF("Unexpected write in state %d\n", dev->mode);
181         break;
182     }
183     return 0;
184 }
185 
186 static void smbus_device_class_init(ObjectClass *klass, void *data)
187 {
188     I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
189 
190     sc->event = smbus_i2c_event;
191     sc->recv = smbus_i2c_recv;
192     sc->send = smbus_i2c_send;
193 }
194 
195 static const TypeInfo smbus_device_type_info = {
196     .name = TYPE_SMBUS_DEVICE,
197     .parent = TYPE_I2C_SLAVE,
198     .instance_size = sizeof(SMBusDevice),
199     .abstract = true,
200     .class_size = sizeof(SMBusDeviceClass),
201     .class_init = smbus_device_class_init,
202 };
203 
204 static void smbus_device_register_types(void)
205 {
206     type_register_static(&smbus_device_type_info);
207 }
208 
209 type_init(smbus_device_register_types)
210