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