Revision 3cd035d8 hw/bitbang_i2c.c

b/hw/bitbang_i2c.c
7 7
 * This code is licenced under the GNU GPL v2.
8 8
 */
9 9
#include "hw.h"
10
#include "i2c.h"
10
#include "bitbang_i2c.h"
11 11
#include "sysbus.h"
12 12

  
13
//#define DEBUG_BITBANG_I2C
14

  
15
#ifdef DEBUG_BITBANG_I2C
16
#define DPRINTF(fmt, ...) \
17
do { printf("bitbang_i2c: " fmt , ## __VA_ARGS__); } while (0)
18
#else
19
#define DPRINTF(fmt, ...) do {} while(0)
20
#endif
21

  
13 22
typedef enum bitbang_i2c_state {
14 23
    STOPPED = 0,
15
    INITIALIZING,
16 24
    SENDING_BIT7,
17 25
    SENDING_BIT6,
18 26
    SENDING_BIT5,
......
33 41
    SENDING_ACK
34 42
} bitbang_i2c_state;
35 43

  
36
typedef struct bitbang_i2c_interface {
37
    SysBusDevice busdev;
44
struct bitbang_i2c_interface {
38 45
    i2c_bus *bus;
39 46
    bitbang_i2c_state state;
40 47
    int last_data;
41 48
    int last_clock;
49
    int device_out;
42 50
    uint8_t buffer;
43 51
    int current_addr;
44
    qemu_irq out;
45
} bitbang_i2c_interface;
52
};
46 53

  
47 54
static void bitbang_i2c_enter_stop(bitbang_i2c_interface *i2c)
48 55
{
56
    DPRINTF("STOP\n");
49 57
    if (i2c->current_addr >= 0)
50 58
        i2c_end_transfer(i2c->bus);
51 59
    i2c->current_addr = -1;
52 60
    i2c->state = STOPPED;
53 61
}
54 62

  
55
static void bitbang_i2c_gpio_set(void *opaque, int irq, int level)
63
/* Set device data pin.  */
64
static int bitbang_i2c_ret(bitbang_i2c_interface *i2c, int level)
65
{
66
    i2c->device_out = level;
67
    //DPRINTF("%d %d %d\n", i2c->last_clock, i2c->last_data, i2c->device_out);
68
    return level & i2c->last_data;
69
}
70

  
71
/* Leave device data pin unodified.  */
72
static int bitbang_i2c_nop(bitbang_i2c_interface *i2c)
73
{
74
    return bitbang_i2c_ret(i2c, i2c->device_out);
75
}
76

  
77
/* Returns data line level.  */
78
int bitbang_i2c_set(bitbang_i2c_interface *i2c, int line, int level)
56 79
{
57
    bitbang_i2c_interface *i2c = opaque;
58 80
    int data;
59
    int clock;
60
    int data_goes_up;
61
    int data_goes_down;
62
    int clock_goes_up;
63
    int clock_goes_down;
64

  
65
    /* get pins states */
66
    data    = i2c->last_data;
67
    clock   = i2c->last_clock;
68

  
69
    if (irq == 0)
70
        data = level;
71
    if (irq == 1)
72
        clock = level;
73

  
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;
79

  
80
    if (data_goes_up == 0 && data_goes_down == 0 &&
81
        clock_goes_up == 0 && clock_goes_down == 0)
82
        return;
83

  
84
    if (!i2c)
85
        return;
86

  
87
    if ((RECEIVING_BIT7 > i2c->state && i2c->state > RECEIVING_BIT0)
88
            || i2c->state == WAITING_FOR_ACK)
89
        qemu_set_irq(i2c->out, 0);
90 81

  
91
    switch (i2c->state) {
92
    case STOPPED:
93
        if (data_goes_down && clock == 1)
94
            i2c->state = INITIALIZING;
95
        break;
82
    if (level != 0 && level != 1) {
83
        abort();
84
    }
96 85

  
97
    case INITIALIZING:
98
        if (clock_goes_down && data == 0)
86
    if (line == BITBANG_I2C_SDA) {
87
        if (level == i2c->last_data) {
88
            return bitbang_i2c_nop(i2c);
89
        }
90
        i2c->last_data = level;
91
        if (i2c->last_clock == 0) {
92
            return bitbang_i2c_nop(i2c);
93
        }
94
        if (level == 0) {
95
            DPRINTF("START\n");
96
            /* START condition.  */
99 97
            i2c->state = SENDING_BIT7;
100
        else
98
            i2c->current_addr = -1;
99
        } else {
100
            /* STOP condition.  */
101 101
            bitbang_i2c_enter_stop(i2c);
102
        break;
102
        }
103
        return bitbang_i2c_ret(i2c, 1);
104
    }
105

  
106
    data = i2c->last_data;
107
    if (i2c->last_clock == level) {
108
        return bitbang_i2c_nop(i2c);
109
    }
110
    i2c->last_clock = level;
111
    if (level == 0) {
112
        /* State is set/read at the start of the clock pulse.
113
           release the data line at the end.  */
114
        return bitbang_i2c_ret(i2c, 1);
115
    }
116
    switch (i2c->state) {
117
    case STOPPED:
118
        return bitbang_i2c_ret(i2c, 1);
103 119

  
104 120
    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 */
108
            i2c->state++; 
109
        } else if (data_goes_up && clock == 1)
110
            bitbang_i2c_enter_stop(i2c);
111
        break;
121
        i2c->buffer = (i2c->buffer << 1) | data;
122
        /* will end up in WAITING_FOR_ACK */
123
        i2c->state++; 
124
        return bitbang_i2c_ret(i2c, 1);
112 125

  
113 126
    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,
118
                                   i2c->buffer & 1);
119
            } else
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);
124
            } else
125
                i2c->state = SENDING_BIT7;
126
        } else if (data_goes_up && clock == 1)
127
            bitbang_i2c_enter_stop(i2c);
128
        break;
129

  
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 */
134
            i2c->state++;
135
            i2c->buffer <<= 1;
136
        } else if (data_goes_up && clock == 1)
137
            bitbang_i2c_enter_stop(i2c);
138
        break;
127
        if (i2c->current_addr < 0) {
128
            i2c->current_addr = i2c->buffer;
129
            DPRINTF("Address 0x%02x\n", i2c->current_addr);
130
            i2c_start_transfer(i2c->bus, i2c->current_addr >> 1,
131
                               i2c->current_addr & 1);
132
        } else {
133
            DPRINTF("Sent 0x%02x\n", i2c->buffer);
134
            i2c_send(i2c->bus, i2c->buffer);
135
        }
136
        if (i2c->current_addr & 1) {
137
            i2c->state = RECEIVING_BIT7;
138
        } else {
139
            i2c->state = SENDING_BIT7;
140
        }
141
        return bitbang_i2c_ret(i2c, 0);
142

  
143
    case RECEIVING_BIT7:
144
        i2c->buffer = i2c_recv(i2c->bus);
145
        DPRINTF("RX byte 0x%02x\n", i2c->buffer);
146
        /* Fall through... */
147
    case RECEIVING_BIT6 ... RECEIVING_BIT0:
148
        data = i2c->buffer >> 7;
149
        /* will end up in SENDING_ACK */
150
        i2c->state++;
151
        i2c->buffer <<= 1;
152
        return bitbang_i2c_ret(i2c, data);
139 153

  
140 154
    case SENDING_ACK:
141
        if (clock_goes_down) {
142
            i2c->state = RECEIVING_BIT7;
143
            if (data == 0)
144
                i2c->buffer = i2c_recv(i2c->bus);
145
            else
146
                i2c_nack(i2c->bus);
147
        } else if (data_goes_up && clock == 1)
148
            bitbang_i2c_enter_stop(i2c);
149
        break;
155
        i2c->state = RECEIVING_BIT7;
156
        if (data != 0) {
157
            DPRINTF("NACKED\n");
158
            i2c_nack(i2c->bus);
159
        } else {
160
            DPRINTF("ACKED\n");
161
        }
162
        return bitbang_i2c_ret(i2c, 1);
150 163
    }
164
    abort();
165
}
166

  
167
bitbang_i2c_interface *bitbang_i2c_init(i2c_bus *bus)
168
{
169
    bitbang_i2c_interface *s;
170

  
171
    s = qemu_mallocz(sizeof(bitbang_i2c_interface));
172

  
173
    s->bus = bus;
174
    s->last_data = 1;
175
    s->last_clock = 1;
176
    s->device_out = 1;
177

  
178
    return s;
179
}
151 180

  
152
    i2c->last_data = data;
153
    i2c->last_clock = clock;
181
/* GPIO interface.  */
182
typedef struct {
183
    SysBusDevice busdev;
184
    bitbang_i2c_interface *bitbang;
185
    int last_level;
186
    qemu_irq out;
187
} GPIOI2CState;
188

  
189
static void bitbang_i2c_gpio_set(void *opaque, int irq, int level)
190
{
191
    GPIOI2CState *s = opaque;
192

  
193
    level = bitbang_i2c_set(s->bitbang, irq, level);
194
    if (level != s->last_level) {
195
        s->last_level = level;
196
        qemu_set_irq(s->out, level);
197
    }
154 198
}
155 199

  
156
static int bitbang_i2c_init(SysBusDevice *dev)
200
static int gpio_i2c_init(SysBusDevice *dev)
157 201
{
158
    bitbang_i2c_interface *s = FROM_SYSBUS(bitbang_i2c_interface, dev);
202
    GPIOI2CState *s = FROM_SYSBUS(GPIOI2CState, dev);
159 203
    i2c_bus *bus;
160 204

  
161 205
    sysbus_init_mmio(dev, 0x0, 0);
162 206

  
163 207
    bus = i2c_init_bus(&dev->qdev, "i2c");
164
    s->bus = bus;
165

  
166
    s->last_data = 1;
167
    s->last_clock = 1;
208
    s->bitbang = bitbang_i2c_init(bus);
168 209

  
169 210
    qdev_init_gpio_in(&dev->qdev, bitbang_i2c_gpio_set, 2);
170 211
    qdev_init_gpio_out(&dev->qdev, &s->out, 1);
......
172 213
    return 0;
173 214
}
174 215

  
216
static SysBusDeviceInfo gpio_i2c_info = {
217
    .init = gpio_i2c_init,
218
    .qdev.name  = "gpio_i2c",
219
    .qdev.desc  = "Virtual GPIO to I2C bridge",
220
    .qdev.size  = sizeof(GPIOI2CState),
221
};
222

  
175 223
static void bitbang_i2c_register(void)
176 224
{
177
    sysbus_register_dev("bitbang_i2c",
178
        sizeof(bitbang_i2c_interface), bitbang_i2c_init);
225
    sysbus_register_withprop(&gpio_i2c_info);
179 226
}
180 227

  
181 228
device_init(bitbang_i2c_register)

Also available in: Unified diff