Statistics
| Branch: | Revision:

root / hw / smbus.c @ e62b5b13

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