1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include "libqos/i2c.h"
22
23
24#include "libqtest.h"
25
26#include "hw/i2c/imx_i2c.h"
27
28enum IMXI2CDirection {
29 IMX_I2C_READ,
30 IMX_I2C_WRITE,
31};
32
33typedef struct IMXI2C {
34 I2CAdapter parent;
35
36 uint64_t addr;
37} IMXI2C;
38
39
40static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr,
41 enum IMXI2CDirection direction)
42{
43 qtest_writeb(s->parent.qts, s->addr + I2DR_ADDR,
44 (addr << 1) | (direction == IMX_I2C_READ ? 1 : 0));
45}
46
47static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
48 const uint8_t *buf, uint16_t len)
49{
50 IMXI2C *s = (IMXI2C *)i2c;
51 uint8_t data;
52 uint8_t status;
53 uint16_t size = 0;
54
55 if (!len) {
56 return;
57 }
58
59
60 data = I2CR_IEN |
61 I2CR_IIEN |
62 I2CR_MSTA |
63 I2CR_MTX |
64 I2CR_TXAK;
65
66 qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
67 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
68 g_assert((status & I2SR_IBB) != 0);
69
70
71 imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE);
72 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
73 g_assert((status & I2SR_IIF) != 0);
74 g_assert((status & I2SR_RXAK) == 0);
75
76
77 qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
78 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
79 g_assert((status & I2SR_IIF) == 0);
80
81 while (size < len) {
82
83 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
84 g_assert((status & I2SR_IBB) != 0);
85
86
87 qtest_writeb(i2c->qts, s->addr + I2DR_ADDR, buf[size]);
88 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
89 g_assert((status & I2SR_IIF) != 0);
90 g_assert((status & I2SR_RXAK) == 0);
91
92
93 qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
94 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
95 g_assert((status & I2SR_IIF) == 0);
96
97 size++;
98 }
99
100
101 data &= ~(I2CR_MSTA | I2CR_MTX);
102 qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
103 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
104 g_assert((status & I2SR_IBB) == 0);
105}
106
107static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
108 uint8_t *buf, uint16_t len)
109{
110 IMXI2C *s = (IMXI2C *)i2c;
111 uint8_t data;
112 uint8_t status;
113 uint16_t size = 0;
114
115 if (!len) {
116 return;
117 }
118
119
120 data = I2CR_IEN |
121 I2CR_IIEN |
122 I2CR_MSTA |
123 I2CR_MTX |
124 I2CR_TXAK;
125
126 qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
127 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
128 g_assert((status & I2SR_IBB) != 0);
129
130
131 imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ);
132 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
133 g_assert((status & I2SR_IIF) != 0);
134 g_assert((status & I2SR_RXAK) == 0);
135
136
137 qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
138 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
139 g_assert((status & I2SR_IIF) == 0);
140
141
142 data &= ~I2CR_MTX;
143
144 if (len != 1) {
145 data &= ~I2CR_TXAK;
146 }
147 qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
148 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
149 g_assert((status & I2SR_IBB) != 0);
150
151
152 qtest_readb(i2c->qts, s->addr + I2DR_ADDR);
153 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
154 g_assert((status & I2SR_IIF) != 0);
155
156
157 qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
158 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
159 g_assert((status & I2SR_IIF) == 0);
160
161 while (size < len) {
162
163 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
164 g_assert((status & I2SR_IBB) != 0);
165
166 if (size == (len - 1)) {
167
168 data &= ~(I2CR_MSTA | I2CR_MTX);
169 } else {
170
171 data |= I2CR_TXAK;
172 }
173 qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
174
175
176 buf[size] = qtest_readb(i2c->qts, s->addr + I2DR_ADDR);
177
178 if (size != (len - 1)) {
179 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
180 g_assert((status & I2SR_IIF) != 0);
181
182
183 qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
184 }
185
186 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
187 g_assert((status & I2SR_IIF) == 0);
188
189 size++;
190 }
191
192 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
193 g_assert((status & I2SR_IBB) == 0);
194}
195
196I2CAdapter *imx_i2c_create(QTestState *qts, uint64_t addr)
197{
198 IMXI2C *s = g_malloc0(sizeof(*s));
199 I2CAdapter *i2c = (I2CAdapter *)s;
200
201 s->addr = addr;
202
203 i2c->send = imx_i2c_send;
204 i2c->recv = imx_i2c_recv;
205 i2c->qts = qts;
206
207 return i2c;
208}
209