193198b6cSCorey Minyard /*
293198b6cSCorey Minyard * QEMU SMBus device emulation.
393198b6cSCorey Minyard *
493198b6cSCorey Minyard * This code is a helper for SMBus device emulation. It implements an
58fa21b80SMichael 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, ...) \
28*fcc8299eSJoe Komlodi do { g_autofree char *qom_path = object_get_canonical_path(OBJECT(dev)); \
29*fcc8299eSJoe Komlodi fprintf(stderr, "%s: smbus: error: " fmt , qom_path, ## __VA_ARGS__); \
30*fcc8299eSJoe Komlodi exit(1); } while (0)
3193198b6cSCorey Minyard #else
3293198b6cSCorey Minyard #define DPRINTF(fmt, ...) do {} while(0)
3393198b6cSCorey Minyard #define BADF(fmt, ...) \
34*fcc8299eSJoe Komlodi do { g_autofree char *qom_path = object_get_canonical_path(OBJECT(dev)); \
35*fcc8299eSJoe Komlodi fprintf(stderr, "%s: smbus: error: " fmt , qom_path, ## __VA_ARGS__); \
36*fcc8299eSJoe Komlodi } while (0)
3793198b6cSCorey Minyard #endif
3893198b6cSCorey Minyard
3993198b6cSCorey Minyard enum {
4093198b6cSCorey Minyard SMBUS_IDLE,
4193198b6cSCorey Minyard SMBUS_WRITE_DATA,
4293198b6cSCorey Minyard SMBUS_READ_DATA,
4393198b6cSCorey Minyard SMBUS_DONE,
4493198b6cSCorey Minyard SMBUS_CONFUSED = -1
4593198b6cSCorey Minyard };
4693198b6cSCorey Minyard
smbus_do_quick_cmd(SMBusDevice * dev,int recv)4793198b6cSCorey Minyard static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
4893198b6cSCorey Minyard {
4993198b6cSCorey Minyard SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
5093198b6cSCorey Minyard
5193198b6cSCorey Minyard DPRINTF("Quick Command %d\n", recv);
5293198b6cSCorey Minyard if (sc->quick_cmd) {
5393198b6cSCorey Minyard sc->quick_cmd(dev, recv);
5493198b6cSCorey Minyard }
5593198b6cSCorey Minyard }
5693198b6cSCorey Minyard
smbus_do_write(SMBusDevice * dev)5793198b6cSCorey Minyard static void smbus_do_write(SMBusDevice *dev)
5893198b6cSCorey Minyard {
5993198b6cSCorey Minyard SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
6093198b6cSCorey Minyard
619cf27d74SCorey Minyard DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len);
6293198b6cSCorey Minyard if (sc->write_data) {
639cf27d74SCorey Minyard sc->write_data(dev, dev->data_buf, dev->data_len);
6493198b6cSCorey Minyard }
6593198b6cSCorey Minyard }
6693198b6cSCorey Minyard
smbus_i2c_event(I2CSlave * s,enum i2c_event event)6793198b6cSCorey Minyard static int smbus_i2c_event(I2CSlave *s, enum i2c_event event)
6893198b6cSCorey Minyard {
6993198b6cSCorey Minyard SMBusDevice *dev = SMBUS_DEVICE(s);
7093198b6cSCorey Minyard
7193198b6cSCorey Minyard switch (event) {
7293198b6cSCorey Minyard case I2C_START_SEND:
7393198b6cSCorey Minyard switch (dev->mode) {
7493198b6cSCorey Minyard case SMBUS_IDLE:
7593198b6cSCorey Minyard DPRINTF("Incoming data\n");
7693198b6cSCorey Minyard dev->mode = SMBUS_WRITE_DATA;
7793198b6cSCorey Minyard break;
788b38e532SCorey Minyard
7993198b6cSCorey Minyard default:
8093198b6cSCorey Minyard BADF("Unexpected send start condition in state %d\n", dev->mode);
8193198b6cSCorey Minyard dev->mode = SMBUS_CONFUSED;
8293198b6cSCorey Minyard break;
8393198b6cSCorey Minyard }
8493198b6cSCorey Minyard break;
8593198b6cSCorey Minyard
8693198b6cSCorey Minyard case I2C_START_RECV:
8793198b6cSCorey Minyard switch (dev->mode) {
8893198b6cSCorey Minyard case SMBUS_IDLE:
8993198b6cSCorey Minyard DPRINTF("Read mode\n");
90031ac498SCorey Minyard dev->mode = SMBUS_READ_DATA;
9193198b6cSCorey Minyard break;
928b38e532SCorey Minyard
9393198b6cSCorey Minyard case SMBUS_WRITE_DATA:
9493198b6cSCorey Minyard if (dev->data_len == 0) {
9593198b6cSCorey Minyard BADF("Read after write with no data\n");
9693198b6cSCorey Minyard dev->mode = SMBUS_CONFUSED;
9793198b6cSCorey Minyard } else {
9893198b6cSCorey Minyard smbus_do_write(dev);
9993198b6cSCorey Minyard DPRINTF("Read mode\n");
10093198b6cSCorey Minyard dev->mode = SMBUS_READ_DATA;
10193198b6cSCorey Minyard }
10293198b6cSCorey Minyard break;
1038b38e532SCorey Minyard
10493198b6cSCorey Minyard default:
10593198b6cSCorey Minyard BADF("Unexpected recv start condition in state %d\n", dev->mode);
10693198b6cSCorey Minyard dev->mode = SMBUS_CONFUSED;
10793198b6cSCorey Minyard break;
10893198b6cSCorey Minyard }
10993198b6cSCorey Minyard break;
11093198b6cSCorey Minyard
11193198b6cSCorey Minyard case I2C_FINISH:
112905cec6dSCorey Minyard if (dev->data_len == 0) {
113905cec6dSCorey Minyard if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) {
114905cec6dSCorey Minyard smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA);
115905cec6dSCorey Minyard }
116905cec6dSCorey Minyard } else {
11793198b6cSCorey Minyard switch (dev->mode) {
11893198b6cSCorey Minyard case SMBUS_WRITE_DATA:
11993198b6cSCorey Minyard smbus_do_write(dev);
12093198b6cSCorey Minyard break;
121905cec6dSCorey Minyard
12293198b6cSCorey Minyard case SMBUS_READ_DATA:
12393198b6cSCorey Minyard BADF("Unexpected stop during receive\n");
12493198b6cSCorey Minyard break;
125905cec6dSCorey Minyard
12693198b6cSCorey Minyard default:
12793198b6cSCorey Minyard /* Nothing to do. */
12893198b6cSCorey Minyard break;
12993198b6cSCorey Minyard }
130905cec6dSCorey Minyard }
13193198b6cSCorey Minyard dev->mode = SMBUS_IDLE;
13293198b6cSCorey Minyard dev->data_len = 0;
13393198b6cSCorey Minyard break;
13493198b6cSCorey Minyard
13593198b6cSCorey Minyard case I2C_NACK:
13693198b6cSCorey Minyard switch (dev->mode) {
13793198b6cSCorey Minyard case SMBUS_DONE:
13893198b6cSCorey Minyard /* Nothing to do. */
13993198b6cSCorey Minyard break;
1408b38e532SCorey Minyard
14193198b6cSCorey Minyard case SMBUS_READ_DATA:
14293198b6cSCorey Minyard dev->mode = SMBUS_DONE;
14393198b6cSCorey Minyard break;
1448b38e532SCorey Minyard
14593198b6cSCorey Minyard default:
14693198b6cSCorey Minyard BADF("Unexpected NACK in state %d\n", dev->mode);
14793198b6cSCorey Minyard dev->mode = SMBUS_CONFUSED;
14893198b6cSCorey Minyard break;
14993198b6cSCorey Minyard }
150a78e9839SKlaus Jensen break;
151a78e9839SKlaus Jensen
152a78e9839SKlaus Jensen default:
153a78e9839SKlaus Jensen return -1;
15493198b6cSCorey Minyard }
15593198b6cSCorey Minyard
15693198b6cSCorey Minyard return 0;
15793198b6cSCorey Minyard }
15893198b6cSCorey Minyard
smbus_i2c_recv(I2CSlave * s)1592ac4c5f4SCorey Minyard static uint8_t smbus_i2c_recv(I2CSlave *s)
16093198b6cSCorey Minyard {
16193198b6cSCorey Minyard SMBusDevice *dev = SMBUS_DEVICE(s);
16293198b6cSCorey Minyard SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
163031ac498SCorey Minyard uint8_t ret = 0xff;
16493198b6cSCorey Minyard
16593198b6cSCorey Minyard switch (dev->mode) {
166031ac498SCorey Minyard case SMBUS_READ_DATA:
16793198b6cSCorey Minyard if (sc->receive_byte) {
16893198b6cSCorey Minyard ret = sc->receive_byte(dev);
16993198b6cSCorey Minyard }
17093198b6cSCorey Minyard DPRINTF("Read data %02x\n", ret);
17193198b6cSCorey Minyard break;
1728b38e532SCorey Minyard
17393198b6cSCorey Minyard default:
17493198b6cSCorey Minyard BADF("Unexpected read in state %d\n", dev->mode);
17593198b6cSCorey Minyard dev->mode = SMBUS_CONFUSED;
17693198b6cSCorey Minyard break;
17793198b6cSCorey Minyard }
1788b38e532SCorey Minyard
17993198b6cSCorey Minyard return ret;
18093198b6cSCorey Minyard }
18193198b6cSCorey Minyard
smbus_i2c_send(I2CSlave * s,uint8_t data)18293198b6cSCorey Minyard static int smbus_i2c_send(I2CSlave *s, uint8_t data)
18393198b6cSCorey Minyard {
18493198b6cSCorey Minyard SMBusDevice *dev = SMBUS_DEVICE(s);
18593198b6cSCorey Minyard
18693198b6cSCorey Minyard switch (dev->mode) {
18793198b6cSCorey Minyard case SMBUS_WRITE_DATA:
18893198b6cSCorey Minyard DPRINTF("Write data %02x\n", data);
18993198b6cSCorey Minyard if (dev->data_len >= sizeof(dev->data_buf)) {
19093198b6cSCorey Minyard BADF("Too many bytes sent\n");
19193198b6cSCorey Minyard } else {
19293198b6cSCorey Minyard dev->data_buf[dev->data_len++] = data;
19393198b6cSCorey Minyard }
19493198b6cSCorey Minyard break;
1958b38e532SCorey Minyard
19693198b6cSCorey Minyard default:
19793198b6cSCorey Minyard BADF("Unexpected write in state %d\n", dev->mode);
19893198b6cSCorey Minyard break;
19993198b6cSCorey Minyard }
2008b38e532SCorey Minyard
20193198b6cSCorey Minyard return 0;
20293198b6cSCorey Minyard }
20393198b6cSCorey Minyard
smbus_device_class_init(ObjectClass * klass,void * data)20493198b6cSCorey Minyard static void smbus_device_class_init(ObjectClass *klass, void *data)
20593198b6cSCorey Minyard {
20693198b6cSCorey Minyard I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
20793198b6cSCorey Minyard
20893198b6cSCorey Minyard sc->event = smbus_i2c_event;
20993198b6cSCorey Minyard sc->recv = smbus_i2c_recv;
21093198b6cSCorey Minyard sc->send = smbus_i2c_send;
21193198b6cSCorey Minyard }
21293198b6cSCorey Minyard
smbus_vmstate_needed(SMBusDevice * dev)213547db24aSCorey Minyard bool smbus_vmstate_needed(SMBusDevice *dev)
214547db24aSCorey Minyard {
215547db24aSCorey Minyard return dev->mode != SMBUS_IDLE;
216547db24aSCorey Minyard }
217547db24aSCorey Minyard
218547db24aSCorey Minyard const VMStateDescription vmstate_smbus_device = {
219547db24aSCorey Minyard .name = TYPE_SMBUS_DEVICE,
220547db24aSCorey Minyard .version_id = 1,
221547db24aSCorey Minyard .minimum_version_id = 1,
22201d9442aSRichard Henderson .fields = (const VMStateField[]) {
223547db24aSCorey Minyard VMSTATE_I2C_SLAVE(i2c, SMBusDevice),
224547db24aSCorey Minyard VMSTATE_INT32(mode, SMBusDevice),
225547db24aSCorey Minyard VMSTATE_INT32(data_len, SMBusDevice),
226547db24aSCorey Minyard VMSTATE_UINT8_ARRAY(data_buf, SMBusDevice, SMBUS_DATA_MAX_LEN),
227547db24aSCorey Minyard VMSTATE_END_OF_LIST()
228547db24aSCorey Minyard }
229547db24aSCorey Minyard };
230547db24aSCorey Minyard
23193198b6cSCorey Minyard static const TypeInfo smbus_device_type_info = {
23293198b6cSCorey Minyard .name = TYPE_SMBUS_DEVICE,
23393198b6cSCorey Minyard .parent = TYPE_I2C_SLAVE,
23493198b6cSCorey Minyard .instance_size = sizeof(SMBusDevice),
23593198b6cSCorey Minyard .abstract = true,
23693198b6cSCorey Minyard .class_size = sizeof(SMBusDeviceClass),
23793198b6cSCorey Minyard .class_init = smbus_device_class_init,
23893198b6cSCorey Minyard };
23993198b6cSCorey Minyard
smbus_device_register_types(void)24093198b6cSCorey Minyard static void smbus_device_register_types(void)
24193198b6cSCorey Minyard {
24293198b6cSCorey Minyard type_register_static(&smbus_device_type_info);
24393198b6cSCorey Minyard }
24493198b6cSCorey Minyard
24593198b6cSCorey Minyard type_init(smbus_device_register_types)
246