Statistics
| Branch: | Revision:

root / hw / smbus.c @ 8c78881f

History | View | Annotate | Download (7.9 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 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 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 1ea96673 Paul Brook
    SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
41 1ea96673 Paul Brook
42 0ff596d0 pbrook
    DPRINTF("Quick Command %d\n", recv);
43 1ea96673 Paul Brook
    if (t->quick_cmd)
44 1ea96673 Paul Brook
        t->quick_cmd(dev, recv);
45 0ff596d0 pbrook
}
46 0ff596d0 pbrook
47 0ff596d0 pbrook
static void smbus_do_write(SMBusDevice *dev)
48 0ff596d0 pbrook
{
49 1ea96673 Paul Brook
    SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
50 1ea96673 Paul Brook
51 0ff596d0 pbrook
    if (dev->data_len == 0) {
52 0ff596d0 pbrook
        smbus_do_quick_cmd(dev, 0);
53 0ff596d0 pbrook
    } else if (dev->data_len == 1) {
54 0ff596d0 pbrook
        DPRINTF("Send Byte\n");
55 1ea96673 Paul Brook
        if (t->send_byte) {
56 1ea96673 Paul Brook
            t->send_byte(dev, dev->data_buf[0]);
57 0ff596d0 pbrook
        }
58 0ff596d0 pbrook
    } else {
59 0ff596d0 pbrook
        dev->command = dev->data_buf[0];
60 0ff596d0 pbrook
        DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
61 1ea96673 Paul Brook
        if (t->write_data) {
62 1ea96673 Paul Brook
            t->write_data(dev, dev->command, dev->data_buf + 1,
63 1ea96673 Paul Brook
                          dev->data_len - 1);
64 0ff596d0 pbrook
        }
65 0ff596d0 pbrook
    }
66 0ff596d0 pbrook
}
67 0ff596d0 pbrook
68 9596ebb7 pbrook
static void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
69 0ff596d0 pbrook
{
70 1ea96673 Paul Brook
    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
71 1ea96673 Paul Brook
72 0ff596d0 pbrook
    switch (event) {
73 0ff596d0 pbrook
    case I2C_START_SEND:
74 0ff596d0 pbrook
        switch (dev->mode) {
75 0ff596d0 pbrook
        case SMBUS_IDLE:
76 0ff596d0 pbrook
            DPRINTF("Incoming data\n");
77 0ff596d0 pbrook
            dev->mode = SMBUS_WRITE_DATA;
78 0ff596d0 pbrook
            break;
79 0ff596d0 pbrook
        default:
80 0ff596d0 pbrook
            BADF("Unexpected send start condition in state %d\n", dev->mode);
81 0ff596d0 pbrook
            dev->mode = SMBUS_CONFUSED;
82 0ff596d0 pbrook
            break;
83 0ff596d0 pbrook
        }
84 0ff596d0 pbrook
        break;
85 0ff596d0 pbrook
86 0ff596d0 pbrook
    case I2C_START_RECV:
87 0ff596d0 pbrook
        switch (dev->mode) {
88 0ff596d0 pbrook
        case SMBUS_IDLE:
89 0ff596d0 pbrook
            DPRINTF("Read mode\n");
90 0ff596d0 pbrook
            dev->mode = SMBUS_RECV_BYTE;
91 0ff596d0 pbrook
            break;
92 0ff596d0 pbrook
        case SMBUS_WRITE_DATA:
93 0ff596d0 pbrook
            if (dev->data_len == 0) {
94 0ff596d0 pbrook
                BADF("Read after write with no data\n");
95 0ff596d0 pbrook
                dev->mode = SMBUS_CONFUSED;
96 0ff596d0 pbrook
            } else {
97 0ff596d0 pbrook
                if (dev->data_len > 1) {
98 0ff596d0 pbrook
                    smbus_do_write(dev);
99 0ff596d0 pbrook
                } else {
100 0ff596d0 pbrook
                    dev->command = dev->data_buf[0];
101 0ff596d0 pbrook
                    DPRINTF("%02x: Command %d\n", dev->i2c.address,
102 0ff596d0 pbrook
                            dev->command);
103 0ff596d0 pbrook
                }
104 0ff596d0 pbrook
                DPRINTF("Read mode\n");
105 0ff596d0 pbrook
                dev->data_len = 0;
106 0ff596d0 pbrook
                dev->mode = SMBUS_READ_DATA;
107 0ff596d0 pbrook
            }
108 0ff596d0 pbrook
            break;
109 0ff596d0 pbrook
        default:
110 0ff596d0 pbrook
            BADF("Unexpected recv start condition in state %d\n", dev->mode);
111 0ff596d0 pbrook
            dev->mode = SMBUS_CONFUSED;
112 0ff596d0 pbrook
            break;
113 0ff596d0 pbrook
        }
114 0ff596d0 pbrook
        break;
115 0ff596d0 pbrook
116 0ff596d0 pbrook
    case I2C_FINISH:
117 0ff596d0 pbrook
        switch (dev->mode) {
118 0ff596d0 pbrook
        case SMBUS_WRITE_DATA:
119 0ff596d0 pbrook
            smbus_do_write(dev);
120 0ff596d0 pbrook
            break;
121 0ff596d0 pbrook
        case SMBUS_RECV_BYTE:
122 0ff596d0 pbrook
            smbus_do_quick_cmd(dev, 1);
123 0ff596d0 pbrook
            break;
124 0ff596d0 pbrook
        case SMBUS_READ_DATA:
125 0ff596d0 pbrook
            BADF("Unexpected stop during receive\n");
126 0ff596d0 pbrook
            break;
127 0ff596d0 pbrook
        default:
128 0ff596d0 pbrook
            /* Nothing to do.  */
129 0ff596d0 pbrook
            break;
130 0ff596d0 pbrook
        }
131 0ff596d0 pbrook
        dev->mode = SMBUS_IDLE;
132 0ff596d0 pbrook
        dev->data_len = 0;
133 0ff596d0 pbrook
        break;
134 0ff596d0 pbrook
135 0ff596d0 pbrook
    case I2C_NACK:
136 0ff596d0 pbrook
        switch (dev->mode) {
137 0ff596d0 pbrook
        case SMBUS_DONE:
138 0ff596d0 pbrook
            /* Nothing to do.  */
139 0ff596d0 pbrook
            break;
140 0ff596d0 pbrook
        case SMBUS_READ_DATA:
141 0ff596d0 pbrook
            dev->mode = SMBUS_DONE;
142 0ff596d0 pbrook
            break;
143 0ff596d0 pbrook
        default:
144 0ff596d0 pbrook
            BADF("Unexpected NACK in state %d\n", dev->mode);
145 0ff596d0 pbrook
            dev->mode = SMBUS_CONFUSED;
146 0ff596d0 pbrook
            break;
147 0ff596d0 pbrook
        }
148 0ff596d0 pbrook
    }
149 0ff596d0 pbrook
}
150 0ff596d0 pbrook
151 0ff596d0 pbrook
static int smbus_i2c_recv(i2c_slave *s)
152 0ff596d0 pbrook
{
153 1ea96673 Paul Brook
    SMBusDeviceInfo *t = container_of(s->info, SMBusDeviceInfo, i2c);
154 1ea96673 Paul Brook
    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
155 0ff596d0 pbrook
    int ret;
156 0ff596d0 pbrook
157 0ff596d0 pbrook
    switch (dev->mode) {
158 0ff596d0 pbrook
    case SMBUS_RECV_BYTE:
159 1ea96673 Paul Brook
        if (t->receive_byte) {
160 1ea96673 Paul Brook
            ret = t->receive_byte(dev);
161 0ff596d0 pbrook
        } else {
162 0ff596d0 pbrook
            ret = 0;
163 0ff596d0 pbrook
        }
164 0ff596d0 pbrook
        DPRINTF("Receive Byte %02x\n", ret);
165 0ff596d0 pbrook
        dev->mode = SMBUS_DONE;
166 0ff596d0 pbrook
        break;
167 0ff596d0 pbrook
    case SMBUS_READ_DATA:
168 1ea96673 Paul Brook
        if (t->read_data) {
169 1ea96673 Paul Brook
            ret = t->read_data(dev, dev->command, dev->data_len);
170 0ff596d0 pbrook
            dev->data_len++;
171 0ff596d0 pbrook
        } else {
172 0ff596d0 pbrook
            ret = 0;
173 0ff596d0 pbrook
        }
174 0ff596d0 pbrook
        DPRINTF("Read data %02x\n", ret);
175 0ff596d0 pbrook
        break;
176 0ff596d0 pbrook
    default:
177 0ff596d0 pbrook
        BADF("Unexpected read in state %d\n", dev->mode);
178 0ff596d0 pbrook
        dev->mode = SMBUS_CONFUSED;
179 0ff596d0 pbrook
        ret = 0;
180 0ff596d0 pbrook
        break;
181 0ff596d0 pbrook
    }
182 0ff596d0 pbrook
    return ret;
183 0ff596d0 pbrook
}
184 0ff596d0 pbrook
185 0ff596d0 pbrook
static int smbus_i2c_send(i2c_slave *s, uint8_t data)
186 0ff596d0 pbrook
{
187 1ea96673 Paul Brook
    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
188 1ea96673 Paul Brook
189 0ff596d0 pbrook
    switch (dev->mode) {
190 0ff596d0 pbrook
    case SMBUS_WRITE_DATA:
191 0ff596d0 pbrook
        DPRINTF("Write data %02x\n", data);
192 0ff596d0 pbrook
        dev->data_buf[dev->data_len++] = data;
193 0ff596d0 pbrook
        break;
194 0ff596d0 pbrook
    default:
195 0ff596d0 pbrook
        BADF("Unexpected write in state %d\n", dev->mode);
196 0ff596d0 pbrook
        break;
197 0ff596d0 pbrook
    }
198 0ff596d0 pbrook
    return 0;
199 0ff596d0 pbrook
}
200 0ff596d0 pbrook
201 81a322d4 Gerd Hoffmann
static int smbus_device_init(i2c_slave *i2c)
202 0ff596d0 pbrook
{
203 1ea96673 Paul Brook
    SMBusDeviceInfo *t = container_of(i2c->info, SMBusDeviceInfo, i2c);
204 1ea96673 Paul Brook
    SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, i2c);
205 0ff596d0 pbrook
206 81a322d4 Gerd Hoffmann
    return t->init(dev);
207 1ea96673 Paul Brook
}
208 0ff596d0 pbrook
209 074f2fff Gerd Hoffmann
void smbus_register_device(SMBusDeviceInfo *info)
210 1ea96673 Paul Brook
{
211 074f2fff Gerd Hoffmann
    assert(info->i2c.qdev.size >= sizeof(SMBusDevice));
212 1ea96673 Paul Brook
    info->i2c.init = smbus_device_init;
213 1ea96673 Paul Brook
    info->i2c.event = smbus_i2c_event;
214 1ea96673 Paul Brook
    info->i2c.recv = smbus_i2c_recv;
215 1ea96673 Paul Brook
    info->i2c.send = smbus_i2c_send;
216 074f2fff Gerd Hoffmann
    i2c_register_slave(&info->i2c);
217 0ff596d0 pbrook
}
218 0ff596d0 pbrook
219 0ff596d0 pbrook
/* Master device commands.  */
220 5b7f5327 Juan Quintela
void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read)
221 0ff596d0 pbrook
{
222 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, read);
223 0ff596d0 pbrook
    i2c_end_transfer(bus);
224 0ff596d0 pbrook
}
225 0ff596d0 pbrook
226 5b7f5327 Juan Quintela
uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr)
227 0ff596d0 pbrook
{
228 0ff596d0 pbrook
    uint8_t data;
229 0ff596d0 pbrook
230 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 1);
231 0ff596d0 pbrook
    data = i2c_recv(bus);
232 0ff596d0 pbrook
    i2c_nack(bus);
233 0ff596d0 pbrook
    i2c_end_transfer(bus);
234 0ff596d0 pbrook
    return data;
235 0ff596d0 pbrook
}
236 0ff596d0 pbrook
237 5b7f5327 Juan Quintela
void smbus_send_byte(i2c_bus *bus, uint8_t addr, uint8_t data)
238 0ff596d0 pbrook
{
239 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 0);
240 0ff596d0 pbrook
    i2c_send(bus, data);
241 0ff596d0 pbrook
    i2c_end_transfer(bus);
242 0ff596d0 pbrook
}
243 0ff596d0 pbrook
244 5b7f5327 Juan Quintela
uint8_t smbus_read_byte(i2c_bus *bus, uint8_t addr, uint8_t command)
245 0ff596d0 pbrook
{
246 0ff596d0 pbrook
    uint8_t data;
247 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 0);
248 0ff596d0 pbrook
    i2c_send(bus, command);
249 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 1);
250 0ff596d0 pbrook
    data = i2c_recv(bus);
251 0ff596d0 pbrook
    i2c_nack(bus);
252 0ff596d0 pbrook
    i2c_end_transfer(bus);
253 0ff596d0 pbrook
    return data;
254 0ff596d0 pbrook
}
255 0ff596d0 pbrook
256 5b7f5327 Juan Quintela
void smbus_write_byte(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t data)
257 0ff596d0 pbrook
{
258 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 0);
259 0ff596d0 pbrook
    i2c_send(bus, command);
260 0ff596d0 pbrook
    i2c_send(bus, data);
261 0ff596d0 pbrook
    i2c_end_transfer(bus);
262 0ff596d0 pbrook
}
263 0ff596d0 pbrook
264 5b7f5327 Juan Quintela
uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command)
265 0ff596d0 pbrook
{
266 0ff596d0 pbrook
    uint16_t data;
267 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 0);
268 0ff596d0 pbrook
    i2c_send(bus, command);
269 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 1);
270 0ff596d0 pbrook
    data = i2c_recv(bus);
271 0ff596d0 pbrook
    data |= i2c_recv(bus) << 8;
272 0ff596d0 pbrook
    i2c_nack(bus);
273 0ff596d0 pbrook
    i2c_end_transfer(bus);
274 0ff596d0 pbrook
    return data;
275 0ff596d0 pbrook
}
276 0ff596d0 pbrook
277 5b7f5327 Juan Quintela
void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data)
278 0ff596d0 pbrook
{
279 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 0);
280 0ff596d0 pbrook
    i2c_send(bus, command);
281 0ff596d0 pbrook
    i2c_send(bus, data & 0xff);
282 0ff596d0 pbrook
    i2c_send(bus, data >> 8);
283 0ff596d0 pbrook
    i2c_end_transfer(bus);
284 0ff596d0 pbrook
}
285 0ff596d0 pbrook
286 5b7f5327 Juan Quintela
int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data)
287 0ff596d0 pbrook
{
288 0ff596d0 pbrook
    int len;
289 0ff596d0 pbrook
    int i;
290 0ff596d0 pbrook
291 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 0);
292 0ff596d0 pbrook
    i2c_send(bus, command);
293 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 1);
294 0ff596d0 pbrook
    len = i2c_recv(bus);
295 0ff596d0 pbrook
    if (len > 32)
296 0ff596d0 pbrook
        len = 0;
297 0ff596d0 pbrook
    for (i = 0; i < len; i++)
298 0ff596d0 pbrook
        data[i] = i2c_recv(bus);
299 0ff596d0 pbrook
    i2c_nack(bus);
300 0ff596d0 pbrook
    i2c_end_transfer(bus);
301 0ff596d0 pbrook
    return len;
302 0ff596d0 pbrook
}
303 0ff596d0 pbrook
304 5b7f5327 Juan Quintela
void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
305 0ff596d0 pbrook
                       int len)
306 0ff596d0 pbrook
{
307 0ff596d0 pbrook
    int i;
308 0ff596d0 pbrook
309 0ff596d0 pbrook
    if (len > 32)
310 0ff596d0 pbrook
        len = 32;
311 0ff596d0 pbrook
312 0ff596d0 pbrook
    i2c_start_transfer(bus, addr, 0);
313 0ff596d0 pbrook
    i2c_send(bus, command);
314 0ff596d0 pbrook
    i2c_send(bus, len);
315 0ff596d0 pbrook
    for (i = 0; i < len; i++)
316 0ff596d0 pbrook
        i2c_send(bus, data[i]);
317 0ff596d0 pbrook
    i2c_end_transfer(bus);
318 0ff596d0 pbrook
}