4 * Copyright (c) 2012 Andreas Färber
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.
9 #include "qemu/osdep.h"
10 #include "libqos/i2c.h"
13 #include "qemu/bswap.h"
16 enum OMAPI2CRegisters
{
25 enum OMAPI2CSTATBits
{
26 OMAP_I2C_STAT_NACK
= 1 << 1,
27 OMAP_I2C_STAT_ARDY
= 1 << 2,
28 OMAP_I2C_STAT_RRDY
= 1 << 3,
29 OMAP_I2C_STAT_XRDY
= 1 << 4,
30 OMAP_I2C_STAT_ROVR
= 1 << 11,
31 OMAP_I2C_STAT_SBD
= 1 << 15,
35 OMAP_I2C_CON_STT
= 1 << 0,
36 OMAP_I2C_CON_STP
= 1 << 1,
37 OMAP_I2C_CON_TRX
= 1 << 9,
38 OMAP_I2C_CON_MST
= 1 << 10,
39 OMAP_I2C_CON_BE
= 1 << 14,
40 OMAP_I2C_CON_I2C_EN
= 1 << 15,
44 static void omap_i2c_set_slave_addr(OMAPI2C
*s
, uint8_t addr
)
48 qtest_writew(s
->parent
.qts
, s
->addr
+ OMAP_I2C_SA
, data
);
49 data
= qtest_readw(s
->parent
.qts
, s
->addr
+ OMAP_I2C_SA
);
50 g_assert_cmphex(data
, ==, addr
);
53 static void omap_i2c_send(I2CAdapter
*i2c
, uint8_t addr
,
54 const uint8_t *buf
, uint16_t len
)
56 OMAPI2C
*s
= container_of(i2c
, OMAPI2C
, parent
);
59 omap_i2c_set_slave_addr(s
, addr
);
62 qtest_writew(i2c
->qts
, s
->addr
+ OMAP_I2C_CNT
, data
);
64 data
= OMAP_I2C_CON_I2C_EN
|
69 qtest_writew(i2c
->qts
, s
->addr
+ OMAP_I2C_CON
, data
);
70 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_CON
);
71 g_assert((data
& OMAP_I2C_CON_STP
) != 0);
73 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_STAT
);
74 g_assert((data
& OMAP_I2C_STAT_NACK
) == 0);
77 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_STAT
);
78 g_assert((data
& OMAP_I2C_STAT_XRDY
) != 0);
80 data
= buf
[0] | ((uint16_t)buf
[1] << 8);
81 qtest_writew(i2c
->qts
, s
->addr
+ OMAP_I2C_DATA
, data
);
82 buf
= (uint8_t *)buf
+ 2;
86 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_STAT
);
87 g_assert((data
& OMAP_I2C_STAT_XRDY
) != 0);
90 qtest_writew(i2c
->qts
, s
->addr
+ OMAP_I2C_DATA
, data
);
93 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_CON
);
94 g_assert((data
& OMAP_I2C_CON_STP
) == 0);
97 static void omap_i2c_recv(I2CAdapter
*i2c
, uint8_t addr
,
98 uint8_t *buf
, uint16_t len
)
100 OMAPI2C
*s
= container_of(i2c
, OMAPI2C
, parent
);
102 uint16_t orig_len
= len
;
104 omap_i2c_set_slave_addr(s
, addr
);
107 qtest_writew(i2c
->qts
, s
->addr
+ OMAP_I2C_CNT
, data
);
109 data
= OMAP_I2C_CON_I2C_EN
|
113 qtest_writew(i2c
->qts
, s
->addr
+ OMAP_I2C_CON
, data
);
115 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_STAT
);
116 g_assert((data
& OMAP_I2C_STAT_NACK
) == 0);
119 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_CON
);
121 g_assert((data
& OMAP_I2C_CON_STP
) == 0);
123 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_CNT
);
124 g_assert_cmpuint(data
, ==, orig_len
);
126 g_assert((data
& OMAP_I2C_CON_STP
) != 0);
128 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_CNT
);
129 g_assert_cmpuint(data
, ==, len
- 4);
132 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_STAT
);
133 g_assert((data
& OMAP_I2C_STAT_RRDY
) != 0);
134 g_assert((data
& OMAP_I2C_STAT_ROVR
) == 0);
136 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_DATA
);
138 stat
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_STAT
);
140 if (unlikely(len
== 1)) {
141 g_assert((stat
& OMAP_I2C_STAT_SBD
) != 0);
143 buf
[0] = data
& 0xff;
147 buf
[0] = data
& 0xff;
154 data
= qtest_readw(i2c
->qts
, s
->addr
+ OMAP_I2C_CON
);
155 g_assert((data
& OMAP_I2C_CON_STP
) == 0);
158 static void *omap_i2c_get_driver(void *obj
, const char *interface
)
161 if (!g_strcmp0(interface
, "i2c-bus")) {
164 fprintf(stderr
, "%s not present in omap_i2c\n", interface
);
165 g_assert_not_reached();
168 static void omap_i2c_start_hw(QOSGraphObject
*object
)
170 OMAPI2C
*s
= (OMAPI2C
*) object
;
173 /* verify the mmio address by looking for a known signature */
174 data
= qtest_readw(s
->parent
.qts
, s
->addr
+ OMAP_I2C_REV
);
175 g_assert_cmphex(data
, ==, 0x34);
178 void omap_i2c_init(OMAPI2C
*s
, QTestState
*qts
, uint64_t addr
)
182 s
->obj
.get_driver
= omap_i2c_get_driver
;
183 s
->obj
.start_hw
= omap_i2c_start_hw
;
185 s
->parent
.send
= omap_i2c_send
;
186 s
->parent
.recv
= omap_i2c_recv
;
190 static void omap_i2c_register_nodes(void)
192 qos_node_create_driver("omap_i2c", NULL
);
193 qos_node_produces("omap_i2c", "i2c-bus");
196 libqos_init(omap_i2c_register_nodes
);