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" 20*d6454270SMarkus Armbruster #include "migration/vmstate.h" 210b8fa32fSMarkus Armbruster #include "qemu/module.h" 220ff596d0Spbrook 230ff596d0Spbrook //#define DEBUG_SMBUS 1 240ff596d0Spbrook 250ff596d0Spbrook #ifdef DEBUG_SMBUS 26001faf32SBlue Swirl #define DPRINTF(fmt, ...) \ 27001faf32SBlue Swirl do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0) 28001faf32SBlue Swirl #define BADF(fmt, ...) \ 29001faf32SBlue Swirl do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) 300ff596d0Spbrook #else 31001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0) 32001faf32SBlue Swirl #define BADF(fmt, ...) \ 33001faf32SBlue Swirl do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0) 340ff596d0Spbrook #endif 350ff596d0Spbrook 360ff596d0Spbrook enum { 370ff596d0Spbrook SMBUS_IDLE, 380ff596d0Spbrook SMBUS_WRITE_DATA, 390ff596d0Spbrook SMBUS_READ_DATA, 400ff596d0Spbrook SMBUS_DONE, 410ff596d0Spbrook SMBUS_CONFUSED = -1 420ff596d0Spbrook }; 430ff596d0Spbrook 440ff596d0Spbrook static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) 450ff596d0Spbrook { 46b5ea9327SAnthony Liguori SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); 471ea96673SPaul Brook 480ff596d0Spbrook DPRINTF("Quick Command %d\n", recv); 49b5ea9327SAnthony Liguori if (sc->quick_cmd) { 50b5ea9327SAnthony Liguori sc->quick_cmd(dev, recv); 51b5ea9327SAnthony Liguori } 520ff596d0Spbrook } 530ff596d0Spbrook 540ff596d0Spbrook static void smbus_do_write(SMBusDevice *dev) 550ff596d0Spbrook { 56b5ea9327SAnthony Liguori SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); 571ea96673SPaul Brook 589cf27d74SCorey Minyard DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len); 59b5ea9327SAnthony Liguori if (sc->write_data) { 609cf27d74SCorey Minyard sc->write_data(dev, dev->data_buf, dev->data_len); 610ff596d0Spbrook } 620ff596d0Spbrook } 630ff596d0Spbrook 64d307c28cSCorey Minyard static int smbus_i2c_event(I2CSlave *s, enum i2c_event event) 650ff596d0Spbrook { 66b5ea9327SAnthony Liguori SMBusDevice *dev = SMBUS_DEVICE(s); 671ea96673SPaul Brook 680ff596d0Spbrook switch (event) { 690ff596d0Spbrook case I2C_START_SEND: 700ff596d0Spbrook switch (dev->mode) { 710ff596d0Spbrook case SMBUS_IDLE: 720ff596d0Spbrook DPRINTF("Incoming data\n"); 730ff596d0Spbrook dev->mode = SMBUS_WRITE_DATA; 740ff596d0Spbrook break; 758b38e532SCorey Minyard 760ff596d0Spbrook default: 770ff596d0Spbrook BADF("Unexpected send start condition in state %d\n", dev->mode); 780ff596d0Spbrook dev->mode = SMBUS_CONFUSED; 790ff596d0Spbrook break; 800ff596d0Spbrook } 810ff596d0Spbrook break; 820ff596d0Spbrook 830ff596d0Spbrook case I2C_START_RECV: 840ff596d0Spbrook switch (dev->mode) { 850ff596d0Spbrook case SMBUS_IDLE: 860ff596d0Spbrook DPRINTF("Read mode\n"); 87031ac498SCorey Minyard dev->mode = SMBUS_READ_DATA; 880ff596d0Spbrook break; 898b38e532SCorey Minyard 900ff596d0Spbrook case SMBUS_WRITE_DATA: 910ff596d0Spbrook if (dev->data_len == 0) { 920ff596d0Spbrook BADF("Read after write with no data\n"); 930ff596d0Spbrook dev->mode = SMBUS_CONFUSED; 940ff596d0Spbrook } else { 950ff596d0Spbrook smbus_do_write(dev); 960ff596d0Spbrook DPRINTF("Read mode\n"); 970ff596d0Spbrook dev->mode = SMBUS_READ_DATA; 980ff596d0Spbrook } 990ff596d0Spbrook break; 1008b38e532SCorey Minyard 1010ff596d0Spbrook default: 1020ff596d0Spbrook BADF("Unexpected recv start condition in state %d\n", dev->mode); 1030ff596d0Spbrook dev->mode = SMBUS_CONFUSED; 1040ff596d0Spbrook break; 1050ff596d0Spbrook } 1060ff596d0Spbrook break; 1070ff596d0Spbrook 1080ff596d0Spbrook case I2C_FINISH: 109905cec6dSCorey Minyard if (dev->data_len == 0) { 110905cec6dSCorey Minyard if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) { 111905cec6dSCorey Minyard smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA); 112905cec6dSCorey Minyard } 113905cec6dSCorey Minyard } else { 1140ff596d0Spbrook switch (dev->mode) { 1150ff596d0Spbrook case SMBUS_WRITE_DATA: 1160ff596d0Spbrook smbus_do_write(dev); 1170ff596d0Spbrook break; 118905cec6dSCorey Minyard 1190ff596d0Spbrook case SMBUS_READ_DATA: 1200ff596d0Spbrook BADF("Unexpected stop during receive\n"); 1210ff596d0Spbrook break; 122905cec6dSCorey Minyard 1230ff596d0Spbrook default: 1240ff596d0Spbrook /* Nothing to do. */ 1250ff596d0Spbrook break; 1260ff596d0Spbrook } 127905cec6dSCorey Minyard } 1280ff596d0Spbrook dev->mode = SMBUS_IDLE; 1290ff596d0Spbrook dev->data_len = 0; 1300ff596d0Spbrook break; 1310ff596d0Spbrook 1320ff596d0Spbrook case I2C_NACK: 1330ff596d0Spbrook switch (dev->mode) { 1340ff596d0Spbrook case SMBUS_DONE: 1350ff596d0Spbrook /* Nothing to do. */ 1360ff596d0Spbrook break; 1378b38e532SCorey Minyard 1380ff596d0Spbrook case SMBUS_READ_DATA: 1390ff596d0Spbrook dev->mode = SMBUS_DONE; 1400ff596d0Spbrook break; 1418b38e532SCorey Minyard 1420ff596d0Spbrook default: 1430ff596d0Spbrook BADF("Unexpected NACK in state %d\n", dev->mode); 1440ff596d0Spbrook dev->mode = SMBUS_CONFUSED; 1450ff596d0Spbrook break; 1460ff596d0Spbrook } 1470ff596d0Spbrook } 148d307c28cSCorey Minyard 149d307c28cSCorey Minyard return 0; 1500ff596d0Spbrook } 1510ff596d0Spbrook 1522ac4c5f4SCorey Minyard static uint8_t smbus_i2c_recv(I2CSlave *s) 1530ff596d0Spbrook { 154b5ea9327SAnthony Liguori SMBusDevice *dev = SMBUS_DEVICE(s); 155b5ea9327SAnthony Liguori SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); 156031ac498SCorey Minyard uint8_t ret = 0xff; 1570ff596d0Spbrook 1580ff596d0Spbrook switch (dev->mode) { 159031ac498SCorey Minyard case SMBUS_READ_DATA: 160b5ea9327SAnthony Liguori if (sc->receive_byte) { 161b5ea9327SAnthony Liguori ret = sc->receive_byte(dev); 1620ff596d0Spbrook } 1630ff596d0Spbrook DPRINTF("Read data %02x\n", ret); 1640ff596d0Spbrook break; 1658b38e532SCorey Minyard 1660ff596d0Spbrook default: 1670ff596d0Spbrook BADF("Unexpected read in state %d\n", dev->mode); 1680ff596d0Spbrook dev->mode = SMBUS_CONFUSED; 1690ff596d0Spbrook break; 1700ff596d0Spbrook } 1718b38e532SCorey Minyard 1720ff596d0Spbrook return ret; 1730ff596d0Spbrook } 1740ff596d0Spbrook 1759e07bdf8SAnthony Liguori static int smbus_i2c_send(I2CSlave *s, uint8_t data) 1760ff596d0Spbrook { 177b5ea9327SAnthony Liguori SMBusDevice *dev = SMBUS_DEVICE(s); 1781ea96673SPaul Brook 1790ff596d0Spbrook switch (dev->mode) { 1800ff596d0Spbrook case SMBUS_WRITE_DATA: 1810ff596d0Spbrook DPRINTF("Write data %02x\n", data); 182629457a1SCorey Minyard if (dev->data_len >= sizeof(dev->data_buf)) { 183629457a1SCorey Minyard BADF("Too many bytes sent\n"); 184629457a1SCorey Minyard } else { 1850ff596d0Spbrook dev->data_buf[dev->data_len++] = data; 186629457a1SCorey Minyard } 1870ff596d0Spbrook break; 1888b38e532SCorey Minyard 1890ff596d0Spbrook default: 1900ff596d0Spbrook BADF("Unexpected write in state %d\n", dev->mode); 1910ff596d0Spbrook break; 1920ff596d0Spbrook } 1938b38e532SCorey Minyard 1940ff596d0Spbrook return 0; 1950ff596d0Spbrook } 1960ff596d0Spbrook 197b5ea9327SAnthony Liguori static void smbus_device_class_init(ObjectClass *klass, void *data) 198b5ea9327SAnthony Liguori { 199b5ea9327SAnthony Liguori I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); 200b5ea9327SAnthony Liguori 201b5ea9327SAnthony Liguori sc->event = smbus_i2c_event; 202b5ea9327SAnthony Liguori sc->recv = smbus_i2c_recv; 203b5ea9327SAnthony Liguori sc->send = smbus_i2c_send; 204b5ea9327SAnthony Liguori } 205b5ea9327SAnthony Liguori 206547db24aSCorey Minyard bool smbus_vmstate_needed(SMBusDevice *dev) 207547db24aSCorey Minyard { 208547db24aSCorey Minyard return dev->mode != SMBUS_IDLE; 209547db24aSCorey Minyard } 210547db24aSCorey Minyard 211547db24aSCorey Minyard const VMStateDescription vmstate_smbus_device = { 212547db24aSCorey Minyard .name = TYPE_SMBUS_DEVICE, 213547db24aSCorey Minyard .version_id = 1, 214547db24aSCorey Minyard .minimum_version_id = 1, 215547db24aSCorey Minyard .fields = (VMStateField[]) { 216547db24aSCorey Minyard VMSTATE_I2C_SLAVE(i2c, SMBusDevice), 217547db24aSCorey Minyard VMSTATE_INT32(mode, SMBusDevice), 218547db24aSCorey Minyard VMSTATE_INT32(data_len, SMBusDevice), 219547db24aSCorey Minyard VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN), 220547db24aSCorey Minyard VMSTATE_END_OF_LIST() 221547db24aSCorey Minyard } 222547db24aSCorey Minyard }; 223547db24aSCorey Minyard 2248c43a6f0SAndreas Färber static const TypeInfo smbus_device_type_info = { 225b5ea9327SAnthony Liguori .name = TYPE_SMBUS_DEVICE, 226b5ea9327SAnthony Liguori .parent = TYPE_I2C_SLAVE, 227b5ea9327SAnthony Liguori .instance_size = sizeof(SMBusDevice), 228b5ea9327SAnthony Liguori .abstract = true, 229b5ea9327SAnthony Liguori .class_size = sizeof(SMBusDeviceClass), 230b5ea9327SAnthony Liguori .class_init = smbus_device_class_init, 231b5ea9327SAnthony Liguori }; 232b5ea9327SAnthony Liguori 23383f7d43aSAndreas Färber static void smbus_device_register_types(void) 234b5ea9327SAnthony Liguori { 235b5ea9327SAnthony Liguori type_register_static(&smbus_device_type_info); 236b5ea9327SAnthony Liguori } 237b5ea9327SAnthony Liguori 23883f7d43aSAndreas Färber type_init(smbus_device_register_types) 239