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