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