xref: /openbmc/qemu/hw/i2c/smbus_slave.c (revision 8fa21b80)
193198b6cSCorey Minyard /*
293198b6cSCorey Minyard  * QEMU SMBus device emulation.
393198b6cSCorey Minyard  *
493198b6cSCorey Minyard  * This code is a helper for SMBus device emulation.  It implements an
5*8fa21b80SMichael Tokarev  * I2C device interface and runs the SMBus protocol from the device
693198b6cSCorey Minyard  * point of view and maps those to simple calls to emulate.
793198b6cSCorey Minyard  *
893198b6cSCorey Minyard  * Copyright (c) 2007 CodeSourcery.
993198b6cSCorey Minyard  * Written by Paul Brook
1093198b6cSCorey Minyard  *
1193198b6cSCorey Minyard  * This code is licensed under the LGPL.
1293198b6cSCorey Minyard  */
1393198b6cSCorey Minyard 
1493198b6cSCorey Minyard /* TODO: Implement PEC.  */
1593198b6cSCorey Minyard 
1693198b6cSCorey Minyard #include "qemu/osdep.h"
1793198b6cSCorey Minyard #include "hw/i2c/i2c.h"
1893198b6cSCorey Minyard #include "hw/i2c/smbus_slave.h"
19d6454270SMarkus Armbruster #include "migration/vmstate.h"
200b8fa32fSMarkus Armbruster #include "qemu/module.h"
2193198b6cSCorey Minyard 
2293198b6cSCorey Minyard //#define DEBUG_SMBUS 1
2393198b6cSCorey Minyard 
2493198b6cSCorey Minyard #ifdef DEBUG_SMBUS
2593198b6cSCorey Minyard #define DPRINTF(fmt, ...) \
2693198b6cSCorey Minyard do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0)
2793198b6cSCorey Minyard #define BADF(fmt, ...) \
2893198b6cSCorey Minyard do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
2993198b6cSCorey Minyard #else
3093198b6cSCorey Minyard #define DPRINTF(fmt, ...) do {} while(0)
3193198b6cSCorey Minyard #define BADF(fmt, ...) \
3293198b6cSCorey Minyard do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0)
3393198b6cSCorey Minyard #endif
3493198b6cSCorey Minyard 
3593198b6cSCorey Minyard enum {
3693198b6cSCorey Minyard     SMBUS_IDLE,
3793198b6cSCorey Minyard     SMBUS_WRITE_DATA,
3893198b6cSCorey Minyard     SMBUS_READ_DATA,
3993198b6cSCorey Minyard     SMBUS_DONE,
4093198b6cSCorey Minyard     SMBUS_CONFUSED = -1
4193198b6cSCorey Minyard };
4293198b6cSCorey Minyard 
smbus_do_quick_cmd(SMBusDevice * dev,int recv)4393198b6cSCorey Minyard static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
4493198b6cSCorey Minyard {
4593198b6cSCorey Minyard     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
4693198b6cSCorey Minyard 
4793198b6cSCorey Minyard     DPRINTF("Quick Command %d\n", recv);
4893198b6cSCorey Minyard     if (sc->quick_cmd) {
4993198b6cSCorey Minyard         sc->quick_cmd(dev, recv);
5093198b6cSCorey Minyard     }
5193198b6cSCorey Minyard }
5293198b6cSCorey Minyard 
smbus_do_write(SMBusDevice * dev)5393198b6cSCorey Minyard static void smbus_do_write(SMBusDevice *dev)
5493198b6cSCorey Minyard {
5593198b6cSCorey Minyard     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
5693198b6cSCorey Minyard 
579cf27d74SCorey Minyard     DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len);
5893198b6cSCorey Minyard     if (sc->write_data) {
599cf27d74SCorey Minyard         sc->write_data(dev, dev->data_buf, dev->data_len);
6093198b6cSCorey Minyard     }
6193198b6cSCorey Minyard }
6293198b6cSCorey Minyard 
smbus_i2c_event(I2CSlave * s,enum i2c_event event)6393198b6cSCorey Minyard static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
6493198b6cSCorey Minyard {
6593198b6cSCorey Minyard     SMBusDevice *dev = SMBUS_DEVICE(s);
6693198b6cSCorey Minyard 
6793198b6cSCorey Minyard     switch (event) {
6893198b6cSCorey Minyard     case I2C_START_SEND:
6993198b6cSCorey Minyard         switch (dev->mode) {
7093198b6cSCorey Minyard         case SMBUS_IDLE:
7193198b6cSCorey Minyard             DPRINTF("Incoming data\n");
7293198b6cSCorey Minyard             dev->mode = SMBUS_WRITE_DATA;
7393198b6cSCorey Minyard             break;
748b38e532SCorey Minyard 
7593198b6cSCorey Minyard         default:
7693198b6cSCorey Minyard             BADF("Unexpected send start condition in state %d\n", dev->mode);
7793198b6cSCorey Minyard             dev->mode = SMBUS_CONFUSED;
7893198b6cSCorey Minyard             break;
7993198b6cSCorey Minyard         }
8093198b6cSCorey Minyard         break;
8193198b6cSCorey Minyard 
8293198b6cSCorey Minyard     case I2C_START_RECV:
8393198b6cSCorey Minyard         switch (dev->mode) {
8493198b6cSCorey Minyard         case SMBUS_IDLE:
8593198b6cSCorey Minyard             DPRINTF("Read mode\n");
86031ac498SCorey Minyard             dev->mode = SMBUS_READ_DATA;
8793198b6cSCorey Minyard             break;
888b38e532SCorey Minyard 
8993198b6cSCorey Minyard         case SMBUS_WRITE_DATA:
9093198b6cSCorey Minyard             if (dev->data_len == 0) {
9193198b6cSCorey Minyard                 BADF("Read after write with no data\n");
9293198b6cSCorey Minyard                 dev->mode = SMBUS_CONFUSED;
9393198b6cSCorey Minyard             } else {
9493198b6cSCorey Minyard                 smbus_do_write(dev);
9593198b6cSCorey Minyard                 DPRINTF("Read mode\n");
9693198b6cSCorey Minyard                 dev->mode = SMBUS_READ_DATA;
9793198b6cSCorey Minyard             }
9893198b6cSCorey Minyard             break;
998b38e532SCorey Minyard 
10093198b6cSCorey Minyard         default:
10193198b6cSCorey Minyard             BADF("Unexpected recv start condition in state %d\n", dev->mode);
10293198b6cSCorey Minyard             dev->mode = SMBUS_CONFUSED;
10393198b6cSCorey Minyard             break;
10493198b6cSCorey Minyard         }
10593198b6cSCorey Minyard         break;
10693198b6cSCorey Minyard 
10793198b6cSCorey Minyard     case I2C_FINISH:
108905cec6dSCorey Minyard         if (dev->data_len == 0) {
109905cec6dSCorey Minyard             if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) {
110905cec6dSCorey Minyard                 smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA);
111905cec6dSCorey Minyard             }
112905cec6dSCorey Minyard         } else {
11393198b6cSCorey Minyard             switch (dev->mode) {
11493198b6cSCorey Minyard             case SMBUS_WRITE_DATA:
11593198b6cSCorey Minyard                 smbus_do_write(dev);
11693198b6cSCorey Minyard                 break;
117905cec6dSCorey Minyard 
11893198b6cSCorey Minyard             case SMBUS_READ_DATA:
11993198b6cSCorey Minyard                 BADF("Unexpected stop during receive\n");
12093198b6cSCorey Minyard                 break;
121905cec6dSCorey Minyard 
12293198b6cSCorey Minyard             default:
12393198b6cSCorey Minyard                 /* Nothing to do.  */
12493198b6cSCorey Minyard                 break;
12593198b6cSCorey Minyard             }
126905cec6dSCorey Minyard         }
12793198b6cSCorey Minyard         dev->mode = SMBUS_IDLE;
12893198b6cSCorey Minyard         dev->data_len = 0;
12993198b6cSCorey Minyard         break;
13093198b6cSCorey Minyard 
13193198b6cSCorey Minyard     case I2C_NACK:
13293198b6cSCorey Minyard         switch (dev->mode) {
13393198b6cSCorey Minyard         case SMBUS_DONE:
13493198b6cSCorey Minyard             /* Nothing to do.  */
13593198b6cSCorey Minyard             break;
1368b38e532SCorey Minyard 
13793198b6cSCorey Minyard         case SMBUS_READ_DATA:
13893198b6cSCorey Minyard             dev->mode = SMBUS_DONE;
13993198b6cSCorey Minyard             break;
1408b38e532SCorey Minyard 
14193198b6cSCorey Minyard         default:
14293198b6cSCorey Minyard             BADF("Unexpected NACK in state %d\n", dev->mode);
14393198b6cSCorey Minyard             dev->mode = SMBUS_CONFUSED;
14493198b6cSCorey Minyard             break;
14593198b6cSCorey Minyard         }
146a78e9839SKlaus Jensen         break;
147a78e9839SKlaus Jensen 
148a78e9839SKlaus Jensen     default:
149a78e9839SKlaus Jensen         return -1;
15093198b6cSCorey Minyard     }
15193198b6cSCorey Minyard 
15293198b6cSCorey Minyard     return 0;
15393198b6cSCorey Minyard }
15493198b6cSCorey Minyard 
smbus_i2c_recv(I2CSlave * s)1552ac4c5f4SCorey Minyard static uint8_t smbus_i2c_recv(I2CSlave *s)
15693198b6cSCorey Minyard {
15793198b6cSCorey Minyard     SMBusDevice *dev = SMBUS_DEVICE(s);
15893198b6cSCorey Minyard     SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
159031ac498SCorey Minyard     uint8_t ret = 0xff;
16093198b6cSCorey Minyard 
16193198b6cSCorey Minyard     switch (dev->mode) {
162031ac498SCorey Minyard     case SMBUS_READ_DATA:
16393198b6cSCorey Minyard         if (sc->receive_byte) {
16493198b6cSCorey Minyard             ret = sc->receive_byte(dev);
16593198b6cSCorey Minyard         }
16693198b6cSCorey Minyard         DPRINTF("Read data %02x\n", ret);
16793198b6cSCorey Minyard         break;
1688b38e532SCorey Minyard 
16993198b6cSCorey Minyard     default:
17093198b6cSCorey Minyard         BADF("Unexpected read in state %d\n", dev->mode);
17193198b6cSCorey Minyard         dev->mode = SMBUS_CONFUSED;
17293198b6cSCorey Minyard         break;
17393198b6cSCorey Minyard     }
1748b38e532SCorey Minyard 
17593198b6cSCorey Minyard     return ret;
17693198b6cSCorey Minyard }
17793198b6cSCorey Minyard 
smbus_i2c_send(I2CSlave * s,uint8_t data)17893198b6cSCorey Minyard static int smbus_i2c_send(I2CSlave *s, uint8_t data)
17993198b6cSCorey Minyard {
18093198b6cSCorey Minyard     SMBusDevice *dev = SMBUS_DEVICE(s);
18193198b6cSCorey Minyard 
18293198b6cSCorey Minyard     switch (dev->mode) {
18393198b6cSCorey Minyard     case SMBUS_WRITE_DATA:
18493198b6cSCorey Minyard         DPRINTF("Write data %02x\n", data);
18593198b6cSCorey Minyard         if (dev->data_len >= sizeof(dev->data_buf)) {
18693198b6cSCorey Minyard             BADF("Too many bytes sent\n");
18793198b6cSCorey Minyard         } else {
18893198b6cSCorey Minyard             dev->data_buf[dev->data_len++] = data;
18993198b6cSCorey Minyard         }
19093198b6cSCorey Minyard         break;
1918b38e532SCorey Minyard 
19293198b6cSCorey Minyard     default:
19393198b6cSCorey Minyard         BADF("Unexpected write in state %d\n", dev->mode);
19493198b6cSCorey Minyard         break;
19593198b6cSCorey Minyard     }
1968b38e532SCorey Minyard 
19793198b6cSCorey Minyard     return 0;
19893198b6cSCorey Minyard }
19993198b6cSCorey Minyard 
smbus_device_class_init(ObjectClass * klass,void * data)20093198b6cSCorey Minyard static void smbus_device_class_init(ObjectClass *klass, void *data)
20193198b6cSCorey Minyard {
20293198b6cSCorey Minyard     I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
20393198b6cSCorey Minyard 
20493198b6cSCorey Minyard     sc->event = smbus_i2c_event;
20593198b6cSCorey Minyard     sc->recv = smbus_i2c_recv;
20693198b6cSCorey Minyard     sc->send = smbus_i2c_send;
20793198b6cSCorey Minyard }
20893198b6cSCorey Minyard 
smbus_vmstate_needed(SMBusDevice * dev)209547db24aSCorey Minyard bool smbus_vmstate_needed(SMBusDevice *dev)
210547db24aSCorey Minyard {
211547db24aSCorey Minyard     return dev->mode != SMBUS_IDLE;
212547db24aSCorey Minyard }
213547db24aSCorey Minyard 
214547db24aSCorey Minyard const VMStateDescription vmstate_smbus_device = {
215547db24aSCorey Minyard     .name = TYPE_SMBUS_DEVICE,
216547db24aSCorey Minyard     .version_id = 1,
217547db24aSCorey Minyard     .minimum_version_id = 1,
218547db24aSCorey Minyard     .fields      = (VMStateField[]) {
219547db24aSCorey Minyard         VMSTATE_I2C_SLAVE(i2c, SMBusDevice),
220547db24aSCorey Minyard         VMSTATE_INT32(mode, SMBusDevice),
221547db24aSCorey Minyard         VMSTATE_INT32(data_len, SMBusDevice),
222547db24aSCorey Minyard         VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN),
223547db24aSCorey Minyard         VMSTATE_END_OF_LIST()
224547db24aSCorey Minyard     }
225547db24aSCorey Minyard };
226547db24aSCorey Minyard 
22793198b6cSCorey Minyard static const TypeInfo smbus_device_type_info = {
22893198b6cSCorey Minyard     .name = TYPE_SMBUS_DEVICE,
22993198b6cSCorey Minyard     .parent = TYPE_I2C_SLAVE,
23093198b6cSCorey Minyard     .instance_size = sizeof(SMBusDevice),
23193198b6cSCorey Minyard     .abstract = true,
23293198b6cSCorey Minyard     .class_size = sizeof(SMBusDeviceClass),
23393198b6cSCorey Minyard     .class_init = smbus_device_class_init,
23493198b6cSCorey Minyard };
23593198b6cSCorey Minyard 
smbus_device_register_types(void)23693198b6cSCorey Minyard static void smbus_device_register_types(void)
23793198b6cSCorey Minyard {
23893198b6cSCorey Minyard     type_register_static(&smbus_device_type_info);
23993198b6cSCorey Minyard }
24093198b6cSCorey Minyard 
24193198b6cSCorey Minyard type_init(smbus_device_register_types)
242