Statistics
| Branch: | Revision:

root / hw / smbus.c @ b30bb3a2

History | View | Annotate | Download (7.4 kB)

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