qemu/tests/libqos/i2c-omap.c
<<
>>
Prefs
   1/*
   2 * QTest I2C driver
   3 *
   4 * Copyright (c) 2012 Andreas Färber
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 */
   9#include "qemu/osdep.h"
  10#include "libqos/i2c.h"
  11
  12#include <glib.h>
  13
  14#include "qemu/bswap.h"
  15#include "libqtest.h"
  16
  17enum OMAPI2CRegisters {
  18    OMAP_I2C_REV  = 0x00,
  19    OMAP_I2C_STAT = 0x08,
  20    OMAP_I2C_CNT  = 0x18,
  21    OMAP_I2C_DATA = 0x1c,
  22    OMAP_I2C_CON  = 0x24,
  23    OMAP_I2C_SA   = 0x2c,
  24};
  25
  26enum OMAPI2CSTATBits {
  27    OMAP_I2C_STAT_NACK = 1 << 1,
  28    OMAP_I2C_STAT_ARDY = 1 << 2,
  29    OMAP_I2C_STAT_RRDY = 1 << 3,
  30    OMAP_I2C_STAT_XRDY = 1 << 4,
  31    OMAP_I2C_STAT_ROVR = 1 << 11,
  32    OMAP_I2C_STAT_SBD  = 1 << 15,
  33};
  34
  35enum OMAPI2CCONBits {
  36    OMAP_I2C_CON_STT    = 1 << 0,
  37    OMAP_I2C_CON_STP    = 1 << 1,
  38    OMAP_I2C_CON_TRX    = 1 << 9,
  39    OMAP_I2C_CON_MST    = 1 << 10,
  40    OMAP_I2C_CON_BE     = 1 << 14,
  41    OMAP_I2C_CON_I2C_EN = 1 << 15,
  42};
  43
  44typedef struct OMAPI2C {
  45    I2CAdapter parent;
  46
  47    uint64_t addr;
  48} OMAPI2C;
  49
  50
  51static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr)
  52{
  53    uint16_t data = addr;
  54
  55    writew(s->addr + OMAP_I2C_SA, data);
  56    data = readw(s->addr + OMAP_I2C_SA);
  57    g_assert_cmphex(data, ==, addr);
  58}
  59
  60static void omap_i2c_send(I2CAdapter *i2c, uint8_t addr,
  61                          const uint8_t *buf, uint16_t len)
  62{
  63    OMAPI2C *s = (OMAPI2C *)i2c;
  64    uint16_t data;
  65
  66    omap_i2c_set_slave_addr(s, addr);
  67
  68    data = len;
  69    writew(s->addr + OMAP_I2C_CNT, data);
  70
  71    data = OMAP_I2C_CON_I2C_EN |
  72           OMAP_I2C_CON_TRX |
  73           OMAP_I2C_CON_MST |
  74           OMAP_I2C_CON_STT |
  75           OMAP_I2C_CON_STP;
  76    writew(s->addr + OMAP_I2C_CON, data);
  77    data = readw(s->addr + OMAP_I2C_CON);
  78    g_assert((data & OMAP_I2C_CON_STP) != 0);
  79
  80    data = readw(s->addr + OMAP_I2C_STAT);
  81    g_assert((data & OMAP_I2C_STAT_NACK) == 0);
  82
  83    while (len > 1) {
  84        data = readw(s->addr + OMAP_I2C_STAT);
  85        g_assert((data & OMAP_I2C_STAT_XRDY) != 0);
  86
  87        data = buf[0] | ((uint16_t)buf[1] << 8);
  88        writew(s->addr + OMAP_I2C_DATA, data);
  89        buf = (uint8_t *)buf + 2;
  90        len -= 2;
  91    }
  92    if (len == 1) {
  93        data = readw(s->addr + OMAP_I2C_STAT);
  94        g_assert((data & OMAP_I2C_STAT_XRDY) != 0);
  95
  96        data = buf[0];
  97        writew(s->addr + OMAP_I2C_DATA, data);
  98    }
  99
 100    data = readw(s->addr + OMAP_I2C_CON);
 101    g_assert((data & OMAP_I2C_CON_STP) == 0);
 102}
 103
 104static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr,
 105                          uint8_t *buf, uint16_t len)
 106{
 107    OMAPI2C *s = (OMAPI2C *)i2c;
 108    uint16_t data, stat;
 109
 110    omap_i2c_set_slave_addr(s, addr);
 111
 112    data = len;
 113    writew(s->addr + OMAP_I2C_CNT, data);
 114
 115    data = OMAP_I2C_CON_I2C_EN |
 116           OMAP_I2C_CON_MST |
 117           OMAP_I2C_CON_STT |
 118           OMAP_I2C_CON_STP;
 119    writew(s->addr + OMAP_I2C_CON, data);
 120    data = readw(s->addr + OMAP_I2C_CON);
 121    g_assert((data & OMAP_I2C_CON_STP) == 0);
 122
 123    data = readw(s->addr + OMAP_I2C_STAT);
 124    g_assert((data & OMAP_I2C_STAT_NACK) == 0);
 125
 126    data = readw(s->addr + OMAP_I2C_CNT);
 127    g_assert_cmpuint(data, ==, len);
 128
 129    while (len > 0) {
 130        data = readw(s->addr + OMAP_I2C_STAT);
 131        g_assert((data & OMAP_I2C_STAT_RRDY) != 0);
 132        g_assert((data & OMAP_I2C_STAT_ROVR) == 0);
 133
 134        data = readw(s->addr + OMAP_I2C_DATA);
 135
 136        stat = readw(s->addr + OMAP_I2C_STAT);
 137
 138        if (unlikely(len == 1)) {
 139            g_assert((stat & OMAP_I2C_STAT_SBD) != 0);
 140
 141            buf[0] = data & 0xff;
 142            buf++;
 143            len--;
 144        } else {
 145            buf[0] = data & 0xff;
 146            buf[1] = data >> 8;
 147            buf += 2;
 148            len -= 2;
 149        }
 150    }
 151
 152    data = readw(s->addr + OMAP_I2C_CON);
 153    g_assert((data & OMAP_I2C_CON_STP) == 0);
 154}
 155
 156I2CAdapter *omap_i2c_create(uint64_t addr)
 157{
 158    OMAPI2C *s = g_malloc0(sizeof(*s));
 159    I2CAdapter *i2c = (I2CAdapter *)s;
 160    uint16_t data;
 161
 162    s->addr = addr;
 163
 164    i2c->send = omap_i2c_send;
 165    i2c->recv = omap_i2c_recv;
 166
 167    /* verify the mmio address by looking for a known signature */
 168    data = readw(addr + OMAP_I2C_REV);
 169    g_assert_cmphex(data, ==, 0x34);
 170
 171    return i2c;
 172}
 173