xref: /openbmc/qemu/tests/qtest/libqos/i2c-imx.c (revision a2ce7dbd)
11cf4323eSThomas Huth /*
21cf4323eSThomas Huth  * QTest i.MX I2C driver
31cf4323eSThomas Huth  *
41cf4323eSThomas Huth  * Copyright (c) 2013 Jean-Christophe Dubois
51cf4323eSThomas Huth  *
61cf4323eSThomas Huth  *  This program is free software; you can redistribute it and/or modify it
71cf4323eSThomas Huth  *  under the terms of the GNU General Public License as published by the
81cf4323eSThomas Huth  *  Free Software Foundation; either version 2 of the License, or
91cf4323eSThomas Huth  *  (at your option) any later version.
101cf4323eSThomas Huth  *
111cf4323eSThomas Huth  *  This program is distributed in the hope that it will be useful, but WITHOUT
121cf4323eSThomas Huth  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131cf4323eSThomas Huth  *  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
141cf4323eSThomas Huth  *  for more details.
151cf4323eSThomas Huth  *
161cf4323eSThomas Huth  *  You should have received a copy of the GNU General Public License along
171cf4323eSThomas Huth  *  with this program; if not, see <http://www.gnu.org/licenses/>.
181cf4323eSThomas Huth  */
191cf4323eSThomas Huth 
201cf4323eSThomas Huth #include "qemu/osdep.h"
21*a2ce7dbdSPaolo Bonzini #include "i2c.h"
221cf4323eSThomas Huth 
231cf4323eSThomas Huth 
241cf4323eSThomas Huth #include "libqtest.h"
251cf4323eSThomas Huth 
261cf4323eSThomas Huth #include "hw/i2c/imx_i2c.h"
271cf4323eSThomas Huth 
281cf4323eSThomas Huth enum IMXI2CDirection {
291cf4323eSThomas Huth     IMX_I2C_READ,
301cf4323eSThomas Huth     IMX_I2C_WRITE,
311cf4323eSThomas Huth };
321cf4323eSThomas Huth 
331cf4323eSThomas Huth static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr,
341cf4323eSThomas Huth                                    enum IMXI2CDirection direction)
351cf4323eSThomas Huth {
361cf4323eSThomas Huth     qtest_writeb(s->parent.qts, s->addr + I2DR_ADDR,
371cf4323eSThomas Huth                  (addr << 1) | (direction == IMX_I2C_READ ? 1 : 0));
381cf4323eSThomas Huth }
391cf4323eSThomas Huth 
401cf4323eSThomas Huth static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr,
411cf4323eSThomas Huth                          const uint8_t *buf, uint16_t len)
421cf4323eSThomas Huth {
431cf4323eSThomas Huth     IMXI2C *s = container_of(i2c, IMXI2C, parent);
441cf4323eSThomas Huth     uint8_t data;
451cf4323eSThomas Huth     uint8_t status;
461cf4323eSThomas Huth     uint16_t size = 0;
471cf4323eSThomas Huth 
481cf4323eSThomas Huth     if (!len) {
491cf4323eSThomas Huth         return;
501cf4323eSThomas Huth     }
511cf4323eSThomas Huth 
521cf4323eSThomas Huth     /* set the bus for write */
531cf4323eSThomas Huth     data = I2CR_IEN |
541cf4323eSThomas Huth            I2CR_IIEN |
551cf4323eSThomas Huth            I2CR_MSTA |
561cf4323eSThomas Huth            I2CR_MTX |
571cf4323eSThomas Huth            I2CR_TXAK;
581cf4323eSThomas Huth 
591cf4323eSThomas Huth     qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
601cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
611cf4323eSThomas Huth     g_assert((status & I2SR_IBB) != 0);
621cf4323eSThomas Huth 
631cf4323eSThomas Huth     /* set the slave address */
641cf4323eSThomas Huth     imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE);
651cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
661cf4323eSThomas Huth     g_assert((status & I2SR_IIF) != 0);
671cf4323eSThomas Huth     g_assert((status & I2SR_RXAK) == 0);
681cf4323eSThomas Huth 
691cf4323eSThomas Huth     /* ack the interrupt */
701cf4323eSThomas Huth     qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
711cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
721cf4323eSThomas Huth     g_assert((status & I2SR_IIF) == 0);
731cf4323eSThomas Huth 
741cf4323eSThomas Huth     while (size < len) {
751cf4323eSThomas Huth         /* check we are still busy */
761cf4323eSThomas Huth         status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
771cf4323eSThomas Huth         g_assert((status & I2SR_IBB) != 0);
781cf4323eSThomas Huth 
791cf4323eSThomas Huth         /* write the data */
801cf4323eSThomas Huth         qtest_writeb(i2c->qts, s->addr + I2DR_ADDR, buf[size]);
811cf4323eSThomas Huth         status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
821cf4323eSThomas Huth         g_assert((status & I2SR_IIF) != 0);
831cf4323eSThomas Huth         g_assert((status & I2SR_RXAK) == 0);
841cf4323eSThomas Huth 
851cf4323eSThomas Huth         /* ack the interrupt */
861cf4323eSThomas Huth         qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
871cf4323eSThomas Huth         status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
881cf4323eSThomas Huth         g_assert((status & I2SR_IIF) == 0);
891cf4323eSThomas Huth 
901cf4323eSThomas Huth         size++;
911cf4323eSThomas Huth     }
921cf4323eSThomas Huth 
931cf4323eSThomas Huth     /* release the bus */
941cf4323eSThomas Huth     data &= ~(I2CR_MSTA | I2CR_MTX);
951cf4323eSThomas Huth     qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
961cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
971cf4323eSThomas Huth     g_assert((status & I2SR_IBB) == 0);
981cf4323eSThomas Huth }
991cf4323eSThomas Huth 
1001cf4323eSThomas Huth static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr,
1011cf4323eSThomas Huth                          uint8_t *buf, uint16_t len)
1021cf4323eSThomas Huth {
1031cf4323eSThomas Huth     IMXI2C *s = container_of(i2c, IMXI2C, parent);
1041cf4323eSThomas Huth     uint8_t data;
1051cf4323eSThomas Huth     uint8_t status;
1061cf4323eSThomas Huth     uint16_t size = 0;
1071cf4323eSThomas Huth 
1081cf4323eSThomas Huth     if (!len) {
1091cf4323eSThomas Huth         return;
1101cf4323eSThomas Huth     }
1111cf4323eSThomas Huth 
1121cf4323eSThomas Huth     /* set the bus for write */
1131cf4323eSThomas Huth     data = I2CR_IEN |
1141cf4323eSThomas Huth            I2CR_IIEN |
1151cf4323eSThomas Huth            I2CR_MSTA |
1161cf4323eSThomas Huth            I2CR_MTX |
1171cf4323eSThomas Huth            I2CR_TXAK;
1181cf4323eSThomas Huth 
1191cf4323eSThomas Huth     qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
1201cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
1211cf4323eSThomas Huth     g_assert((status & I2SR_IBB) != 0);
1221cf4323eSThomas Huth 
1231cf4323eSThomas Huth     /* set the slave address */
1241cf4323eSThomas Huth     imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ);
1251cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
1261cf4323eSThomas Huth     g_assert((status & I2SR_IIF) != 0);
1271cf4323eSThomas Huth     g_assert((status & I2SR_RXAK) == 0);
1281cf4323eSThomas Huth 
1291cf4323eSThomas Huth     /* ack the interrupt */
1301cf4323eSThomas Huth     qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
1311cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
1321cf4323eSThomas Huth     g_assert((status & I2SR_IIF) == 0);
1331cf4323eSThomas Huth 
1341cf4323eSThomas Huth     /* set the bus for read */
1351cf4323eSThomas Huth     data &= ~I2CR_MTX;
1361cf4323eSThomas Huth     /* if only one byte don't ack */
1371cf4323eSThomas Huth     if (len != 1) {
1381cf4323eSThomas Huth         data &= ~I2CR_TXAK;
1391cf4323eSThomas Huth     }
1401cf4323eSThomas Huth     qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
1411cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
1421cf4323eSThomas Huth     g_assert((status & I2SR_IBB) != 0);
1431cf4323eSThomas Huth 
1441cf4323eSThomas Huth     /* dummy read */
1451cf4323eSThomas Huth     qtest_readb(i2c->qts, s->addr + I2DR_ADDR);
1461cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
1471cf4323eSThomas Huth     g_assert((status & I2SR_IIF) != 0);
1481cf4323eSThomas Huth 
1491cf4323eSThomas Huth     /* ack the interrupt */
1501cf4323eSThomas Huth     qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
1511cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
1521cf4323eSThomas Huth     g_assert((status & I2SR_IIF) == 0);
1531cf4323eSThomas Huth 
1541cf4323eSThomas Huth     while (size < len) {
1551cf4323eSThomas Huth         /* check we are still busy */
1561cf4323eSThomas Huth         status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
1571cf4323eSThomas Huth         g_assert((status & I2SR_IBB) != 0);
1581cf4323eSThomas Huth 
1591cf4323eSThomas Huth         if (size == (len - 1)) {
1601cf4323eSThomas Huth             /* stop the read transaction */
1611cf4323eSThomas Huth             data &= ~(I2CR_MSTA | I2CR_MTX);
1621cf4323eSThomas Huth         } else {
1631cf4323eSThomas Huth             /* ack the data read */
1641cf4323eSThomas Huth             data |= I2CR_TXAK;
1651cf4323eSThomas Huth         }
1661cf4323eSThomas Huth         qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data);
1671cf4323eSThomas Huth 
1681cf4323eSThomas Huth         /* read the data */
1691cf4323eSThomas Huth         buf[size] = qtest_readb(i2c->qts, s->addr + I2DR_ADDR);
1701cf4323eSThomas Huth 
1711cf4323eSThomas Huth         if (size != (len - 1)) {
1721cf4323eSThomas Huth             status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
1731cf4323eSThomas Huth             g_assert((status & I2SR_IIF) != 0);
1741cf4323eSThomas Huth 
1751cf4323eSThomas Huth             /* ack the interrupt */
1761cf4323eSThomas Huth             qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0);
1771cf4323eSThomas Huth         }
1781cf4323eSThomas Huth 
1791cf4323eSThomas Huth         status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
1801cf4323eSThomas Huth         g_assert((status & I2SR_IIF) == 0);
1811cf4323eSThomas Huth 
1821cf4323eSThomas Huth         size++;
1831cf4323eSThomas Huth     }
1841cf4323eSThomas Huth 
1851cf4323eSThomas Huth     status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR);
1861cf4323eSThomas Huth     g_assert((status & I2SR_IBB) == 0);
1871cf4323eSThomas Huth }
1881cf4323eSThomas Huth 
1891cf4323eSThomas Huth static void *imx_i2c_get_driver(void *obj, const char *interface)
1901cf4323eSThomas Huth {
1911cf4323eSThomas Huth     IMXI2C *s = obj;
1921cf4323eSThomas Huth     if (!g_strcmp0(interface, "i2c-bus")) {
1931cf4323eSThomas Huth         return &s->parent;
1941cf4323eSThomas Huth     }
1951cf4323eSThomas Huth     fprintf(stderr, "%s not present in imx-i2c\n", interface);
1961cf4323eSThomas Huth     g_assert_not_reached();
1971cf4323eSThomas Huth }
1981cf4323eSThomas Huth 
1991cf4323eSThomas Huth void imx_i2c_init(IMXI2C *s, QTestState *qts, uint64_t addr)
2001cf4323eSThomas Huth {
2011cf4323eSThomas Huth     s->addr = addr;
2021cf4323eSThomas Huth 
2031cf4323eSThomas Huth     s->obj.get_driver = imx_i2c_get_driver;
2041cf4323eSThomas Huth 
2051cf4323eSThomas Huth     s->parent.send = imx_i2c_send;
2061cf4323eSThomas Huth     s->parent.recv = imx_i2c_recv;
2071cf4323eSThomas Huth     s->parent.qts = qts;
2081cf4323eSThomas Huth }
2091cf4323eSThomas Huth 
2101cf4323eSThomas Huth static void imx_i2c_register_nodes(void)
2111cf4323eSThomas Huth {
2121cf4323eSThomas Huth     qos_node_create_driver("imx.i2c", NULL);
2131cf4323eSThomas Huth     qos_node_produces("imx.i2c", "i2c-bus");
2141cf4323eSThomas Huth }
2151cf4323eSThomas Huth 
2161cf4323eSThomas Huth libqos_init(imx_i2c_register_nodes);
217