i.MX: Add qtest support for I2C device emulator.
[qemu/ar7.git] / tests / libqos / i2c-imx.c
blobb5cef66b94f356b2506a944314f72747b2ea0868
1 /*
2 * QTest i.MX I2C driver
4 * Copyright (c) 2013 Jean-Christophe Dubois
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.
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.
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/>.
20 #include "libqos/i2c.h"
22 #include <glib.h>
23 #include <string.h>
25 #include "qemu/osdep.h"
26 #include "libqtest.h"
28 #include "hw/i2c/imx_i2c.h"
30 enum IMXI2CDirection {
31 IMX_I2C_READ,
32 IMX_I2C_WRITE,
35 typedef struct IMXI2C {
36 I2CAdapter parent;
38 uint64_t addr;
39 } IMXI2C;
42 static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr,
43 enum IMXI2CDirection direction)
45 writeb(s->addr + I2DR_ADDR, (addr << 1) |
46 (direction == IMX_I2C_READ ? 1 : 0));
49 static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
50 const uint8_t *buf, uint16_t len)
52 IMXI2C *s = (IMXI2C *)i2c;
53 uint8_t data;
54 uint8_t status;
55 uint16_t size = 0;
57 if (!len) {
58 return;
61 /* set the bus for write */
62 data = I2CR_IEN |
63 I2CR_IIEN |
64 I2CR_MSTA |
65 I2CR_MTX |
66 I2CR_TXAK;
68 writeb(s->addr + I2CR_ADDR, data);
69 status = readb(s->addr + I2SR_ADDR);
70 g_assert((status & I2SR_IBB) != 0);
72 /* set the slave address */
73 imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE);
74 status = readb(s->addr + I2SR_ADDR);
75 g_assert((status & I2SR_IIF) != 0);
76 g_assert((status & I2SR_RXAK) == 0);
78 /* ack the interrupt */
79 writeb(s->addr + I2SR_ADDR, 0);
80 status = readb(s->addr + I2SR_ADDR);
81 g_assert((status & I2SR_IIF) == 0);
83 while (size < len) {
84 /* check we are still busy */
85 status = readb(s->addr + I2SR_ADDR);
86 g_assert((status & I2SR_IBB) != 0);
88 /* write the data */
89 writeb(s->addr + I2DR_ADDR, buf[size]);
90 status = readb(s->addr + I2SR_ADDR);
91 g_assert((status & I2SR_IIF) != 0);
92 g_assert((status & I2SR_RXAK) == 0);
94 /* ack the interrupt */
95 writeb(s->addr + I2SR_ADDR, 0);
96 status = readb(s->addr + I2SR_ADDR);
97 g_assert((status & I2SR_IIF) == 0);
99 size++;
102 /* release the bus */
103 data &= ~(I2CR_MSTA | I2CR_MTX);
104 writeb(s->addr + I2CR_ADDR, data);
105 status = readb(s->addr + I2SR_ADDR);
106 g_assert((status & I2SR_IBB) == 0);
109 static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
110 uint8_t *buf, uint16_t len)
112 IMXI2C *s = (IMXI2C *)i2c;
113 uint8_t data;
114 uint8_t status;
115 uint16_t size = 0;
117 if (!len) {
118 return;
121 /* set the bus for write */
122 data = I2CR_IEN |
123 I2CR_IIEN |
124 I2CR_MSTA |
125 I2CR_MTX |
126 I2CR_TXAK;
128 writeb(s->addr + I2CR_ADDR, data);
129 status = readb(s->addr + I2SR_ADDR);
130 g_assert((status & I2SR_IBB) != 0);
132 /* set the slave address */
133 imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ);
134 status = readb(s->addr + I2SR_ADDR);
135 g_assert((status & I2SR_IIF) != 0);
136 g_assert((status & I2SR_RXAK) == 0);
138 /* ack the interrupt */
139 writeb(s->addr + I2SR_ADDR, 0);
140 status = readb(s->addr + I2SR_ADDR);
141 g_assert((status & I2SR_IIF) == 0);
143 /* set the bus for read */
144 data &= ~I2CR_MTX;
145 /* if only one byte don't ack */
146 if (len != 1) {
147 data &= ~I2CR_TXAK;
149 writeb(s->addr + I2CR_ADDR, data);
150 status = readb(s->addr + I2SR_ADDR);
151 g_assert((status & I2SR_IBB) != 0);
153 /* dummy read */
154 readb(s->addr + I2DR_ADDR);
155 status = readb(s->addr + I2SR_ADDR);
156 g_assert((status & I2SR_IIF) != 0);
158 /* ack the interrupt */
159 writeb(s->addr + I2SR_ADDR, 0);
160 status = readb(s->addr + I2SR_ADDR);
161 g_assert((status & I2SR_IIF) == 0);
163 while (size < len) {
164 /* check we are still busy */
165 status = readb(s->addr + I2SR_ADDR);
166 g_assert((status & I2SR_IBB) != 0);
168 if (size == (len - 1)) {
169 /* stop the read transaction */
170 data &= ~(I2CR_MSTA | I2CR_MTX);
171 } else {
172 /* ack the data read */
173 data |= I2CR_TXAK;
175 writeb(s->addr + I2CR_ADDR, data);
177 /* read the data */
178 buf[size] = readb(s->addr + I2DR_ADDR);
180 if (size != (len - 1)) {
181 status = readb(s->addr + I2SR_ADDR);
182 g_assert((status & I2SR_IIF) != 0);
184 /* ack the interrupt */
185 writeb(s->addr + I2SR_ADDR, 0);
188 status = readb(s->addr + I2SR_ADDR);
189 g_assert((status & I2SR_IIF) == 0);
191 size++;
194 status = readb(s->addr + I2SR_ADDR);
195 g_assert((status & I2SR_IBB) == 0);
198 I2CAdapter *imx_i2c_create(uint64_t addr)
200 IMXI2C *s = g_malloc0(sizeof(*s));
201 I2CAdapter *i2c = (I2CAdapter *)s;
203 s->addr = addr;
205 i2c->send = imx_i2c_send;
206 i2c->recv = imx_i2c_recv;
208 return i2c;