Statistics
| Branch: | Revision:

root / tests / libi2c-omap.c @ d0bce760

History | View | Annotate | Download (4.6 kB)

1
/*
2
 * QTest I2C driver
3
 *
4
 * Copyright (c) 2012 Andreas Färber
5
 *
6
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7
 * See the COPYING file in the top-level directory.
8
 */
9
#include "libi2c.h"
10

    
11
#include <glib.h>
12
#include <string.h>
13

    
14
#include "qemu/osdep.h"
15
#include "qemu/bswap.h"
16
#include "libqtest.h"
17

    
18
enum OMAPI2CRegisters {
19
    OMAP_I2C_REV  = 0x00,
20
    OMAP_I2C_STAT = 0x08,
21
    OMAP_I2C_CNT  = 0x18,
22
    OMAP_I2C_DATA = 0x1c,
23
    OMAP_I2C_CON  = 0x24,
24
    OMAP_I2C_SA   = 0x2c,
25
};
26

    
27
enum OMAPI2CSTATBits {
28
    OMAP_I2C_STAT_NACK = 1 << 1,
29
    OMAP_I2C_STAT_ARDY = 1 << 2,
30
    OMAP_I2C_STAT_RRDY = 1 << 3,
31
    OMAP_I2C_STAT_XRDY = 1 << 4,
32
    OMAP_I2C_STAT_ROVR = 1 << 11,
33
    OMAP_I2C_STAT_SBD  = 1 << 15,
34
};
35

    
36
enum OMAPI2CCONBits {
37
    OMAP_I2C_CON_STT    = 1 << 0,
38
    OMAP_I2C_CON_STP    = 1 << 1,
39
    OMAP_I2C_CON_TRX    = 1 << 9,
40
    OMAP_I2C_CON_MST    = 1 << 10,
41
    OMAP_I2C_CON_BE     = 1 << 14,
42
    OMAP_I2C_CON_I2C_EN = 1 << 15,
43
};
44

    
45
typedef struct OMAPI2C {
46
    I2CAdapter parent;
47

    
48
    uint64_t addr;
49
} OMAPI2C;
50

    
51

    
52
/* FIXME Use TBD readw qtest API */
53
static inline uint16_t readw(uint64_t addr)
54
{
55
    uint16_t data;
56

    
57
    memread(addr, &data, 2);
58
    return le16_to_cpu(data);
59
}
60

    
61
/* FIXME Use TBD writew qtest API */
62
static inline void writew(uint64_t addr, uint16_t data)
63
{
64
    data = cpu_to_le16(data);
65
    memwrite(addr, &data, 2);
66
}
67

    
68
#ifdef __GNUC__
69
#undef memread
70
#undef memwrite
71
#pragma GCC poison memread
72
#pragma GCC poison memwrite
73
#endif
74

    
75
static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr)
76
{
77
    uint16_t data = addr;
78

    
79
    writew(s->addr + OMAP_I2C_SA, data);
80
    data = readw(s->addr + OMAP_I2C_SA);
81
    g_assert_cmphex(data, ==, addr);
82
}
83

    
84
static void omap_i2c_send(I2CAdapter *i2c, uint8_t addr,
85
                          const uint8_t *buf, uint16_t len)
86
{
87
    OMAPI2C *s = (OMAPI2C *)i2c;
88
    uint16_t data;
89

    
90
    omap_i2c_set_slave_addr(s, addr);
91

    
92
    data = len;
93
    writew(s->addr + OMAP_I2C_CNT, data);
94

    
95
    data = OMAP_I2C_CON_I2C_EN |
96
           OMAP_I2C_CON_TRX |
97
           OMAP_I2C_CON_MST |
98
           OMAP_I2C_CON_STT |
99
           OMAP_I2C_CON_STP;
100
    writew(s->addr + OMAP_I2C_CON, data);
101
    data = readw(s->addr + OMAP_I2C_CON);
102
    g_assert((data & OMAP_I2C_CON_STP) != 0);
103

    
104
    data = readw(s->addr + OMAP_I2C_STAT);
105
    g_assert((data & OMAP_I2C_STAT_NACK) == 0);
106

    
107
    while (len > 1) {
108
        data = readw(s->addr + OMAP_I2C_STAT);
109
        g_assert((data & OMAP_I2C_STAT_XRDY) != 0);
110

    
111
        data = buf[0] | ((uint16_t)buf[1] << 8);
112
        writew(s->addr + OMAP_I2C_DATA, data);
113
        buf = (uint8_t *)buf + 2;
114
        len -= 2;
115
    }
116
    if (len == 1) {
117
        data = readw(s->addr + OMAP_I2C_STAT);
118
        g_assert((data & OMAP_I2C_STAT_XRDY) != 0);
119

    
120
        data = buf[0];
121
        writew(s->addr + OMAP_I2C_DATA, data);
122
    }
123

    
124
    data = readw(s->addr + OMAP_I2C_CON);
125
    g_assert((data & OMAP_I2C_CON_STP) == 0);
126
}
127

    
128
static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr,
129
                          uint8_t *buf, uint16_t len)
130
{
131
    OMAPI2C *s = (OMAPI2C *)i2c;
132
    uint16_t data, stat;
133

    
134
    omap_i2c_set_slave_addr(s, addr);
135

    
136
    data = len;
137
    writew(s->addr + OMAP_I2C_CNT, data);
138

    
139
    data = OMAP_I2C_CON_I2C_EN |
140
           OMAP_I2C_CON_MST |
141
           OMAP_I2C_CON_STT |
142
           OMAP_I2C_CON_STP;
143
    writew(s->addr + OMAP_I2C_CON, data);
144
    data = readw(s->addr + OMAP_I2C_CON);
145
    g_assert((data & OMAP_I2C_CON_STP) == 0);
146

    
147
    data = readw(s->addr + OMAP_I2C_STAT);
148
    g_assert((data & OMAP_I2C_STAT_NACK) == 0);
149

    
150
    data = readw(s->addr + OMAP_I2C_CNT);
151
    g_assert_cmpuint(data, ==, len);
152

    
153
    while (len > 0) {
154
        data = readw(s->addr + OMAP_I2C_STAT);
155
        g_assert((data & OMAP_I2C_STAT_RRDY) != 0);
156
        g_assert((data & OMAP_I2C_STAT_ROVR) == 0);
157

    
158
        data = readw(s->addr + OMAP_I2C_DATA);
159

    
160
        stat = readw(s->addr + OMAP_I2C_STAT);
161

    
162
        if (unlikely(len == 1)) {
163
            g_assert((stat & OMAP_I2C_STAT_SBD) != 0);
164

    
165
            buf[0] = data & 0xff;
166
            buf++;
167
            len--;
168
        } else {
169
            buf[0] = data & 0xff;
170
            buf[1] = data >> 8;
171
            buf += 2;
172
            len -= 2;
173
        }
174
    }
175

    
176
    data = readw(s->addr + OMAP_I2C_CON);
177
    g_assert((data & OMAP_I2C_CON_STP) == 0);
178
}
179

    
180
I2CAdapter *omap_i2c_create(uint64_t addr)
181
{
182
    OMAPI2C *s = g_malloc0(sizeof(*s));
183
    I2CAdapter *i2c = (I2CAdapter *)s;
184
    uint16_t data;
185

    
186
    s->addr = addr;
187

    
188
    i2c->send = omap_i2c_send;
189
    i2c->recv = omap_i2c_recv;
190

    
191
    /* verify the mmio address by looking for a known signature */
192
    data = readw(addr + OMAP_I2C_REV);
193
    g_assert_cmphex(data, ==, 0x34);
194

    
195
    return i2c;
196
}