i2c-imx.c (6252B)
1/* 2 * QTest i.MX I2C driver 3 * 4 * Copyright (c) 2013 Jean-Christophe Dubois 5 * 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. 10 * 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. 15 * 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/>. 18 */ 19 20#include "qemu/osdep.h" 21#include "i2c.h" 22 23 24#include "libqtest.h" 25 26#include "hw/i2c/imx_i2c.h" 27 28enum IMXI2CDirection { 29 IMX_I2C_READ, 30 IMX_I2C_WRITE, 31}; 32 33static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr, 34 enum IMXI2CDirection direction) 35{ 36 qtest_writeb(s->parent.qts, s->addr + I2DR_ADDR, 37 (addr << 1) | (direction == IMX_I2C_READ ? 1 : 0)); 38} 39 40static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr, 41 const uint8_t *buf, uint16_t len) 42{ 43 IMXI2C *s = container_of(i2c, IMXI2C, parent); 44 uint8_t data; 45 uint8_t status; 46 uint16_t size = 0; 47 48 if (!len) { 49 return; 50 } 51 52 /* set the bus for write */ 53 data = I2CR_IEN | 54 I2CR_IIEN | 55 I2CR_MSTA | 56 I2CR_MTX | 57 I2CR_TXAK; 58 59 qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data); 60 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 61 g_assert((status & I2SR_IBB) != 0); 62 63 /* set the slave address */ 64 imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE); 65 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 66 g_assert((status & I2SR_IIF) != 0); 67 g_assert((status & I2SR_RXAK) == 0); 68 69 /* ack the interrupt */ 70 qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0); 71 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 72 g_assert((status & I2SR_IIF) == 0); 73 74 while (size < len) { 75 /* check we are still busy */ 76 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 77 g_assert((status & I2SR_IBB) != 0); 78 79 /* write the data */ 80 qtest_writeb(i2c->qts, s->addr + I2DR_ADDR, buf[size]); 81 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 82 g_assert((status & I2SR_IIF) != 0); 83 g_assert((status & I2SR_RXAK) == 0); 84 85 /* ack the interrupt */ 86 qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0); 87 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 88 g_assert((status & I2SR_IIF) == 0); 89 90 size++; 91 } 92 93 /* release the bus */ 94 data &= ~(I2CR_MSTA | I2CR_MTX); 95 qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data); 96 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 97 g_assert((status & I2SR_IBB) == 0); 98} 99 100static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr, 101 uint8_t *buf, uint16_t len) 102{ 103 IMXI2C *s = container_of(i2c, IMXI2C, parent); 104 uint8_t data; 105 uint8_t status; 106 uint16_t size = 0; 107 108 if (!len) { 109 return; 110 } 111 112 /* set the bus for write */ 113 data = I2CR_IEN | 114 I2CR_IIEN | 115 I2CR_MSTA | 116 I2CR_MTX | 117 I2CR_TXAK; 118 119 qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data); 120 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 121 g_assert((status & I2SR_IBB) != 0); 122 123 /* set the slave address */ 124 imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ); 125 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 126 g_assert((status & I2SR_IIF) != 0); 127 g_assert((status & I2SR_RXAK) == 0); 128 129 /* ack the interrupt */ 130 qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0); 131 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 132 g_assert((status & I2SR_IIF) == 0); 133 134 /* set the bus for read */ 135 data &= ~I2CR_MTX; 136 /* if only one byte don't ack */ 137 if (len != 1) { 138 data &= ~I2CR_TXAK; 139 } 140 qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data); 141 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 142 g_assert((status & I2SR_IBB) != 0); 143 144 /* dummy read */ 145 qtest_readb(i2c->qts, s->addr + I2DR_ADDR); 146 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 147 g_assert((status & I2SR_IIF) != 0); 148 149 /* ack the interrupt */ 150 qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0); 151 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 152 g_assert((status & I2SR_IIF) == 0); 153 154 while (size < len) { 155 /* check we are still busy */ 156 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 157 g_assert((status & I2SR_IBB) != 0); 158 159 if (size == (len - 1)) { 160 /* stop the read transaction */ 161 data &= ~(I2CR_MSTA | I2CR_MTX); 162 } else { 163 /* ack the data read */ 164 data |= I2CR_TXAK; 165 } 166 qtest_writeb(i2c->qts, s->addr + I2CR_ADDR, data); 167 168 /* read the data */ 169 buf[size] = qtest_readb(i2c->qts, s->addr + I2DR_ADDR); 170 171 if (size != (len - 1)) { 172 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 173 g_assert((status & I2SR_IIF) != 0); 174 175 /* ack the interrupt */ 176 qtest_writeb(i2c->qts, s->addr + I2SR_ADDR, 0); 177 } 178 179 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 180 g_assert((status & I2SR_IIF) == 0); 181 182 size++; 183 } 184 185 status = qtest_readb(i2c->qts, s->addr + I2SR_ADDR); 186 g_assert((status & I2SR_IBB) == 0); 187} 188 189static void *imx_i2c_get_driver(void *obj, const char *interface) 190{ 191 IMXI2C *s = obj; 192 if (!g_strcmp0(interface, "i2c-bus")) { 193 return &s->parent; 194 } 195 fprintf(stderr, "%s not present in imx-i2c\n", interface); 196 g_assert_not_reached(); 197} 198 199void imx_i2c_init(IMXI2C *s, QTestState *qts, uint64_t addr) 200{ 201 s->addr = addr; 202 203 s->obj.get_driver = imx_i2c_get_driver; 204 205 s->parent.send = imx_i2c_send; 206 s->parent.recv = imx_i2c_recv; 207 s->parent.qts = qts; 208} 209 210static void imx_i2c_register_nodes(void) 211{ 212 qos_node_create_driver("imx.i2c", NULL); 213 qos_node_produces("imx.i2c", "i2c-bus"); 214} 215 216libqos_init(imx_i2c_register_nodes);