Annotation of qemu/hw/bitbang_i2c.c, revision 1.1.1.4

1.1       root        1: /*
                      2:  * Bit-Bang i2c emulation extracted from
                      3:  * Marvell MV88W8618 / Freecom MusicPal emulation.
                      4:  *
                      5:  * Copyright (c) 2008 Jan Kiszka
                      6:  *
1.1.1.2   root        7:  * This code is licensed under the GNU GPL v2.
1.1.1.4 ! root        8:  *
        !             9:  * Contributions after 2012-01-13 are licensed under the terms of the
        !            10:  * GNU GPL, version 2 or (at your option) any later version.
1.1       root       11:  */
                     12: #include "hw.h"
                     13: #include "bitbang_i2c.h"
                     14: #include "sysbus.h"
                     15: 
                     16: //#define DEBUG_BITBANG_I2C
                     17: 
                     18: #ifdef DEBUG_BITBANG_I2C
                     19: #define DPRINTF(fmt, ...) \
                     20: do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0)
                     21: #else
                     22: #define DPRINTF(fmt, ...) do {} while(0)
                     23: #endif
                     24: 
                     25: typedef enum bitbang_i2c_state {
                     26:     STOPPED = 0,
                     27:     SENDING_BIT7,
                     28:     SENDING_BIT6,
                     29:     SENDING_BIT5,
                     30:     SENDING_BIT4,
                     31:     SENDING_BIT3,
                     32:     SENDING_BIT2,
                     33:     SENDING_BIT1,
                     34:     SENDING_BIT0,
                     35:     WAITING_FOR_ACK,
                     36:     RECEIVING_BIT7,
                     37:     RECEIVING_BIT6,
                     38:     RECEIVING_BIT5,
                     39:     RECEIVING_BIT4,
                     40:     RECEIVING_BIT3,
                     41:     RECEIVING_BIT2,
                     42:     RECEIVING_BIT1,
                     43:     RECEIVING_BIT0,
1.1.1.2   root       44:     SENDING_ACK,
                     45:     SENT_NACK
1.1       root       46: } bitbang_i2c_state;
                     47: 
                     48: struct bitbang_i2c_interface {
                     49:     i2c_bus *bus;
                     50:     bitbang_i2c_state state;
                     51:     int last_data;
                     52:     int last_clock;
                     53:     int device_out;
                     54:     uint8_t buffer;
                     55:     int current_addr;
                     56: };
                     57: 
                     58: static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c)
                     59: {
                     60:     DPRINTF("STOP\n");
                     61:     if (i2c->current_addr >= 0)
                     62:         i2c_end_transfer(i2c->bus);
                     63:     i2c->current_addr = -1;
                     64:     i2c->state = STOPPED;
                     65: }
                     66: 
                     67: /* Set device data pin.  */
                     68: static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level)
                     69: {
                     70:     i2c->device_out = level;
                     71:     //DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out);
                     72:     return level & i2c->last_data;
                     73: }
                     74: 
                     75: /* Leave device data pin unodified.  */
                     76: static int bitbang_i2c_nop(bitbang_i2c_interface *i2c)
                     77: {
                     78:     return bitbang_i2c_ret(i2c, i2c->device_out);
                     79: }
                     80: 
                     81: /* Returns data line level.  */
                     82: int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
                     83: {
                     84:     int data;
                     85: 
                     86:     if (level != 0 && level != 1) {
                     87:         abort();
                     88:     }
                     89: 
                     90:     if (line == BITBANG_I2C_SDA) {
                     91:         if (level == i2c->last_data) {
                     92:             return bitbang_i2c_nop(i2c);
                     93:         }
                     94:         i2c->last_data = level;
                     95:         if (i2c->last_clock == 0) {
                     96:             return bitbang_i2c_nop(i2c);
                     97:         }
                     98:         if (level == 0) {
                     99:             DPRINTF("START\n");
                    100:             /* START condition.  */
                    101:             i2c->state = SENDING_BIT7;
                    102:             i2c->current_addr = -1;
                    103:         } else {
                    104:             /* STOP condition.  */
                    105:             bitbang_i2c_enter_stop(i2c);
                    106:         }
                    107:         return bitbang_i2c_ret(i2c, 1);
                    108:     }
                    109: 
                    110:     data = i2c->last_data;
                    111:     if (i2c->last_clock == level) {
                    112:         return bitbang_i2c_nop(i2c);
                    113:     }
                    114:     i2c->last_clock = level;
                    115:     if (level == 0) {
                    116:         /* State is set/read at the start of the clock pulse.
                    117:            release the data line at the end.  */
                    118:         return bitbang_i2c_ret(i2c, 1);
                    119:     }
                    120:     switch (i2c->state) {
                    121:     case STOPPED:
1.1.1.2   root      122:     case SENT_NACK:
1.1       root      123:         return bitbang_i2c_ret(i2c, 1);
                    124: 
                    125:     case SENDING_BIT7 ... SENDING_BIT0:
                    126:         i2c->buffer = (i2c->buffer << 1) | data;
                    127:         /* will end up in WAITING_FOR_ACK */
                    128:         i2c->state++; 
                    129:         return bitbang_i2c_ret(i2c, 1);
                    130: 
                    131:     case WAITING_FOR_ACK:
                    132:         if (i2c->current_addr < 0) {
                    133:             i2c->current_addr = i2c->buffer;
                    134:             DPRINTF("Address 0x%02x\n", i2c->current_addr);
                    135:             i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
                    136:                                i2c->current_addr & 1);
                    137:         } else {
                    138:             DPRINTF("Sent 0x%02x\n", i2c->buffer);
                    139:             i2c_send(i2c->bus, i2c->buffer);
                    140:         }
                    141:         if (i2c->current_addr & 1) {
                    142:             i2c->state = RECEIVING_BIT7;
                    143:         } else {
                    144:             i2c->state = SENDING_BIT7;
                    145:         }
                    146:         return bitbang_i2c_ret(i2c, 0);
                    147: 
                    148:     case RECEIVING_BIT7:
                    149:         i2c->buffer = i2c_recv(i2c->bus);
                    150:         DPRINTF("RX byte 0x%02x\n", i2c->buffer);
                    151:         /* Fall through... */
                    152:     case RECEIVING_BIT6 ... RECEIVING_BIT0:
                    153:         data = i2c->buffer >> 7;
                    154:         /* will end up in SENDING_ACK */
                    155:         i2c->state++;
                    156:         i2c->buffer <<= 1;
                    157:         return bitbang_i2c_ret(i2c, data);
                    158: 
                    159:     case SENDING_ACK:
                    160:         i2c->state = RECEIVING_BIT7;
                    161:         if (data != 0) {
                    162:             DPRINTF("NACKED\n");
1.1.1.2   root      163:             i2c->state = SENT_NACK;
1.1       root      164:             i2c_nack(i2c->bus);
                    165:         } else {
                    166:             DPRINTF("ACKED\n");
                    167:         }
                    168:         return bitbang_i2c_ret(i2c, 1);
                    169:     }
                    170:     abort();
                    171: }
                    172: 
                    173: bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus)
                    174: {
                    175:     bitbang_i2c_interface *s;
                    176: 
1.1.1.3   root      177:     s = g_malloc0(sizeof(bitbang_i2c_interface));
1.1       root      178: 
                    179:     s->bus = bus;
                    180:     s->last_data = 1;
                    181:     s->last_clock = 1;
                    182:     s->device_out = 1;
                    183: 
                    184:     return s;
                    185: }
                    186: 
                    187: /* GPIO interface.  */
                    188: typedef struct {
                    189:     SysBusDevice busdev;
1.1.1.4 ! root      190:     MemoryRegion dummy_iomem;
1.1       root      191:     bitbang_i2c_interface *bitbang;
                    192:     int last_level;
                    193:     qemu_irq out;
                    194: } GPIOI2CState;
                    195: 
                    196: static void bitbang_i2c_gpio_set(void *opaque, int irq, int level)
                    197: {
                    198:     GPIOI2CState *s = opaque;
                    199: 
                    200:     level = bitbang_i2c_set(s->bitbang, irq, level);
                    201:     if (level != s->last_level) {
                    202:         s->last_level = level;
                    203:         qemu_set_irq(s->out, level);
                    204:     }
                    205: }
                    206: 
                    207: static int gpio_i2c_init(SysBusDevice *dev)
                    208: {
                    209:     GPIOI2CState *s = FROM_SYSBUS(GPIOI2CState, dev);
                    210:     i2c_bus *bus;
                    211: 
1.1.1.4 ! root      212:     memory_region_init(&s->dummy_iomem, "gpio_i2c", 0);
        !           213:     sysbus_init_mmio(dev, &s->dummy_iomem);
1.1       root      214: 
                    215:     bus = i2c_init_bus(&dev->qdev, "i2c");
                    216:     s->bitbang = bitbang_i2c_init(bus);
                    217: 
                    218:     qdev_init_gpio_in(&dev->qdev, bitbang_i2c_gpio_set, 2);
                    219:     qdev_init_gpio_out(&dev->qdev, &s->out, 1);
                    220: 
                    221:     return 0;
                    222: }
                    223: 
1.1.1.4 ! root      224: static void gpio_i2c_class_init(ObjectClass *klass, void *data)
        !           225: {
        !           226:     DeviceClass *dc = DEVICE_CLASS(klass);
        !           227:     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
        !           228: 
        !           229:     k->init = gpio_i2c_init;
        !           230:     dc->desc = "Virtual GPIO to I2C bridge";
        !           231: }
        !           232: 
        !           233: static TypeInfo gpio_i2c_info = {
        !           234:     .name          = "gpio_i2c",
        !           235:     .parent        = TYPE_SYS_BUS_DEVICE,
        !           236:     .instance_size = sizeof(GPIOI2CState),
        !           237:     .class_init    = gpio_i2c_class_init,
1.1       root      238: };
                    239: 
1.1.1.4 ! root      240: static void bitbang_i2c_register_types(void)
1.1       root      241: {
1.1.1.4 ! root      242:     type_register_static(&gpio_i2c_info);
1.1       root      243: }
                    244: 
1.1.1.4 ! root      245: type_init(bitbang_i2c_register_types)

unix.superglobalmegacorp.com