Statistics
| Branch: | Revision:

root / hw / i2c / bitbang_i2c.c @ 47b43a1f

History | View | Annotate | Download (6 kB)

1
/*
2
 * Bit-Bang i2c emulation extracted from
3
 * Marvell MV88W8618 / Freecom MusicPal emulation.
4
 *
5
 * Copyright (c) 2008 Jan Kiszka
6
 *
7
 * This code is licensed under the GNU GPL v2.
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.
11
 */
12
#include "hw/hw.h"
13
#include "bitbang_i2c.h"
14
#include "hw/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,
44
    SENDING_ACK,
45
    SENT_NACK
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:
122
    case SENT_NACK:
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");
163
            i2c->state = SENT_NACK;
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

    
177
    s = g_malloc0(sizeof(bitbang_i2c_interface));
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;
190
    MemoryRegion dummy_iomem;
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

    
212
    memory_region_init(&s->dummy_iomem, "gpio_i2c", 0);
213
    sysbus_init_mmio(dev, &s->dummy_iomem);
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

    
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 const 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,
238
};
239

    
240
static void bitbang_i2c_register_types(void)
241
{
242
    type_register_static(&gpio_i2c_info);
243
}
244

    
245
type_init(bitbang_i2c_register_types)