qemu/tests/qtest/libqos/i2c-imx.c
<<
>>
Prefs
   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);
 217