qemu/hw/i2c/omap_i2c.c
<<
>>
Prefs
   1/*
   2 * TI OMAP on-chip I2C controller.  Only "new I2C" mode supported.
   3 *
   4 * Copyright (C) 2007 Andrzej Zaborowski  <balrog@zabor.org>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License as
   8 * published by the Free Software Foundation; either version 2 of
   9 * the License, or (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License 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#include "qemu/osdep.h"
  20#include "hw/hw.h"
  21#include "hw/i2c/i2c.h"
  22#include "hw/arm/omap.h"
  23#include "hw/sysbus.h"
  24#include "qemu/error-report.h"
  25#include "qapi/error.h"
  26
  27#define TYPE_OMAP_I2C "omap_i2c"
  28#define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C)
  29
  30typedef struct OMAPI2CState {
  31    SysBusDevice parent_obj;
  32
  33    MemoryRegion iomem;
  34    qemu_irq irq;
  35    qemu_irq drq[2];
  36    I2CBus *bus;
  37
  38    uint8_t revision;
  39    void *iclk;
  40    void *fclk;
  41
  42    uint8_t mask;
  43    uint16_t stat;
  44    uint16_t dma;
  45    uint16_t count;
  46    int count_cur;
  47    uint32_t fifo;
  48    int rxlen;
  49    int txlen;
  50    uint16_t control;
  51    uint16_t addr[2];
  52    uint8_t divider;
  53    uint8_t times[2];
  54    uint16_t test;
  55} OMAPI2CState;
  56
  57#define OMAP2_INTR_REV  0x34
  58#define OMAP2_GC_REV    0x34
  59
  60static void omap_i2c_interrupts_update(OMAPI2CState *s)
  61{
  62    qemu_set_irq(s->irq, s->stat & s->mask);
  63    if ((s->dma >> 15) & 1)                                     /* RDMA_EN */
  64        qemu_set_irq(s->drq[0], (s->stat >> 3) & 1);            /* RRDY */
  65    if ((s->dma >> 7) & 1)                                      /* XDMA_EN */
  66        qemu_set_irq(s->drq[1], (s->stat >> 4) & 1);            /* XRDY */
  67}
  68
  69static void omap_i2c_fifo_run(OMAPI2CState *s)
  70{
  71    int ack = 1;
  72
  73    if (!i2c_bus_busy(s->bus))
  74        return;
  75
  76    if ((s->control >> 2) & 1) {                                /* RM */
  77        if ((s->control >> 1) & 1) {                            /* STP */
  78            i2c_end_transfer(s->bus);
  79            s->control &= ~(1 << 1);                            /* STP */
  80            s->count_cur = s->count;
  81            s->txlen = 0;
  82        } else if ((s->control >> 9) & 1) {                     /* TRX */
  83            while (ack && s->txlen)
  84                ack = (i2c_send(s->bus,
  85                                        (s->fifo >> ((-- s->txlen) << 3)) &
  86                                        0xff) >= 0);
  87            s->stat |= 1 << 4;                                  /* XRDY */
  88        } else {
  89            while (s->rxlen < 4)
  90                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
  91            s->stat |= 1 << 3;                                  /* RRDY */
  92        }
  93    } else {
  94        if ((s->control >> 9) & 1) {                            /* TRX */
  95            while (ack && s->count_cur && s->txlen) {
  96                ack = (i2c_send(s->bus,
  97                                        (s->fifo >> ((-- s->txlen) << 3)) &
  98                                        0xff) >= 0);
  99                s->count_cur --;
 100            }
 101            if (ack && s->count_cur)
 102                s->stat |= 1 << 4;                              /* XRDY */
 103            else
 104                s->stat &= ~(1 << 4);                           /* XRDY */
 105            if (!s->count_cur) {
 106                s->stat |= 1 << 2;                              /* ARDY */
 107                s->control &= ~(1 << 10);                       /* MST */
 108            }
 109        } else {
 110            while (s->count_cur && s->rxlen < 4) {
 111                s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3);
 112                s->count_cur --;
 113            }
 114            if (s->rxlen)
 115                s->stat |= 1 << 3;                              /* RRDY */
 116            else
 117                s->stat &= ~(1 << 3);                           /* RRDY */
 118        }
 119        if (!s->count_cur) {
 120            if ((s->control >> 1) & 1) {                        /* STP */
 121                i2c_end_transfer(s->bus);
 122                s->control &= ~(1 << 1);                        /* STP */
 123                s->count_cur = s->count;
 124                s->txlen = 0;
 125            } else {
 126                s->stat |= 1 << 2;                              /* ARDY */
 127                s->control &= ~(1 << 10);                       /* MST */
 128            }
 129        }
 130    }
 131
 132    s->stat |= (!ack) << 1;                                     /* NACK */
 133    if (!ack)
 134        s->control &= ~(1 << 1);                                /* STP */
 135}
 136
 137static void omap_i2c_reset(DeviceState *dev)
 138{
 139    OMAPI2CState *s = OMAP_I2C(dev);
 140
 141    s->mask = 0;
 142    s->stat = 0;
 143    s->dma = 0;
 144    s->count = 0;
 145    s->count_cur = 0;
 146    s->fifo = 0;
 147    s->rxlen = 0;
 148    s->txlen = 0;
 149    s->control = 0;
 150    s->addr[0] = 0;
 151    s->addr[1] = 0;
 152    s->divider = 0;
 153    s->times[0] = 0;
 154    s->times[1] = 0;
 155    s->test = 0;
 156}
 157
 158static uint32_t omap_i2c_read(void *opaque, hwaddr addr)
 159{
 160    OMAPI2CState *s = opaque;
 161    int offset = addr & OMAP_MPUI_REG_MASK;
 162    uint16_t ret;
 163
 164    switch (offset) {
 165    case 0x00:  /* I2C_REV */
 166        return s->revision;                                     /* REV */
 167
 168    case 0x04:  /* I2C_IE */
 169        return s->mask;
 170
 171    case 0x08:  /* I2C_STAT */
 172        return s->stat | (i2c_bus_busy(s->bus) << 12);
 173
 174    case 0x0c:  /* I2C_IV */
 175        if (s->revision >= OMAP2_INTR_REV)
 176            break;
 177        ret = ctz32(s->stat & s->mask);
 178        if (ret != 32) {
 179            s->stat ^= 1 << ret;
 180            ret++;
 181        } else {
 182            ret = 0;
 183        }
 184        omap_i2c_interrupts_update(s);
 185        return ret;
 186
 187    case 0x10:  /* I2C_SYSS */
 188        return (s->control >> 15) & 1;                          /* I2C_EN */
 189
 190    case 0x14:  /* I2C_BUF */
 191        return s->dma;
 192
 193    case 0x18:  /* I2C_CNT */
 194        return s->count_cur;                                    /* DCOUNT */
 195
 196    case 0x1c:  /* I2C_DATA */
 197        ret = 0;
 198        if (s->control & (1 << 14)) {                           /* BE */
 199            ret |= ((s->fifo >> 0) & 0xff) << 8;
 200            ret |= ((s->fifo >> 8) & 0xff) << 0;
 201        } else {
 202            ret |= ((s->fifo >> 8) & 0xff) << 8;
 203            ret |= ((s->fifo >> 0) & 0xff) << 0;
 204        }
 205        if (s->rxlen == 1) {
 206            s->stat |= 1 << 15;                                 /* SBD */
 207            s->rxlen = 0;
 208        } else if (s->rxlen > 1) {
 209            if (s->rxlen > 2)
 210                s->fifo >>= 16;
 211            s->rxlen -= 2;
 212        } else {
 213            /* XXX: remote access (qualifier) error - what's that?  */
 214        }
 215        if (!s->rxlen) {
 216            s->stat &= ~(1 << 3);                               /* RRDY */
 217            if (((s->control >> 10) & 1) &&                     /* MST */
 218                            ((~s->control >> 9) & 1)) {         /* TRX */
 219                s->stat |= 1 << 2;                              /* ARDY */
 220                s->control &= ~(1 << 10);                       /* MST */
 221            }
 222        }
 223        s->stat &= ~(1 << 11);                                  /* ROVR */
 224        omap_i2c_fifo_run(s);
 225        omap_i2c_interrupts_update(s);
 226        return ret;
 227
 228    case 0x20:  /* I2C_SYSC */
 229        return 0;
 230
 231    case 0x24:  /* I2C_CON */
 232        return s->control;
 233
 234    case 0x28:  /* I2C_OA */
 235        return s->addr[0];
 236
 237    case 0x2c:  /* I2C_SA */
 238        return s->addr[1];
 239
 240    case 0x30:  /* I2C_PSC */
 241        return s->divider;
 242
 243    case 0x34:  /* I2C_SCLL */
 244        return s->times[0];
 245
 246    case 0x38:  /* I2C_SCLH */
 247        return s->times[1];
 248
 249    case 0x3c:  /* I2C_SYSTEST */
 250        if (s->test & (1 << 15)) {                              /* ST_EN */
 251            s->test ^= 0xa;
 252            return s->test;
 253        } else
 254            return s->test & ~0x300f;
 255    }
 256
 257    OMAP_BAD_REG(addr);
 258    return 0;
 259}
 260
 261static void omap_i2c_write(void *opaque, hwaddr addr,
 262                uint32_t value)
 263{
 264    OMAPI2CState *s = opaque;
 265    int offset = addr & OMAP_MPUI_REG_MASK;
 266    int nack;
 267
 268    switch (offset) {
 269    case 0x00:  /* I2C_REV */
 270    case 0x0c:  /* I2C_IV */
 271    case 0x10:  /* I2C_SYSS */
 272        OMAP_RO_REG(addr);
 273        return;
 274
 275    case 0x04:  /* I2C_IE */
 276        s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f);
 277        break;
 278
 279    case 0x08:  /* I2C_STAT */
 280        if (s->revision < OMAP2_INTR_REV) {
 281            OMAP_RO_REG(addr);
 282            return;
 283        }
 284
 285        /* RRDY and XRDY are reset by hardware. (in all versions???) */
 286        s->stat &= ~(value & 0x27);
 287        omap_i2c_interrupts_update(s);
 288        break;
 289
 290    case 0x14:  /* I2C_BUF */
 291        s->dma = value & 0x8080;
 292        if (value & (1 << 15))                                  /* RDMA_EN */
 293            s->mask &= ~(1 << 3);                               /* RRDY_IE */
 294        if (value & (1 << 7))                                   /* XDMA_EN */
 295            s->mask &= ~(1 << 4);                               /* XRDY_IE */
 296        break;
 297
 298    case 0x18:  /* I2C_CNT */
 299        s->count = value;                                       /* DCOUNT */
 300        break;
 301
 302    case 0x1c:  /* I2C_DATA */
 303        if (s->txlen > 2) {
 304            /* XXX: remote access (qualifier) error - what's that?  */
 305            break;
 306        }
 307        s->fifo <<= 16;
 308        s->txlen += 2;
 309        if (s->control & (1 << 14)) {                           /* BE */
 310            s->fifo |= ((value >> 8) & 0xff) << 8;
 311            s->fifo |= ((value >> 0) & 0xff) << 0;
 312        } else {
 313            s->fifo |= ((value >> 0) & 0xff) << 8;
 314            s->fifo |= ((value >> 8) & 0xff) << 0;
 315        }
 316        s->stat &= ~(1 << 10);                                  /* XUDF */
 317        if (s->txlen > 2)
 318            s->stat &= ~(1 << 4);                               /* XRDY */
 319        omap_i2c_fifo_run(s);
 320        omap_i2c_interrupts_update(s);
 321        break;
 322
 323    case 0x20:  /* I2C_SYSC */
 324        if (s->revision < OMAP2_INTR_REV) {
 325            OMAP_BAD_REG(addr);
 326            return;
 327        }
 328
 329        if (value & 2) {
 330            omap_i2c_reset(DEVICE(s));
 331        }
 332        break;
 333
 334    case 0x24:  /* I2C_CON */
 335        s->control = value & 0xcf87;
 336        if (~value & (1 << 15)) {                               /* I2C_EN */
 337            if (s->revision < OMAP2_INTR_REV) {
 338                omap_i2c_reset(DEVICE(s));
 339            }
 340            break;
 341        }
 342        if ((value & (1 << 15)) && !(value & (1 << 10))) {      /* MST */
 343            fprintf(stderr, "%s: I^2C slave mode not supported\n",
 344                            __func__);
 345            break;
 346        }
 347        if ((value & (1 << 15)) && value & (1 << 8)) {          /* XA */
 348            fprintf(stderr, "%s: 10-bit addressing mode not supported\n",
 349                            __func__);
 350            break;
 351        }
 352        if ((value & (1 << 15)) && value & (1 << 0)) {          /* STT */
 353            nack = !!i2c_start_transfer(s->bus, s->addr[1],     /* SA */
 354                            (~value >> 9) & 1);                 /* TRX */
 355            s->stat |= nack << 1;                               /* NACK */
 356            s->control &= ~(1 << 0);                            /* STT */
 357            s->fifo = 0;
 358            if (nack)
 359                s->control &= ~(1 << 1);                        /* STP */
 360            else {
 361                s->count_cur = s->count;
 362                omap_i2c_fifo_run(s);
 363            }
 364            omap_i2c_interrupts_update(s);
 365        }
 366        break;
 367
 368    case 0x28:  /* I2C_OA */
 369        s->addr[0] = value & 0x3ff;
 370        break;
 371
 372    case 0x2c:  /* I2C_SA */
 373        s->addr[1] = value & 0x3ff;
 374        break;
 375
 376    case 0x30:  /* I2C_PSC */
 377        s->divider = value;
 378        break;
 379
 380    case 0x34:  /* I2C_SCLL */
 381        s->times[0] = value;
 382        break;
 383
 384    case 0x38:  /* I2C_SCLH */
 385        s->times[1] = value;
 386        break;
 387
 388    case 0x3c:  /* I2C_SYSTEST */
 389        s->test = value & 0xf80f;
 390        if (value & (1 << 11))                                  /* SBB */
 391            if (s->revision >= OMAP2_INTR_REV) {
 392                s->stat |= 0x3f;
 393                omap_i2c_interrupts_update(s);
 394            }
 395        if (value & (1 << 15))                                  /* ST_EN */
 396            fprintf(stderr, "%s: System Test not supported\n", __func__);
 397        break;
 398
 399    default:
 400        OMAP_BAD_REG(addr);
 401        return;
 402    }
 403}
 404
 405static void omap_i2c_writeb(void *opaque, hwaddr addr,
 406                uint32_t value)
 407{
 408    OMAPI2CState *s = opaque;
 409    int offset = addr & OMAP_MPUI_REG_MASK;
 410
 411    switch (offset) {
 412    case 0x1c:  /* I2C_DATA */
 413        if (s->txlen > 2) {
 414            /* XXX: remote access (qualifier) error - what's that?  */
 415            break;
 416        }
 417        s->fifo <<= 8;
 418        s->txlen += 1;
 419        s->fifo |= value & 0xff;
 420        s->stat &= ~(1 << 10);                                  /* XUDF */
 421        if (s->txlen > 2)
 422            s->stat &= ~(1 << 4);                               /* XRDY */
 423        omap_i2c_fifo_run(s);
 424        omap_i2c_interrupts_update(s);
 425        break;
 426
 427    default:
 428        OMAP_BAD_REG(addr);
 429        return;
 430    }
 431}
 432
 433static uint64_t omap_i2c_readfn(void *opaque, hwaddr addr,
 434                                unsigned size)
 435{
 436    switch (size) {
 437    case 2:
 438        return omap_i2c_read(opaque, addr);
 439    default:
 440        return omap_badwidth_read16(opaque, addr);
 441    }
 442}
 443
 444static void omap_i2c_writefn(void *opaque, hwaddr addr,
 445                             uint64_t value, unsigned size)
 446{
 447    switch (size) {
 448    case 1:
 449        /* Only the last fifo write can be 8 bit. */
 450        omap_i2c_writeb(opaque, addr, value);
 451        break;
 452    case 2:
 453        omap_i2c_write(opaque, addr, value);
 454        break;
 455    default:
 456        omap_badwidth_write16(opaque, addr, value);
 457        break;
 458    }
 459}
 460
 461static const MemoryRegionOps omap_i2c_ops = {
 462    .read = omap_i2c_readfn,
 463    .write = omap_i2c_writefn,
 464    .valid.min_access_size = 1,
 465    .valid.max_access_size = 4,
 466    .endianness = DEVICE_NATIVE_ENDIAN,
 467};
 468
 469static void omap_i2c_init(Object *obj)
 470{
 471    DeviceState *dev = DEVICE(obj);
 472    OMAPI2CState *s = OMAP_I2C(obj);
 473    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 474
 475    sysbus_init_irq(sbd, &s->irq);
 476    sysbus_init_irq(sbd, &s->drq[0]);
 477    sysbus_init_irq(sbd, &s->drq[1]);
 478    sysbus_init_mmio(sbd, &s->iomem);
 479    s->bus = i2c_init_bus(dev, NULL);
 480}
 481
 482static void omap_i2c_realize(DeviceState *dev, Error **errp)
 483{
 484    OMAPI2CState *s = OMAP_I2C(dev);
 485
 486    memory_region_init_io(&s->iomem, OBJECT(dev), &omap_i2c_ops, s, "omap.i2c",
 487                          (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
 488
 489    if (!s->fclk) {
 490        error_setg(errp, "omap_i2c: fclk not connected");
 491        return;
 492    }
 493    if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
 494        /* Note that OMAP1 doesn't have a separate interface clock */
 495        error_setg(errp, "omap_i2c: iclk not connected");
 496        return;
 497    }
 498}
 499
 500static Property omap_i2c_properties[] = {
 501    DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0),
 502    DEFINE_PROP_PTR("iclk", OMAPI2CState, iclk),
 503    DEFINE_PROP_PTR("fclk", OMAPI2CState, fclk),
 504    DEFINE_PROP_END_OF_LIST(),
 505};
 506
 507static void omap_i2c_class_init(ObjectClass *klass, void *data)
 508{
 509    DeviceClass *dc = DEVICE_CLASS(klass);
 510
 511    dc->props = omap_i2c_properties;
 512    dc->reset = omap_i2c_reset;
 513    /* Reason: pointer properties "iclk", "fclk" */
 514    dc->user_creatable = false;
 515    dc->realize = omap_i2c_realize;
 516}
 517
 518static const TypeInfo omap_i2c_info = {
 519    .name = TYPE_OMAP_I2C,
 520    .parent = TYPE_SYS_BUS_DEVICE,
 521    .instance_size = sizeof(OMAPI2CState),
 522    .instance_init = omap_i2c_init,
 523    .class_init = omap_i2c_class_init,
 524};
 525
 526static void omap_i2c_register_types(void)
 527{
 528    type_register_static(&omap_i2c_info);
 529}
 530
 531I2CBus *omap_i2c_bus(DeviceState *omap_i2c)
 532{
 533    OMAPI2CState *s = OMAP_I2C(omap_i2c);
 534    return s->bus;
 535}
 536
 537type_init(omap_i2c_register_types)
 538