10ff596d0Spbrook /* 20ff596d0Spbrook * QEMU SMBus device emulation. 30ff596d0Spbrook * 493198b6cSCorey Minyard * This code is a helper for SMBus device emulation. It implements an 593198b6cSCorey Minyard * I2C device inteface and runs the SMBus protocol from the device 693198b6cSCorey Minyard * point of view and maps those to simple calls to emulate. 793198b6cSCorey Minyard * 80ff596d0Spbrook * Copyright (c) 2007 CodeSourcery. 90ff596d0Spbrook * Written by Paul Brook 100ff596d0Spbrook * 118e31bf38SMatthew Fernandez * This code is licensed under the LGPL. 120ff596d0Spbrook */ 130ff596d0Spbrook 140ff596d0Spbrook /* TODO: Implement PEC. */ 150ff596d0Spbrook 160430891cSPeter Maydell #include "qemu/osdep.h" 1783c9f4caSPaolo Bonzini #include "hw/hw.h" 180d09e41aSPaolo Bonzini #include "hw/i2c/i2c.h" 1993198b6cSCorey Minyard #include "hw/i2c/smbus_slave.h" 200ff596d0Spbrook 210ff596d0Spbrook //#define DEBUG_SMBUS 1 220ff596d0Spbrook 230ff596d0Spbrook #ifdef DEBUG_SMBUS 24001faf32SBlue Swirl #define DPRINTF(fmt, ...) \ 25001faf32SBlue Swirl do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0) 26001faf32SBlue Swirl #define BADF(fmt, ...) \ 27001faf32SBlue Swirl do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) 280ff596d0Spbrook #else 29001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0) 30001faf32SBlue Swirl #define BADF(fmt, ...) \ 31001faf32SBlue Swirl do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0) 320ff596d0Spbrook #endif 330ff596d0Spbrook 340ff596d0Spbrook enum { 350ff596d0Spbrook SMBUS_IDLE, 360ff596d0Spbrook SMBUS_WRITE_DATA, 370ff596d0Spbrook SMBUS_RECV_BYTE, 380ff596d0Spbrook SMBUS_READ_DATA, 390ff596d0Spbrook SMBUS_DONE, 400ff596d0Spbrook SMBUS_CONFUSED = -1 410ff596d0Spbrook }; 420ff596d0Spbrook 430ff596d0Spbrook static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) 440ff596d0Spbrook { 45b5ea9327SAnthony Liguori SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); 461ea96673SPaul Brook 470ff596d0Spbrook DPRINTF("Quick Command %d\n", recv); 48b5ea9327SAnthony Liguori if (sc->quick_cmd) { 49b5ea9327SAnthony Liguori sc->quick_cmd(dev, recv); 50b5ea9327SAnthony Liguori } 510ff596d0Spbrook } 520ff596d0Spbrook 530ff596d0Spbrook static void smbus_do_write(SMBusDevice *dev) 540ff596d0Spbrook { 55b5ea9327SAnthony Liguori SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); 561ea96673SPaul Brook 57*9cf27d74SCorey Minyard DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len); 58b5ea9327SAnthony Liguori if (sc->write_data) { 59*9cf27d74SCorey Minyard sc->write_data(dev, dev->data_buf, dev->data_len); 600ff596d0Spbrook } 610ff596d0Spbrook } 620ff596d0Spbrook 63d307c28cSCorey Minyard static int smbus_i2c_event(I2CSlave *s, enum i2c_event event) 640ff596d0Spbrook { 65b5ea9327SAnthony Liguori SMBusDevice *dev = SMBUS_DEVICE(s); 661ea96673SPaul Brook 670ff596d0Spbrook switch (event) { 680ff596d0Spbrook case I2C_START_SEND: 690ff596d0Spbrook switch (dev->mode) { 700ff596d0Spbrook case SMBUS_IDLE: 710ff596d0Spbrook DPRINTF("Incoming data\n"); 720ff596d0Spbrook dev->mode = SMBUS_WRITE_DATA; 730ff596d0Spbrook break; 740ff596d0Spbrook default: 750ff596d0Spbrook BADF("Unexpected send start condition in state %d\n", dev->mode); 760ff596d0Spbrook dev->mode = SMBUS_CONFUSED; 770ff596d0Spbrook break; 780ff596d0Spbrook } 790ff596d0Spbrook break; 800ff596d0Spbrook 810ff596d0Spbrook case I2C_START_RECV: 820ff596d0Spbrook switch (dev->mode) { 830ff596d0Spbrook case SMBUS_IDLE: 840ff596d0Spbrook DPRINTF("Read mode\n"); 850ff596d0Spbrook dev->mode = SMBUS_RECV_BYTE; 860ff596d0Spbrook break; 870ff596d0Spbrook case SMBUS_WRITE_DATA: 880ff596d0Spbrook if (dev->data_len == 0) { 890ff596d0Spbrook BADF("Read after write with no data\n"); 900ff596d0Spbrook dev->mode = SMBUS_CONFUSED; 910ff596d0Spbrook } else { 920ff596d0Spbrook smbus_do_write(dev); 930ff596d0Spbrook DPRINTF("Read mode\n"); 940ff596d0Spbrook dev->data_len = 0; 950ff596d0Spbrook dev->mode = SMBUS_READ_DATA; 960ff596d0Spbrook } 970ff596d0Spbrook break; 980ff596d0Spbrook default: 990ff596d0Spbrook BADF("Unexpected recv start condition in state %d\n", dev->mode); 1000ff596d0Spbrook dev->mode = SMBUS_CONFUSED; 1010ff596d0Spbrook break; 1020ff596d0Spbrook } 1030ff596d0Spbrook break; 1040ff596d0Spbrook 1050ff596d0Spbrook case I2C_FINISH: 106905cec6dSCorey Minyard if (dev->data_len == 0) { 107905cec6dSCorey Minyard if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) { 108905cec6dSCorey Minyard smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA); 109905cec6dSCorey Minyard } 110905cec6dSCorey Minyard } else { 1110ff596d0Spbrook switch (dev->mode) { 1120ff596d0Spbrook case SMBUS_WRITE_DATA: 1130ff596d0Spbrook smbus_do_write(dev); 1140ff596d0Spbrook break; 115905cec6dSCorey Minyard 1160ff596d0Spbrook case SMBUS_READ_DATA: 1170ff596d0Spbrook BADF("Unexpected stop during receive\n"); 1180ff596d0Spbrook break; 119905cec6dSCorey Minyard 1200ff596d0Spbrook default: 1210ff596d0Spbrook /* Nothing to do. */ 1220ff596d0Spbrook break; 1230ff596d0Spbrook } 124905cec6dSCorey Minyard } 1250ff596d0Spbrook dev->mode = SMBUS_IDLE; 1260ff596d0Spbrook dev->data_len = 0; 1270ff596d0Spbrook break; 1280ff596d0Spbrook 1290ff596d0Spbrook case I2C_NACK: 1300ff596d0Spbrook switch (dev->mode) { 1310ff596d0Spbrook case SMBUS_DONE: 1320ff596d0Spbrook /* Nothing to do. */ 1330ff596d0Spbrook break; 1340ff596d0Spbrook case SMBUS_READ_DATA: 1350ff596d0Spbrook dev->mode = SMBUS_DONE; 1360ff596d0Spbrook break; 1370ff596d0Spbrook default: 1380ff596d0Spbrook BADF("Unexpected NACK in state %d\n", dev->mode); 1390ff596d0Spbrook dev->mode = SMBUS_CONFUSED; 1400ff596d0Spbrook break; 1410ff596d0Spbrook } 1420ff596d0Spbrook } 143d307c28cSCorey Minyard 144d307c28cSCorey Minyard return 0; 1450ff596d0Spbrook } 1460ff596d0Spbrook 1472ac4c5f4SCorey Minyard static uint8_t smbus_i2c_recv(I2CSlave *s) 1480ff596d0Spbrook { 149b5ea9327SAnthony Liguori SMBusDevice *dev = SMBUS_DEVICE(s); 150b5ea9327SAnthony Liguori SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); 1512ac4c5f4SCorey Minyard uint8_t ret; 1520ff596d0Spbrook 1530ff596d0Spbrook switch (dev->mode) { 1540ff596d0Spbrook case SMBUS_RECV_BYTE: 155b5ea9327SAnthony Liguori if (sc->receive_byte) { 156b5ea9327SAnthony Liguori ret = sc->receive_byte(dev); 1570ff596d0Spbrook } else { 1580ff596d0Spbrook ret = 0; 1590ff596d0Spbrook } 1600ff596d0Spbrook DPRINTF("Receive Byte %02x\n", ret); 1610ff596d0Spbrook dev->mode = SMBUS_DONE; 1620ff596d0Spbrook break; 1630ff596d0Spbrook case SMBUS_READ_DATA: 164b5ea9327SAnthony Liguori if (sc->read_data) { 165*9cf27d74SCorey Minyard ret = sc->read_data(dev, dev->data_len); 1660ff596d0Spbrook dev->data_len++; 1670ff596d0Spbrook } else { 1680ff596d0Spbrook ret = 0; 1690ff596d0Spbrook } 1700ff596d0Spbrook DPRINTF("Read data %02x\n", ret); 1710ff596d0Spbrook break; 1720ff596d0Spbrook default: 1730ff596d0Spbrook BADF("Unexpected read in state %d\n", dev->mode); 1740ff596d0Spbrook dev->mode = SMBUS_CONFUSED; 1750ff596d0Spbrook ret = 0; 1760ff596d0Spbrook break; 1770ff596d0Spbrook } 1780ff596d0Spbrook return ret; 1790ff596d0Spbrook } 1800ff596d0Spbrook 1819e07bdf8SAnthony Liguori static int smbus_i2c_send(I2CSlave *s, uint8_t data) 1820ff596d0Spbrook { 183b5ea9327SAnthony Liguori SMBusDevice *dev = SMBUS_DEVICE(s); 1841ea96673SPaul Brook 1850ff596d0Spbrook switch (dev->mode) { 1860ff596d0Spbrook case SMBUS_WRITE_DATA: 1870ff596d0Spbrook DPRINTF("Write data %02x\n", data); 188629457a1SCorey Minyard if (dev->data_len >= sizeof(dev->data_buf)) { 189629457a1SCorey Minyard BADF("Too many bytes sent\n"); 190629457a1SCorey Minyard } else { 1910ff596d0Spbrook dev->data_buf[dev->data_len++] = data; 192629457a1SCorey Minyard } 1930ff596d0Spbrook break; 1940ff596d0Spbrook default: 1950ff596d0Spbrook BADF("Unexpected write in state %d\n", dev->mode); 1960ff596d0Spbrook break; 1970ff596d0Spbrook } 1980ff596d0Spbrook return 0; 1990ff596d0Spbrook } 2000ff596d0Spbrook 201b5ea9327SAnthony Liguori static void smbus_device_class_init(ObjectClass *klass, void *data) 202b5ea9327SAnthony Liguori { 203b5ea9327SAnthony Liguori I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); 204b5ea9327SAnthony Liguori 205b5ea9327SAnthony Liguori sc->event = smbus_i2c_event; 206b5ea9327SAnthony Liguori sc->recv = smbus_i2c_recv; 207b5ea9327SAnthony Liguori sc->send = smbus_i2c_send; 208b5ea9327SAnthony Liguori } 209b5ea9327SAnthony Liguori 2108c43a6f0SAndreas Färber static const TypeInfo smbus_device_type_info = { 211b5ea9327SAnthony Liguori .name = TYPE_SMBUS_DEVICE, 212b5ea9327SAnthony Liguori .parent = TYPE_I2C_SLAVE, 213b5ea9327SAnthony Liguori .instance_size = sizeof(SMBusDevice), 214b5ea9327SAnthony Liguori .abstract = true, 215b5ea9327SAnthony Liguori .class_size = sizeof(SMBusDeviceClass), 216b5ea9327SAnthony Liguori .class_init = smbus_device_class_init, 217b5ea9327SAnthony Liguori }; 218b5ea9327SAnthony Liguori 21983f7d43aSAndreas Färber static void smbus_device_register_types(void) 220b5ea9327SAnthony Liguori { 221b5ea9327SAnthony Liguori type_register_static(&smbus_device_type_info); 222b5ea9327SAnthony Liguori } 223b5ea9327SAnthony Liguori 22483f7d43aSAndreas Färber type_init(smbus_device_register_types) 225