xref: /qemu/hw/i2c/smbus_slave.c (revision 629457a13080052c575779e1fd9f5eb5ee6b8ad9)
10ff596d0Spbrook /*
20ff596d0Spbrook  * QEMU SMBus device emulation.
30ff596d0Spbrook  *
40ff596d0Spbrook  * Copyright (c) 2007 CodeSourcery.
50ff596d0Spbrook  * Written by Paul Brook
60ff596d0Spbrook  *
78e31bf38SMatthew Fernandez  * This code is licensed under the LGPL.
80ff596d0Spbrook  */
90ff596d0Spbrook 
100ff596d0Spbrook /* TODO: Implement PEC.  */
110ff596d0Spbrook 
120430891cSPeter Maydell #include "qemu/osdep.h"
1383c9f4caSPaolo Bonzini #include "hw/hw.h"
140d09e41aSPaolo Bonzini #include "hw/i2c/i2c.h"
150d09e41aSPaolo Bonzini #include "hw/i2c/smbus.h"
160ff596d0Spbrook 
170ff596d0Spbrook //#define DEBUG_SMBUS 1
180ff596d0Spbrook 
190ff596d0Spbrook #ifdef DEBUG_SMBUS
20001faf32SBlue Swirl #define DPRINTF(fmt, ...) \
21001faf32SBlue Swirl do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
22001faf32SBlue Swirl #define BADF(fmt, ...) \
23001faf32SBlue Swirl do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
240ff596d0Spbrook #else
25001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0)
26001faf32SBlue Swirl #define BADF(fmt, ...) \
27001faf32SBlue Swirl do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
280ff596d0Spbrook #endif
290ff596d0Spbrook 
300ff596d0Spbrook enum {
310ff596d0Spbrook     SMBUS_IDLE,
320ff596d0Spbrook     SMBUS_WRITE_DATA,
330ff596d0Spbrook     SMBUS_RECV_BYTE,
340ff596d0Spbrook     SMBUS_READ_DATA,
350ff596d0Spbrook     SMBUS_DONE,
360ff596d0Spbrook     SMBUS_CONFUSED = -1
370ff596d0Spbrook };
380ff596d0Spbrook 
390ff596d0Spbrook static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
400ff596d0Spbrook {
41b5ea9327SAnthony Liguori     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
421ea96673SPaul Brook 
430ff596d0Spbrook     DPRINTF("Quick Command %d\n", recv);
44b5ea9327SAnthony Liguori     if (sc->quick_cmd) {
45b5ea9327SAnthony Liguori         sc->quick_cmd(dev, recv);
46b5ea9327SAnthony Liguori     }
470ff596d0Spbrook }
480ff596d0Spbrook 
490ff596d0Spbrook static void smbus_do_write(SMBusDevice *dev)
500ff596d0Spbrook {
51b5ea9327SAnthony Liguori     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
521ea96673SPaul Brook 
530ff596d0Spbrook     if (dev->data_len == 0) {
540ff596d0Spbrook         smbus_do_quick_cmd(dev, 0);
550ff596d0Spbrook     } else if (dev->data_len == 1) {
560ff596d0Spbrook         DPRINTF("Send Byte\n");
57b5ea9327SAnthony Liguori         if (sc->send_byte) {
58b5ea9327SAnthony Liguori             sc->send_byte(dev, dev->data_buf[0]);
590ff596d0Spbrook         }
600ff596d0Spbrook     } else {
610ff596d0Spbrook         dev->command = dev->data_buf[0];
620ff596d0Spbrook         DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
63b5ea9327SAnthony Liguori         if (sc->write_data) {
64b5ea9327SAnthony Liguori             sc->write_data(dev, dev->command, dev->data_buf + 1,
650ff596d0Spbrook                            dev->data_len - 1);
660ff596d0Spbrook         }
670ff596d0Spbrook     }
680ff596d0Spbrook }
690ff596d0Spbrook 
70d307c28cSCorey Minyard static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
710ff596d0Spbrook {
72b5ea9327SAnthony Liguori     SMBusDevice *dev = SMBUS_DEVICE(s);
731ea96673SPaul Brook 
740ff596d0Spbrook     switch (event) {
750ff596d0Spbrook     case I2C_START_SEND:
760ff596d0Spbrook         switch (dev->mode) {
770ff596d0Spbrook         case SMBUS_IDLE:
780ff596d0Spbrook             DPRINTF("Incoming data\n");
790ff596d0Spbrook             dev->mode = SMBUS_WRITE_DATA;
800ff596d0Spbrook             break;
810ff596d0Spbrook         default:
820ff596d0Spbrook             BADF("Unexpected send start condition in state %d\n", dev->mode);
830ff596d0Spbrook             dev->mode = SMBUS_CONFUSED;
840ff596d0Spbrook             break;
850ff596d0Spbrook         }
860ff596d0Spbrook         break;
870ff596d0Spbrook 
880ff596d0Spbrook     case I2C_START_RECV:
890ff596d0Spbrook         switch (dev->mode) {
900ff596d0Spbrook         case SMBUS_IDLE:
910ff596d0Spbrook             DPRINTF("Read mode\n");
920ff596d0Spbrook             dev->mode = SMBUS_RECV_BYTE;
930ff596d0Spbrook             break;
940ff596d0Spbrook         case SMBUS_WRITE_DATA:
950ff596d0Spbrook             if (dev->data_len == 0) {
960ff596d0Spbrook                 BADF("Read after write with no data\n");
970ff596d0Spbrook                 dev->mode = SMBUS_CONFUSED;
980ff596d0Spbrook             } else {
990ff596d0Spbrook                 if (dev->data_len > 1) {
1000ff596d0Spbrook                     smbus_do_write(dev);
1010ff596d0Spbrook                 } else {
1020ff596d0Spbrook                     dev->command = dev->data_buf[0];
1030ff596d0Spbrook                     DPRINTF("%02x: Command %d\n", dev->i2c.address,
1040ff596d0Spbrook                             dev->command);
1050ff596d0Spbrook                 }
1060ff596d0Spbrook                 DPRINTF("Read mode\n");
1070ff596d0Spbrook                 dev->data_len = 0;
1080ff596d0Spbrook                 dev->mode = SMBUS_READ_DATA;
1090ff596d0Spbrook             }
1100ff596d0Spbrook             break;
1110ff596d0Spbrook         default:
1120ff596d0Spbrook             BADF("Unexpected recv start condition in state %d\n", dev->mode);
1130ff596d0Spbrook             dev->mode = SMBUS_CONFUSED;
1140ff596d0Spbrook             break;
1150ff596d0Spbrook         }
1160ff596d0Spbrook         break;
1170ff596d0Spbrook 
1180ff596d0Spbrook     case I2C_FINISH:
1190ff596d0Spbrook         switch (dev->mode) {
1200ff596d0Spbrook         case SMBUS_WRITE_DATA:
1210ff596d0Spbrook             smbus_do_write(dev);
1220ff596d0Spbrook             break;
1230ff596d0Spbrook         case SMBUS_RECV_BYTE:
1240ff596d0Spbrook             smbus_do_quick_cmd(dev, 1);
1250ff596d0Spbrook             break;
1260ff596d0Spbrook         case SMBUS_READ_DATA:
1270ff596d0Spbrook             BADF("Unexpected stop during receive\n");
1280ff596d0Spbrook             break;
1290ff596d0Spbrook         default:
1300ff596d0Spbrook             /* Nothing to do.  */
1310ff596d0Spbrook             break;
1320ff596d0Spbrook         }
1330ff596d0Spbrook         dev->mode = SMBUS_IDLE;
1340ff596d0Spbrook         dev->data_len = 0;
1350ff596d0Spbrook         break;
1360ff596d0Spbrook 
1370ff596d0Spbrook     case I2C_NACK:
1380ff596d0Spbrook         switch (dev->mode) {
1390ff596d0Spbrook         case SMBUS_DONE:
1400ff596d0Spbrook             /* Nothing to do.  */
1410ff596d0Spbrook             break;
1420ff596d0Spbrook         case SMBUS_READ_DATA:
1430ff596d0Spbrook             dev->mode = SMBUS_DONE;
1440ff596d0Spbrook             break;
1450ff596d0Spbrook         default:
1460ff596d0Spbrook             BADF("Unexpected NACK in state %d\n", dev->mode);
1470ff596d0Spbrook             dev->mode = SMBUS_CONFUSED;
1480ff596d0Spbrook             break;
1490ff596d0Spbrook         }
1500ff596d0Spbrook     }
151d307c28cSCorey Minyard 
152d307c28cSCorey Minyard     return 0;
1530ff596d0Spbrook }
1540ff596d0Spbrook 
1559e07bdf8SAnthony Liguori static int smbus_i2c_recv(I2CSlave *s)
1560ff596d0Spbrook {
157b5ea9327SAnthony Liguori     SMBusDevice *dev = SMBUS_DEVICE(s);
158b5ea9327SAnthony Liguori     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
1590ff596d0Spbrook     int ret;
1600ff596d0Spbrook 
1610ff596d0Spbrook     switch (dev->mode) {
1620ff596d0Spbrook     case SMBUS_RECV_BYTE:
163b5ea9327SAnthony Liguori         if (sc->receive_byte) {
164b5ea9327SAnthony Liguori             ret = sc->receive_byte(dev);
1650ff596d0Spbrook         } else {
1660ff596d0Spbrook             ret = 0;
1670ff596d0Spbrook         }
1680ff596d0Spbrook         DPRINTF("Receive Byte %02x\n", ret);
1690ff596d0Spbrook         dev->mode = SMBUS_DONE;
1700ff596d0Spbrook         break;
1710ff596d0Spbrook     case SMBUS_READ_DATA:
172b5ea9327SAnthony Liguori         if (sc->read_data) {
173b5ea9327SAnthony Liguori             ret = sc->read_data(dev, dev->command, dev->data_len);
1740ff596d0Spbrook             dev->data_len++;
1750ff596d0Spbrook         } else {
1760ff596d0Spbrook             ret = 0;
1770ff596d0Spbrook         }
1780ff596d0Spbrook         DPRINTF("Read data %02x\n", ret);
1790ff596d0Spbrook         break;
1800ff596d0Spbrook     default:
1810ff596d0Spbrook         BADF("Unexpected read in state %d\n", dev->mode);
1820ff596d0Spbrook         dev->mode = SMBUS_CONFUSED;
1830ff596d0Spbrook         ret = 0;
1840ff596d0Spbrook         break;
1850ff596d0Spbrook     }
1860ff596d0Spbrook     return ret;
1870ff596d0Spbrook }
1880ff596d0Spbrook 
1899e07bdf8SAnthony Liguori static int smbus_i2c_send(I2CSlave *s, uint8_t data)
1900ff596d0Spbrook {
191b5ea9327SAnthony Liguori     SMBusDevice *dev = SMBUS_DEVICE(s);
1921ea96673SPaul Brook 
1930ff596d0Spbrook     switch (dev->mode) {
1940ff596d0Spbrook     case SMBUS_WRITE_DATA:
1950ff596d0Spbrook         DPRINTF("Write data %02x\n", data);
196*629457a1SCorey Minyard         if (dev->data_len >= sizeof(dev->data_buf)) {
197*629457a1SCorey Minyard             BADF("Too many bytes sent\n");
198*629457a1SCorey Minyard         } else {
1990ff596d0Spbrook             dev->data_buf[dev->data_len++] = data;
200*629457a1SCorey Minyard         }
2010ff596d0Spbrook         break;
2020ff596d0Spbrook     default:
2030ff596d0Spbrook         BADF("Unexpected write in state %d\n", dev->mode);
2040ff596d0Spbrook         break;
2050ff596d0Spbrook     }
2060ff596d0Spbrook     return 0;
2070ff596d0Spbrook }
2080ff596d0Spbrook 
2090ff596d0Spbrook /* Master device commands.  */
210046a1844SPaolo Bonzini int smbus_quick_command(I2CBus *bus, uint8_t addr, int read)
2110ff596d0Spbrook {
212046a1844SPaolo Bonzini     if (i2c_start_transfer(bus, addr, read)) {
213046a1844SPaolo Bonzini         return -1;
214046a1844SPaolo Bonzini     }
2150ff596d0Spbrook     i2c_end_transfer(bus);
216046a1844SPaolo Bonzini     return 0;
2170ff596d0Spbrook }
2180ff596d0Spbrook 
219285364e9SPaolo Bonzini int smbus_receive_byte(I2CBus *bus, uint8_t addr)
2200ff596d0Spbrook {
2210ff596d0Spbrook     uint8_t data;
2220ff596d0Spbrook 
223046a1844SPaolo Bonzini     if (i2c_start_transfer(bus, addr, 1)) {
224046a1844SPaolo Bonzini         return -1;
225046a1844SPaolo Bonzini     }
2260ff596d0Spbrook     data = i2c_recv(bus);
2270ff596d0Spbrook     i2c_nack(bus);
2280ff596d0Spbrook     i2c_end_transfer(bus);
2290ff596d0Spbrook     return data;
2300ff596d0Spbrook }
2310ff596d0Spbrook 
232046a1844SPaolo Bonzini int smbus_send_byte(I2CBus *bus, uint8_t addr, uint8_t data)
2330ff596d0Spbrook {
234046a1844SPaolo Bonzini     if (i2c_start_transfer(bus, addr, 0)) {
235046a1844SPaolo Bonzini         return -1;
236046a1844SPaolo Bonzini     }
2370ff596d0Spbrook     i2c_send(bus, data);
2380ff596d0Spbrook     i2c_end_transfer(bus);
239046a1844SPaolo Bonzini     return 0;
2400ff596d0Spbrook }
2410ff596d0Spbrook 
242285364e9SPaolo Bonzini int smbus_read_byte(I2CBus *bus, uint8_t addr, uint8_t command)
2430ff596d0Spbrook {
2440ff596d0Spbrook     uint8_t data;
245046a1844SPaolo Bonzini     if (i2c_start_transfer(bus, addr, 0)) {
246046a1844SPaolo Bonzini         return -1;
247046a1844SPaolo Bonzini     }
2480ff596d0Spbrook     i2c_send(bus, command);
249cc083d8aSCorey Minyard     if (i2c_start_transfer(bus, addr, 1)) {
250d307c28cSCorey Minyard         i2c_end_transfer(bus);
251d307c28cSCorey Minyard         return -1;
252cc083d8aSCorey Minyard     }
2530ff596d0Spbrook     data = i2c_recv(bus);
2540ff596d0Spbrook     i2c_nack(bus);
2550ff596d0Spbrook     i2c_end_transfer(bus);
2560ff596d0Spbrook     return data;
2570ff596d0Spbrook }
2580ff596d0Spbrook 
259046a1844SPaolo Bonzini int smbus_write_byte(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t data)
2600ff596d0Spbrook {
261046a1844SPaolo Bonzini     if (i2c_start_transfer(bus, addr, 0)) {
262046a1844SPaolo Bonzini         return -1;
263046a1844SPaolo Bonzini     }
2640ff596d0Spbrook     i2c_send(bus, command);
2650ff596d0Spbrook     i2c_send(bus, data);
2660ff596d0Spbrook     i2c_end_transfer(bus);
267046a1844SPaolo Bonzini     return 0;
2680ff596d0Spbrook }
2690ff596d0Spbrook 
270285364e9SPaolo Bonzini int smbus_read_word(I2CBus *bus, uint8_t addr, uint8_t command)
2710ff596d0Spbrook {
2720ff596d0Spbrook     uint16_t data;
273046a1844SPaolo Bonzini     if (i2c_start_transfer(bus, addr, 0)) {
274046a1844SPaolo Bonzini         return -1;
275046a1844SPaolo Bonzini     }
2760ff596d0Spbrook     i2c_send(bus, command);
277cc083d8aSCorey Minyard     if (i2c_start_transfer(bus, addr, 1)) {
278d307c28cSCorey Minyard         i2c_end_transfer(bus);
279d307c28cSCorey Minyard         return -1;
280cc083d8aSCorey Minyard     }
2810ff596d0Spbrook     data = i2c_recv(bus);
2820ff596d0Spbrook     data |= i2c_recv(bus) << 8;
2830ff596d0Spbrook     i2c_nack(bus);
2840ff596d0Spbrook     i2c_end_transfer(bus);
2850ff596d0Spbrook     return data;
2860ff596d0Spbrook }
2870ff596d0Spbrook 
288046a1844SPaolo Bonzini int smbus_write_word(I2CBus *bus, uint8_t addr, uint8_t command, uint16_t data)
2890ff596d0Spbrook {
290046a1844SPaolo Bonzini     if (i2c_start_transfer(bus, addr, 0)) {
291046a1844SPaolo Bonzini         return -1;
292046a1844SPaolo Bonzini     }
2930ff596d0Spbrook     i2c_send(bus, command);
2940ff596d0Spbrook     i2c_send(bus, data & 0xff);
2950ff596d0Spbrook     i2c_send(bus, data >> 8);
2960ff596d0Spbrook     i2c_end_transfer(bus);
297046a1844SPaolo Bonzini     return 0;
2980ff596d0Spbrook }
2990ff596d0Spbrook 
3004b615be5SCorey Minyard int smbus_read_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
3014b615be5SCorey Minyard                      int len, bool recv_len, bool send_cmd)
3020ff596d0Spbrook {
3034b615be5SCorey Minyard     int rlen;
3040ff596d0Spbrook     int i;
3050ff596d0Spbrook 
3064b615be5SCorey Minyard     if (send_cmd) {
307046a1844SPaolo Bonzini         if (i2c_start_transfer(bus, addr, 0)) {
308046a1844SPaolo Bonzini             return -1;
309046a1844SPaolo Bonzini         }
3100ff596d0Spbrook         i2c_send(bus, command);
3114b615be5SCorey Minyard     }
312cc083d8aSCorey Minyard     if (i2c_start_transfer(bus, addr, 1)) {
3134b615be5SCorey Minyard         if (send_cmd) {
314d307c28cSCorey Minyard             i2c_end_transfer(bus);
3154b615be5SCorey Minyard         }
316d307c28cSCorey Minyard         return -1;
317cc083d8aSCorey Minyard     }
3184b615be5SCorey Minyard     if (recv_len) {
3194b615be5SCorey Minyard         rlen = i2c_recv(bus);
3204b615be5SCorey Minyard     } else {
3214b615be5SCorey Minyard         rlen = len;
322046a1844SPaolo Bonzini     }
3234b615be5SCorey Minyard     if (rlen > len) {
3244b615be5SCorey Minyard         rlen = 0;
3254b615be5SCorey Minyard     }
3264b615be5SCorey Minyard     for (i = 0; i < rlen; i++) {
3270ff596d0Spbrook         data[i] = i2c_recv(bus);
328046a1844SPaolo Bonzini     }
3290ff596d0Spbrook     i2c_nack(bus);
3300ff596d0Spbrook     i2c_end_transfer(bus);
3314b615be5SCorey Minyard     return rlen;
3320ff596d0Spbrook }
3330ff596d0Spbrook 
334046a1844SPaolo Bonzini int smbus_write_block(I2CBus *bus, uint8_t addr, uint8_t command, uint8_t *data,
3354b615be5SCorey Minyard                       int len, bool send_len)
3360ff596d0Spbrook {
3370ff596d0Spbrook     int i;
3380ff596d0Spbrook 
3390ff596d0Spbrook     if (len > 32)
3400ff596d0Spbrook         len = 32;
3410ff596d0Spbrook 
342046a1844SPaolo Bonzini     if (i2c_start_transfer(bus, addr, 0)) {
343046a1844SPaolo Bonzini         return -1;
344046a1844SPaolo Bonzini     }
3450ff596d0Spbrook     i2c_send(bus, command);
3464b615be5SCorey Minyard     if (send_len) {
3470ff596d0Spbrook         i2c_send(bus, len);
3484b615be5SCorey Minyard     }
349046a1844SPaolo Bonzini     for (i = 0; i < len; i++) {
3500ff596d0Spbrook         i2c_send(bus, data[i]);
351046a1844SPaolo Bonzini     }
3520ff596d0Spbrook     i2c_end_transfer(bus);
353046a1844SPaolo Bonzini     return 0;
3540ff596d0Spbrook }
355b5ea9327SAnthony Liguori 
356b5ea9327SAnthony Liguori static void smbus_device_class_init(ObjectClass *klass, void *data)
357b5ea9327SAnthony Liguori {
358b5ea9327SAnthony Liguori     I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
359b5ea9327SAnthony Liguori 
360b5ea9327SAnthony Liguori     sc->event = smbus_i2c_event;
361b5ea9327SAnthony Liguori     sc->recv = smbus_i2c_recv;
362b5ea9327SAnthony Liguori     sc->send = smbus_i2c_send;
363b5ea9327SAnthony Liguori }
364b5ea9327SAnthony Liguori 
3658c43a6f0SAndreas Färber static const TypeInfo smbus_device_type_info = {
366b5ea9327SAnthony Liguori     .name = TYPE_SMBUS_DEVICE,
367b5ea9327SAnthony Liguori     .parent = TYPE_I2C_SLAVE,
368b5ea9327SAnthony Liguori     .instance_size = sizeof(SMBusDevice),
369b5ea9327SAnthony Liguori     .abstract = true,
370b5ea9327SAnthony Liguori     .class_size = sizeof(SMBusDeviceClass),
371b5ea9327SAnthony Liguori     .class_init = smbus_device_class_init,
372b5ea9327SAnthony Liguori };
373b5ea9327SAnthony Liguori 
37483f7d43aSAndreas Färber static void smbus_device_register_types(void)
375b5ea9327SAnthony Liguori {
376b5ea9327SAnthony Liguori     type_register_static(&smbus_device_type_info);
377b5ea9327SAnthony Liguori }
378b5ea9327SAnthony Liguori 
37983f7d43aSAndreas Färber type_init(smbus_device_register_types)
380