Statistics
| Branch: | Revision:

root / hw / smbus.c @ c9159fe9

History | View | Annotate | Download (8.1 kB)

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