]> git.proxmox.com Git - qemu.git/blame - hw/smbus.c
Merge remote-tracking branch 'kraxel/usb.31' into staging
[qemu.git] / hw / smbus.c
CommitLineData
5fafdf24 1/*
0ff596d0
PB
2 * QEMU SMBus device emulation.
3 *
4 * Copyright (c) 2007 CodeSourcery.
5 * Written by Paul Brook
6 *
8e31bf38 7 * This code is licensed under the LGPL.
0ff596d0
PB
8 */
9
10/* TODO: Implement PEC. */
11
87ecb68b
PB
12#include "hw.h"
13#include "i2c.h"
14#include "smbus.h"
0ff596d0
PB
15
16//#define DEBUG_SMBUS 1
17
18#ifdef DEBUG_SMBUS
001faf32
BS
19#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)
0ff596d0 23#else
001faf32
BS
24#define DPRINTF(fmt, ...) do {} while(0)
25#define BADF(fmt, ...) \
26do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
0ff596d0
PB
27#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{
1ea96673
PB
40 SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
41
0ff596d0 42 DPRINTF("Quick Command %d\n", recv);
1ea96673
PB
43 if (t->quick_cmd)
44 t->quick_cmd(dev, recv);
0ff596d0
PB
45}
46
47static void smbus_do_write(SMBusDevice *dev)
48{
1ea96673
PB
49 SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
50
0ff596d0
PB
51 if (dev->data_len == 0) {
52 smbus_do_quick_cmd(dev, 0);
53 } else if (dev->data_len == 1) {
54 DPRINTF("Send Byte\n");
1ea96673
PB
55 if (t->send_byte) {
56 t->send_byte(dev, dev->data_buf[0]);
0ff596d0
PB
57 }
58 } else {
59 dev->command = dev->data_buf[0];
60 DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
1ea96673
PB
61 if (t->write_data) {
62 t->write_data(dev, dev->command, dev->data_buf + 1,
63 dev->data_len - 1);
0ff596d0
PB
64 }
65 }
66}
67
9596ebb7 68static void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
0ff596d0 69{
1ea96673
PB
70 SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
71
0ff596d0
PB
72 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{
1ea96673
PB
153 SMBusDeviceInfo *t = container_of(s->info, SMBusDeviceInfo, i2c);
154 SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
0ff596d0
PB
155 int ret;
156
157 switch (dev->mode) {
158 case SMBUS_RECV_BYTE:
1ea96673
PB
159 if (t->receive_byte) {
160 ret = t->receive_byte(dev);
0ff596d0
PB
161 } else {
162 ret = 0;
163 }
164 DPRINTF("Receive Byte %02x\n", ret);
165 dev->mode = SMBUS_DONE;
166 break;
167 case SMBUS_READ_DATA:
1ea96673
PB
168 if (t->read_data) {
169 ret = t->read_data(dev, dev->command, dev->data_len);
0ff596d0
PB
170 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{
1ea96673
PB
187 SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
188
0ff596d0
PB
189 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
81a322d4 201static int smbus_device_init(i2c_slave *i2c)
0ff596d0 202{
1ea96673
PB
203 SMBusDeviceInfo *t = container_of(i2c->info, SMBusDeviceInfo, i2c);
204 SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, i2c);
0ff596d0 205
81a322d4 206 return t->init(dev);
1ea96673 207}
0ff596d0 208
074f2fff 209void smbus_register_device(SMBusDeviceInfo *info)
1ea96673 210{
074f2fff 211 assert(info->i2c.qdev.size >= sizeof(SMBusDevice));
1ea96673
PB
212 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;
074f2fff 216 i2c_register_slave(&info->i2c);
0ff596d0
PB
217}
218
219/* Master device commands. */
5b7f5327 220void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read)
0ff596d0
PB
221{
222 i2c_start_transfer(bus, addr, read);
223 i2c_end_transfer(bus);
224}
225
5b7f5327 226uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr)
0ff596d0
PB
227{
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
5b7f5327 237void smbus_send_byte(i2c_bus *bus, uint8_t addr, uint8_t data)
0ff596d0
PB
238{
239 i2c_start_transfer(bus, addr, 0);
240 i2c_send(bus, data);
241 i2c_end_transfer(bus);
242}
243
5b7f5327 244uint8_t smbus_read_byte(i2c_bus *bus, uint8_t addr, uint8_t command)
0ff596d0
PB
245{
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
5b7f5327 256void smbus_write_byte(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t data)
0ff596d0
PB
257{
258 i2c_start_transfer(bus, addr, 0);
259 i2c_send(bus, command);
260 i2c_send(bus, data);
261 i2c_end_transfer(bus);
262}
263
5b7f5327 264uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command)
0ff596d0
PB
265{
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
5b7f5327 277void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data)
0ff596d0
PB
278{
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
5b7f5327 286int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data)
0ff596d0
PB
287{
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
5b7f5327 304void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
0ff596d0
PB
305 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}