|
1 /* |
|
2 * QEMU SMBus device emulation. |
|
3 * |
|
4 * Copyright (c) 2007 CodeSourcery. |
|
5 * Written by Paul Brook |
|
6 * |
|
7 * This code is licenced under the LGPL. |
|
8 */ |
|
9 |
|
10 /* TODO: Implement PEC. */ |
|
11 |
|
12 #include "hw.h" |
|
13 #include "i2c.h" |
|
14 #include "smbus.h" |
|
15 |
|
16 //#define DEBUG_SMBUS 1 |
|
17 |
|
18 #ifdef DEBUG_SMBUS |
|
19 #define DPRINTF(fmt, args...) \ |
|
20 do { printf("smbus(%02x): " fmt , dev->i2c.address, ##args); } while (0) |
|
21 #define BADF(fmt, args...) \ |
|
22 do { fprintf(stderr, "smbus: error: " fmt , ##args); exit(1);} while (0) |
|
23 #else |
|
24 #define DPRINTF(fmt, args...) do {} while(0) |
|
25 #define BADF(fmt, args...) \ |
|
26 do { fprintf(stderr, "smbus: error: " fmt , ##args);} while (0) |
|
27 #endif |
|
28 |
|
29 enum { |
|
30 SMBUS_IDLE, |
|
31 SMBUS_WRITE_DATA, |
|
32 SMBUS_RECV_BYTE, |
|
33 SMBUS_READ_DATA, |
|
34 SMBUS_DONE, |
|
35 SMBUS_CONFUSED = -1 |
|
36 }; |
|
37 |
|
38 static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) |
|
39 { |
|
40 DPRINTF("Quick Command %d\n", recv); |
|
41 if (dev->quick_cmd) |
|
42 dev->quick_cmd(dev, recv); |
|
43 } |
|
44 |
|
45 static void smbus_do_write(SMBusDevice *dev) |
|
46 { |
|
47 if (dev->data_len == 0) { |
|
48 smbus_do_quick_cmd(dev, 0); |
|
49 } else if (dev->data_len == 1) { |
|
50 DPRINTF("Send Byte\n"); |
|
51 if (dev->send_byte) { |
|
52 dev->send_byte(dev, dev->data_buf[0]); |
|
53 } |
|
54 } else { |
|
55 dev->command = dev->data_buf[0]; |
|
56 DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1); |
|
57 if (dev->write_data) { |
|
58 dev->write_data(dev, dev->command, dev->data_buf + 1, |
|
59 dev->data_len - 1); |
|
60 } |
|
61 } |
|
62 } |
|
63 |
|
64 static void smbus_i2c_event(i2c_slave *s, enum i2c_event event) |
|
65 { |
|
66 SMBusDevice *dev = (SMBusDevice *)s; |
|
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 default: |
|
75 BADF("Unexpected send start condition in state %d\n", dev->mode); |
|
76 dev->mode = SMBUS_CONFUSED; |
|
77 break; |
|
78 } |
|
79 break; |
|
80 |
|
81 case I2C_START_RECV: |
|
82 switch (dev->mode) { |
|
83 case SMBUS_IDLE: |
|
84 DPRINTF("Read mode\n"); |
|
85 dev->mode = SMBUS_RECV_BYTE; |
|
86 break; |
|
87 case SMBUS_WRITE_DATA: |
|
88 if (dev->data_len == 0) { |
|
89 BADF("Read after write with no data\n"); |
|
90 dev->mode = SMBUS_CONFUSED; |
|
91 } else { |
|
92 if (dev->data_len > 1) { |
|
93 smbus_do_write(dev); |
|
94 } else { |
|
95 dev->command = dev->data_buf[0]; |
|
96 DPRINTF("%02x: Command %d\n", dev->i2c.address, |
|
97 dev->command); |
|
98 } |
|
99 DPRINTF("Read mode\n"); |
|
100 dev->data_len = 0; |
|
101 dev->mode = SMBUS_READ_DATA; |
|
102 } |
|
103 break; |
|
104 default: |
|
105 BADF("Unexpected recv start condition in state %d\n", dev->mode); |
|
106 dev->mode = SMBUS_CONFUSED; |
|
107 break; |
|
108 } |
|
109 break; |
|
110 |
|
111 case I2C_FINISH: |
|
112 switch (dev->mode) { |
|
113 case SMBUS_WRITE_DATA: |
|
114 smbus_do_write(dev); |
|
115 break; |
|
116 case SMBUS_RECV_BYTE: |
|
117 smbus_do_quick_cmd(dev, 1); |
|
118 break; |
|
119 case SMBUS_READ_DATA: |
|
120 BADF("Unexpected stop during receive\n"); |
|
121 break; |
|
122 default: |
|
123 /* Nothing to do. */ |
|
124 break; |
|
125 } |
|
126 dev->mode = SMBUS_IDLE; |
|
127 dev->data_len = 0; |
|
128 break; |
|
129 |
|
130 case I2C_NACK: |
|
131 switch (dev->mode) { |
|
132 case SMBUS_DONE: |
|
133 /* Nothing to do. */ |
|
134 break; |
|
135 case SMBUS_READ_DATA: |
|
136 dev->mode = SMBUS_DONE; |
|
137 break; |
|
138 default: |
|
139 BADF("Unexpected NACK in state %d\n", dev->mode); |
|
140 dev->mode = SMBUS_CONFUSED; |
|
141 break; |
|
142 } |
|
143 } |
|
144 } |
|
145 |
|
146 static int smbus_i2c_recv(i2c_slave *s) |
|
147 { |
|
148 SMBusDevice *dev = (SMBusDevice *)s; |
|
149 int ret; |
|
150 |
|
151 switch (dev->mode) { |
|
152 case SMBUS_RECV_BYTE: |
|
153 if (dev->receive_byte) { |
|
154 ret = dev->receive_byte(dev); |
|
155 } else { |
|
156 ret = 0; |
|
157 } |
|
158 DPRINTF("Receive Byte %02x\n", ret); |
|
159 dev->mode = SMBUS_DONE; |
|
160 break; |
|
161 case SMBUS_READ_DATA: |
|
162 if (dev->read_data) { |
|
163 ret = dev->read_data(dev, dev->command, dev->data_len); |
|
164 dev->data_len++; |
|
165 } else { |
|
166 ret = 0; |
|
167 } |
|
168 DPRINTF("Read data %02x\n", ret); |
|
169 break; |
|
170 default: |
|
171 BADF("Unexpected read in state %d\n", dev->mode); |
|
172 dev->mode = SMBUS_CONFUSED; |
|
173 ret = 0; |
|
174 break; |
|
175 } |
|
176 return ret; |
|
177 } |
|
178 |
|
179 static int smbus_i2c_send(i2c_slave *s, uint8_t data) |
|
180 { |
|
181 SMBusDevice *dev = (SMBusDevice *)s; |
|
182 switch (dev->mode) { |
|
183 case SMBUS_WRITE_DATA: |
|
184 DPRINTF("Write data %02x\n", data); |
|
185 dev->data_buf[dev->data_len++] = data; |
|
186 break; |
|
187 default: |
|
188 BADF("Unexpected write in state %d\n", dev->mode); |
|
189 break; |
|
190 } |
|
191 return 0; |
|
192 } |
|
193 |
|
194 SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size) |
|
195 { |
|
196 SMBusDevice *dev; |
|
197 |
|
198 if (size < sizeof(SMBusDevice)) |
|
199 hw_error("SMBus struct too small"); |
|
200 |
|
201 dev = (SMBusDevice *)i2c_slave_init(bus, address, size); |
|
202 dev->i2c.event = smbus_i2c_event; |
|
203 dev->i2c.recv = smbus_i2c_recv; |
|
204 dev->i2c.send = smbus_i2c_send; |
|
205 |
|
206 return dev; |
|
207 } |
|
208 |
|
209 /* Master device commands. */ |
|
210 void smbus_quick_command(i2c_bus *bus, int addr, int read) |
|
211 { |
|
212 i2c_start_transfer(bus, addr, read); |
|
213 i2c_end_transfer(bus); |
|
214 } |
|
215 |
|
216 uint8_t smbus_receive_byte(i2c_bus *bus, int addr) |
|
217 { |
|
218 uint8_t data; |
|
219 |
|
220 i2c_start_transfer(bus, addr, 1); |
|
221 data = i2c_recv(bus); |
|
222 i2c_nack(bus); |
|
223 i2c_end_transfer(bus); |
|
224 return data; |
|
225 } |
|
226 |
|
227 void smbus_send_byte(i2c_bus *bus, int addr, uint8_t data) |
|
228 { |
|
229 i2c_start_transfer(bus, addr, 0); |
|
230 i2c_send(bus, data); |
|
231 i2c_end_transfer(bus); |
|
232 } |
|
233 |
|
234 uint8_t smbus_read_byte(i2c_bus *bus, int addr, uint8_t command) |
|
235 { |
|
236 uint8_t data; |
|
237 i2c_start_transfer(bus, addr, 0); |
|
238 i2c_send(bus, command); |
|
239 i2c_start_transfer(bus, addr, 1); |
|
240 data = i2c_recv(bus); |
|
241 i2c_nack(bus); |
|
242 i2c_end_transfer(bus); |
|
243 return data; |
|
244 } |
|
245 |
|
246 void smbus_write_byte(i2c_bus *bus, int addr, uint8_t command, uint8_t data) |
|
247 { |
|
248 i2c_start_transfer(bus, addr, 0); |
|
249 i2c_send(bus, command); |
|
250 i2c_send(bus, data); |
|
251 i2c_end_transfer(bus); |
|
252 } |
|
253 |
|
254 uint16_t smbus_read_word(i2c_bus *bus, int addr, uint8_t command) |
|
255 { |
|
256 uint16_t data; |
|
257 i2c_start_transfer(bus, addr, 0); |
|
258 i2c_send(bus, command); |
|
259 i2c_start_transfer(bus, addr, 1); |
|
260 data = i2c_recv(bus); |
|
261 data |= i2c_recv(bus) << 8; |
|
262 i2c_nack(bus); |
|
263 i2c_end_transfer(bus); |
|
264 return data; |
|
265 } |
|
266 |
|
267 void smbus_write_word(i2c_bus *bus, int addr, uint8_t command, uint16_t data) |
|
268 { |
|
269 i2c_start_transfer(bus, addr, 0); |
|
270 i2c_send(bus, command); |
|
271 i2c_send(bus, data & 0xff); |
|
272 i2c_send(bus, data >> 8); |
|
273 i2c_end_transfer(bus); |
|
274 } |
|
275 |
|
276 int smbus_read_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data) |
|
277 { |
|
278 int len; |
|
279 int i; |
|
280 |
|
281 i2c_start_transfer(bus, addr, 0); |
|
282 i2c_send(bus, command); |
|
283 i2c_start_transfer(bus, addr, 1); |
|
284 len = i2c_recv(bus); |
|
285 if (len > 32) |
|
286 len = 0; |
|
287 for (i = 0; i < len; i++) |
|
288 data[i] = i2c_recv(bus); |
|
289 i2c_nack(bus); |
|
290 i2c_end_transfer(bus); |
|
291 return len; |
|
292 } |
|
293 |
|
294 void smbus_write_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data, |
|
295 int len) |
|
296 { |
|
297 int i; |
|
298 |
|
299 if (len > 32) |
|
300 len = 32; |
|
301 |
|
302 i2c_start_transfer(bus, addr, 0); |
|
303 i2c_send(bus, command); |
|
304 i2c_send(bus, len); |
|
305 for (i = 0; i < len; i++) |
|
306 i2c_send(bus, data[i]); |
|
307 i2c_end_transfer(bus); |
|
308 } |