2 * Bit-Bang i2c emulation extracted from
3 * Marvell MV88W8618 / Freecom MusicPal emulation.
5 * Copyright (c) 2008 Jan Kiszka
7 * This code is licenced under the GNU GPL v2.
13 typedef enum bitbang_i2c_state {
36 typedef struct bitbang_i2c_interface {
39 bitbang_i2c_state state;
45 } bitbang_i2c_interface;
47 static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c)
49 if (i2c->current_addr >= 0)
50 i2c_end_transfer(i2c->bus);
51 i2c->current_addr = -1;
55 static void bitbang_i2c_gpio_set(void *opaque, int irq, int level)
57 bitbang_i2c_interface *i2c = opaque;
66 data = i2c->last_data;
67 clock = i2c->last_clock;
74 /* compute pins changes */
75 data_goes_up = data == 1 && i2c->last_data == 0;
76 data_goes_down = data == 0 && i2c->last_data == 1;
77 clock_goes_up = clock == 1 && i2c->last_clock == 0;
78 clock_goes_down = clock == 0 && i2c->last_clock == 1;
80 if (data_goes_up == 0 && data_goes_down == 0 &&
81 clock_goes_up == 0 && clock_goes_down == 0)
87 if ((RECEIVING_BIT7 > i2c->state && i2c->state > RECEIVING_BIT0)
88 || i2c->state == WAITING_FOR_ACK)
89 qemu_set_irq(i2c->out, 0);
93 if (data_goes_down && clock == 1)
94 i2c->state = INITIALIZING;
98 if (clock_goes_down && data == 0)
99 i2c->state = SENDING_BIT7;
101 bitbang_i2c_enter_stop(i2c);
104 case SENDING_BIT7 ... SENDING_BIT0:
105 if (clock_goes_down) {
106 i2c->buffer = (i2c->buffer << 1) | data;
107 /* will end up in WAITING_FOR_ACK */
109 } else if (data_goes_up && clock == 1)
110 bitbang_i2c_enter_stop(i2c);
113 case WAITING_FOR_ACK:
114 if (clock_goes_down) {
115 if (i2c->current_addr < 0) {
116 i2c->current_addr = i2c->buffer;
117 i2c_start_transfer(i2c->bus, (i2c->current_addr & 0xfe) / 2,
120 i2c_send(i2c->bus, i2c->buffer);
121 if (i2c->current_addr & 1) {
122 i2c->state = RECEIVING_BIT7;
123 i2c->buffer = i2c_recv(i2c->bus);
125 i2c->state = SENDING_BIT7;
126 } else if (data_goes_up && clock == 1)
127 bitbang_i2c_enter_stop(i2c);
130 case RECEIVING_BIT7 ... RECEIVING_BIT0:
131 qemu_set_irq(i2c->out, i2c->buffer >> 7);
132 if (clock_goes_down) {
133 /* will end up in SENDING_ACK */
136 } else if (data_goes_up && clock == 1)
137 bitbang_i2c_enter_stop(i2c);
141 if (clock_goes_down) {
142 i2c->state = RECEIVING_BIT7;
144 i2c->buffer = i2c_recv(i2c->bus);
147 } else if (data_goes_up && clock == 1)
148 bitbang_i2c_enter_stop(i2c);
152 i2c->last_data = data;
153 i2c->last_clock = clock;
156 static int bitbang_i2c_init(SysBusDevice *dev)
158 bitbang_i2c_interface *s = FROM_SYSBUS(bitbang_i2c_interface, dev);
161 sysbus_init_mmio(dev, 0x0, 0);
163 bus = i2c_init_bus(&dev->qdev, "i2c");
169 qdev_init_gpio_in(&dev->qdev, bitbang_i2c_gpio_set, 2);
170 qdev_init_gpio_out(&dev->qdev, &s->out, 1);
175 static void bitbang_i2c_register(void)
177 sysbus_register_dev("bitbang_i2c",
178 sizeof(bitbang_i2c_interface), bitbang_i2c_init);
181 device_init(bitbang_i2c_register)