blob: ff027c814f7d0b690dc2f0c7c26f2d74d8548227 [file] [log] [blame]
ths5fafdf22007-09-16 21:08:06 +00001/*
pbrook0ff596d2007-05-23 00:03:59 +00002 * QEMU SMBus device emulation.
3 *
4 * Copyright (c) 2007 CodeSourcery.
5 * Written by Paul Brook
6 *
Matthew Fernandez8e31bf32011-06-26 12:21:35 +10007 * This code is licensed under the LGPL.
pbrook0ff596d2007-05-23 00:03:59 +00008 */
9
10/* TODO: Implement PEC. */
11
pbrook87ecb682007-11-17 17:14:51 +000012#include "hw.h"
13#include "i2c.h"
14#include "smbus.h"
pbrook0ff596d2007-05-23 00:03:59 +000015
16//#define DEBUG_SMBUS 1
17
18#ifdef DEBUG_SMBUS
Blue Swirl001faf32009-05-13 17:53:17 +000019#define DPRINTF(fmt, ...) \
20do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
21#define BADF(fmt, ...) \
22do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
pbrook0ff596d2007-05-23 00:03:59 +000023#else
Blue Swirl001faf32009-05-13 17:53:17 +000024#define DPRINTF(fmt, ...) do {} while(0)
25#define BADF(fmt, ...) \
26do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
pbrook0ff596d2007-05-23 00:03:59 +000027#endif
28
29enum {
30 SMBUS_IDLE,
31 SMBUS_WRITE_DATA,
32 SMBUS_RECV_BYTE,
33 SMBUS_READ_DATA,
34 SMBUS_DONE,
35 SMBUS_CONFUSED = -1
36};
37
38static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
39{
Paul Brook1ea96672009-05-14 22:35:08 +010040 SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
41
pbrook0ff596d2007-05-23 00:03:59 +000042 DPRINTF("Quick Command %d\n", recv);
Paul Brook1ea96672009-05-14 22:35:08 +010043 if (t->quick_cmd)
44 t->quick_cmd(dev, recv);
pbrook0ff596d2007-05-23 00:03:59 +000045}
46
47static void smbus_do_write(SMBusDevice *dev)
48{
Paul Brook1ea96672009-05-14 22:35:08 +010049 SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
50
pbrook0ff596d2007-05-23 00:03:59 +000051 if (dev->data_len == 0) {
52 smbus_do_quick_cmd(dev, 0);
53 } else if (dev->data_len == 1) {
54 DPRINTF("Send Byte\n");
Paul Brook1ea96672009-05-14 22:35:08 +010055 if (t->send_byte) {
56 t->send_byte(dev, dev->data_buf[0]);
pbrook0ff596d2007-05-23 00:03:59 +000057 }
58 } else {
59 dev->command = dev->data_buf[0];
60 DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
Paul Brook1ea96672009-05-14 22:35:08 +010061 if (t->write_data) {
62 t->write_data(dev, dev->command, dev->data_buf + 1,
63 dev->data_len - 1);
pbrook0ff596d2007-05-23 00:03:59 +000064 }
65 }
66}
67
pbrook9596ebb2007-11-18 01:44:38 +000068static void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
pbrook0ff596d2007-05-23 00:03:59 +000069{
Paul Brook1ea96672009-05-14 22:35:08 +010070 SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
71
pbrook0ff596d2007-05-23 00:03:59 +000072 switch (event) {
73 case I2C_START_SEND:
74 switch (dev->mode) {
75 case SMBUS_IDLE:
76 DPRINTF("Incoming data\n");
77 dev->mode = SMBUS_WRITE_DATA;
78 break;
79 default:
80 BADF("Unexpected send start condition in state %d\n", dev->mode);
81 dev->mode = SMBUS_CONFUSED;
82 break;
83 }
84 break;
85
86 case I2C_START_RECV:
87 switch (dev->mode) {
88 case SMBUS_IDLE:
89 DPRINTF("Read mode\n");
90 dev->mode = SMBUS_RECV_BYTE;
91 break;
92 case SMBUS_WRITE_DATA:
93 if (dev->data_len == 0) {
94 BADF("Read after write with no data\n");
95 dev->mode = SMBUS_CONFUSED;
96 } else {
97 if (dev->data_len > 1) {
98 smbus_do_write(dev);
99 } else {
100 dev->command = dev->data_buf[0];
101 DPRINTF("%02x: Command %d\n", dev->i2c.address,
102 dev->command);
103 }
104 DPRINTF("Read mode\n");
105 dev->data_len = 0;
106 dev->mode = SMBUS_READ_DATA;
107 }
108 break;
109 default:
110 BADF("Unexpected recv start condition in state %d\n", dev->mode);
111 dev->mode = SMBUS_CONFUSED;
112 break;
113 }
114 break;
115
116 case I2C_FINISH:
117 switch (dev->mode) {
118 case SMBUS_WRITE_DATA:
119 smbus_do_write(dev);
120 break;
121 case SMBUS_RECV_BYTE:
122 smbus_do_quick_cmd(dev, 1);
123 break;
124 case SMBUS_READ_DATA:
125 BADF("Unexpected stop during receive\n");
126 break;
127 default:
128 /* Nothing to do. */
129 break;
130 }
131 dev->mode = SMBUS_IDLE;
132 dev->data_len = 0;
133 break;
134
135 case I2C_NACK:
136 switch (dev->mode) {
137 case SMBUS_DONE:
138 /* Nothing to do. */
139 break;
140 case SMBUS_READ_DATA:
141 dev->mode = SMBUS_DONE;
142 break;
143 default:
144 BADF("Unexpected NACK in state %d\n", dev->mode);
145 dev->mode = SMBUS_CONFUSED;
146 break;
147 }
148 }
149}
150
151static int smbus_i2c_recv(i2c_slave *s)
152{
Paul Brook1ea96672009-05-14 22:35:08 +0100153 SMBusDeviceInfo *t = container_of(s->info, SMBusDeviceInfo, i2c);
154 SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
pbrook0ff596d2007-05-23 00:03:59 +0000155 int ret;
156
157 switch (dev->mode) {
158 case SMBUS_RECV_BYTE:
Paul Brook1ea96672009-05-14 22:35:08 +0100159 if (t->receive_byte) {
160 ret = t->receive_byte(dev);
pbrook0ff596d2007-05-23 00:03:59 +0000161 } else {
162 ret = 0;
163 }
164 DPRINTF("Receive Byte %02x\n", ret);
165 dev->mode = SMBUS_DONE;
166 break;
167 case SMBUS_READ_DATA:
Paul Brook1ea96672009-05-14 22:35:08 +0100168 if (t->read_data) {
169 ret = t->read_data(dev, dev->command, dev->data_len);
pbrook0ff596d2007-05-23 00:03:59 +0000170 dev->data_len++;
171 } else {
172 ret = 0;
173 }
174 DPRINTF("Read data %02x\n", ret);
175 break;
176 default:
177 BADF("Unexpected read in state %d\n", dev->mode);
178 dev->mode = SMBUS_CONFUSED;
179 ret = 0;
180 break;
181 }
182 return ret;
183}
184
185static int smbus_i2c_send(i2c_slave *s, uint8_t data)
186{
Paul Brook1ea96672009-05-14 22:35:08 +0100187 SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
188
pbrook0ff596d2007-05-23 00:03:59 +0000189 switch (dev->mode) {
190 case SMBUS_WRITE_DATA:
191 DPRINTF("Write data %02x\n", data);
192 dev->data_buf[dev->data_len++] = data;
193 break;
194 default:
195 BADF("Unexpected write in state %d\n", dev->mode);
196 break;
197 }
198 return 0;
199}
200
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200201static int smbus_device_init(i2c_slave *i2c)
pbrook0ff596d2007-05-23 00:03:59 +0000202{
Paul Brook1ea96672009-05-14 22:35:08 +0100203 SMBusDeviceInfo *t = container_of(i2c->info, SMBusDeviceInfo, i2c);
204 SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, i2c);
pbrook0ff596d2007-05-23 00:03:59 +0000205
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200206 return t->init(dev);
Paul Brook1ea96672009-05-14 22:35:08 +0100207}
balrog3f582262007-05-23 21:47:51 +0000208
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +0200209void smbus_register_device(SMBusDeviceInfo *info)
Paul Brook1ea96672009-05-14 22:35:08 +0100210{
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +0200211 assert(info->i2c.qdev.size >= sizeof(SMBusDevice));
Paul Brook1ea96672009-05-14 22:35:08 +0100212 info->i2c.init = smbus_device_init;
213 info->i2c.event = smbus_i2c_event;
214 info->i2c.recv = smbus_i2c_recv;
215 info->i2c.send = smbus_i2c_send;
Gerd Hoffmann074f2ff2009-06-10 09:41:42 +0200216 i2c_register_slave(&info->i2c);
pbrook0ff596d2007-05-23 00:03:59 +0000217}
218
219/* Master device commands. */
Juan Quintela5b7f5322009-09-29 22:48:26 +0200220void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read)
pbrook0ff596d2007-05-23 00:03:59 +0000221{
222 i2c_start_transfer(bus, addr, read);
223 i2c_end_transfer(bus);
224}
225
Juan Quintela5b7f5322009-09-29 22:48:26 +0200226uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr)
pbrook0ff596d2007-05-23 00:03:59 +0000227{
228 uint8_t data;
229
230 i2c_start_transfer(bus, addr, 1);
231 data = i2c_recv(bus);
232 i2c_nack(bus);
233 i2c_end_transfer(bus);
234 return data;
235}
236
Juan Quintela5b7f5322009-09-29 22:48:26 +0200237void smbus_send_byte(i2c_bus *bus, uint8_t addr, uint8_t data)
pbrook0ff596d2007-05-23 00:03:59 +0000238{
239 i2c_start_transfer(bus, addr, 0);
240 i2c_send(bus, data);
241 i2c_end_transfer(bus);
242}
243
Juan Quintela5b7f5322009-09-29 22:48:26 +0200244uint8_t smbus_read_byte(i2c_bus *bus, uint8_t addr, uint8_t command)
pbrook0ff596d2007-05-23 00:03:59 +0000245{
246 uint8_t data;
247 i2c_start_transfer(bus, addr, 0);
248 i2c_send(bus, command);
249 i2c_start_transfer(bus, addr, 1);
250 data = i2c_recv(bus);
251 i2c_nack(bus);
252 i2c_end_transfer(bus);
253 return data;
254}
255
Juan Quintela5b7f5322009-09-29 22:48:26 +0200256void smbus_write_byte(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t data)
pbrook0ff596d2007-05-23 00:03:59 +0000257{
258 i2c_start_transfer(bus, addr, 0);
259 i2c_send(bus, command);
260 i2c_send(bus, data);
261 i2c_end_transfer(bus);
262}
263
Juan Quintela5b7f5322009-09-29 22:48:26 +0200264uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command)
pbrook0ff596d2007-05-23 00:03:59 +0000265{
266 uint16_t data;
267 i2c_start_transfer(bus, addr, 0);
268 i2c_send(bus, command);
269 i2c_start_transfer(bus, addr, 1);
270 data = i2c_recv(bus);
271 data |= i2c_recv(bus) << 8;
272 i2c_nack(bus);
273 i2c_end_transfer(bus);
274 return data;
275}
276
Juan Quintela5b7f5322009-09-29 22:48:26 +0200277void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data)
pbrook0ff596d2007-05-23 00:03:59 +0000278{
279 i2c_start_transfer(bus, addr, 0);
280 i2c_send(bus, command);
281 i2c_send(bus, data & 0xff);
282 i2c_send(bus, data >> 8);
283 i2c_end_transfer(bus);
284}
285
Juan Quintela5b7f5322009-09-29 22:48:26 +0200286int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data)
pbrook0ff596d2007-05-23 00:03:59 +0000287{
288 int len;
289 int i;
290
291 i2c_start_transfer(bus, addr, 0);
292 i2c_send(bus, command);
293 i2c_start_transfer(bus, addr, 1);
294 len = i2c_recv(bus);
295 if (len > 32)
296 len = 0;
297 for (i = 0; i < len; i++)
298 data[i] = i2c_recv(bus);
299 i2c_nack(bus);
300 i2c_end_transfer(bus);
301 return len;
302}
303
Juan Quintela5b7f5322009-09-29 22:48:26 +0200304void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
pbrook0ff596d2007-05-23 00:03:59 +0000305 int len)
306{
307 int i;
308
309 if (len > 32)
310 len = 32;
311
312 i2c_start_transfer(bus, addr, 0);
313 i2c_send(bus, command);
314 i2c_send(bus, len);
315 for (i = 0; i < len; i++)
316 i2c_send(bus, data[i]);
317 i2c_end_transfer(bus);
318}