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 void 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);
173 static void bitbang_i2c_register(void)
175 sysbus_register_dev("bitbang_i2c",
176 sizeof(bitbang_i2c_interface
), bitbang_i2c_init
);
179 device_init(bitbang_i2c_register
)