qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

i2c-imx.c (6255B)


      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 
     28 enum IMXI2CDirection {
     29     IMX_I2C_READ,
     30     IMX_I2C_WRITE,
     31 };
     32 
     33 static 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 
     40 static 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 
    100 static 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 
    189 static 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 
    199 void 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 
    210 static 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 
    216 libqos_init(imx_i2c_register_nodes);