xref: /openbmc/qemu/tests/qtest/libqos/i2c-imx.c (revision a9a5c473)
1 /*
2  * QTest i.MX I2C driver
3  *
4  * Copyright (c) 2013 Jean-Christophe Dubois
5  *
6  *  This program is free software; you can redistribute it and/or modify it
7  *  under the terms of the GNU General Public License as published by the
8  *  Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful, but WITHOUT
12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14  *  for more details.
15  *
16  *  You should have received a copy of the GNU General Public License along
17  *  with this program; if not, see <http://www.gnu.org/licenses/>.
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 
28 enum IMXI2CDirection {
29     IMX_I2C_READ,
30     IMX_I2C_WRITE,
31 };
32 
33 static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr,
34                                    enum IMXI2CDirection direction)
35 {
36     qtest_writeb(s->parent.qts, s->addr + I2DR_ADDR,
37                  (addr << 1) | (direction == IMX_I2C_READ ? 1 : 0));
38 }
39 
40 static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
41                          const uint8_t *buf, uint16_t len)
42 {
43     IMXI2C *s = container_of(i2c, IMXI2C, parent);
44     uint8_t data;
45     uint8_t status;
46     uint16_t size = 0;
47 
48     if (!len) {
49         return;
50     }
51 
52     /* set the bus for write */
53     data = I2CR_IEN |
54            I2CR_IIEN |
55            I2CR_MSTA |
56            I2CR_MTX |
57            I2CR_TXAK;
58 
59     qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
60     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
61     g_assert((status & I2SR_IBB) != 0);
62 
63     /* set the slave address */
64     imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE);
65     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
66     g_assert((status & I2SR_IIF) != 0);
67     g_assert((status & I2SR_RXAK) == 0);
68 
69     /* ack the interrupt */
70     qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
71     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
72     g_assert((status & I2SR_IIF) == 0);
73 
74     while (size < len) {
75         /* check we are still busy */
76         status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
77         g_assert((status & I2SR_IBB) != 0);
78 
79         /* write the data */
80         qtest_writeb(i2c->qts, s->addr + I2DR_ADDR, buf[size]);
81         status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
82         g_assert((status & I2SR_IIF) != 0);
83         g_assert((status & I2SR_RXAK) == 0);
84 
85         /* ack the interrupt */
86         qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
87         status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
88         g_assert((status & I2SR_IIF) == 0);
89 
90         size++;
91     }
92 
93     /* release the bus */
94     data &= ~(I2CR_MSTA | I2CR_MTX);
95     qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
96     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
97     g_assert((status & I2SR_IBB) == 0);
98 }
99 
100 static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
101                          uint8_t *buf, uint16_t len)
102 {
103     IMXI2C *s = container_of(i2c, IMXI2C, parent);
104     uint8_t data;
105     uint8_t status;
106     uint16_t size = 0;
107 
108     if (!len) {
109         return;
110     }
111 
112     /* set the bus for write */
113     data = I2CR_IEN |
114            I2CR_IIEN |
115            I2CR_MSTA |
116            I2CR_MTX |
117            I2CR_TXAK;
118 
119     qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
120     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
121     g_assert((status & I2SR_IBB) != 0);
122 
123     /* set the slave address */
124     imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ);
125     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
126     g_assert((status & I2SR_IIF) != 0);
127     g_assert((status & I2SR_RXAK) == 0);
128 
129     /* ack the interrupt */
130     qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
131     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
132     g_assert((status & I2SR_IIF) == 0);
133 
134     /* set the bus for read */
135     data &= ~I2CR_MTX;
136     /* if only one byte don't ack */
137     if (len != 1) {
138         data &= ~I2CR_TXAK;
139     }
140     qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
141     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
142     g_assert((status & I2SR_IBB) != 0);
143 
144     /* dummy read */
145     qtest_readb(i2c->qts, s->addr + I2DR_ADDR);
146     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
147     g_assert((status & I2SR_IIF) != 0);
148 
149     /* ack the interrupt */
150     qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
151     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
152     g_assert((status & I2SR_IIF) == 0);
153 
154     while (size < len) {
155         /* check we are still busy */
156         status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
157         g_assert((status & I2SR_IBB) != 0);
158 
159         if (size == (len - 1)) {
160             /* stop the read transaction */
161             data &= ~(I2CR_MSTA | I2CR_MTX);
162         } else {
163             /* ack the data read */
164             data |= I2CR_TXAK;
165         }
166         qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
167 
168         /* read the data */
169         buf[size] = qtest_readb(i2c->qts, s->addr + I2DR_ADDR);
170 
171         if (size != (len - 1)) {
172             status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
173             g_assert((status & I2SR_IIF) != 0);
174 
175             /* ack the interrupt */
176             qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
177         }
178 
179         status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
180         g_assert((status & I2SR_IIF) == 0);
181 
182         size++;
183     }
184 
185     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
186     g_assert((status & I2SR_IBB) == 0);
187 }
188 
189 static void *imx_i2c_get_driver(void *obj, const char *interface)
190 {
191     IMXI2C *s = obj;
192     if (!g_strcmp0(interface, "i2c-bus")) {
193         return &s->parent;
194     }
195     fprintf(stderr, "%s not present in imx-i2c\n", interface);
196     g_assert_not_reached();
197 }
198 
199 void imx_i2c_init(IMXI2C *s, QTestState *qts, uint64_t addr)
200 {
201     s->addr = addr;
202 
203     s->obj.get_driver = imx_i2c_get_driver;
204 
205     s->parent.send = imx_i2c_send;
206     s->parent.recv = imx_i2c_recv;
207     s->parent.qts = qts;
208 }
209 
210 static void imx_i2c_register_nodes(void)
211 {
212     qos_node_create_driver("imx.i2c", NULL);
213     qos_node_produces("imx.i2c", "i2c-bus");
214 }
215 
216 libqos_init(imx_i2c_register_nodes);
217