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