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 |
} |