qemu/hw/i2c/npcm7xx_smbus.c
<<
>>
Prefs
   1/*
   2 * Nuvoton NPCM7xx SMBus Module.
   3 *
   4 * Copyright 2020 Google LLC
   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
  17#include "qemu/osdep.h"
  18
  19#include "hw/i2c/npcm7xx_smbus.h"
  20#include "migration/vmstate.h"
  21#include "qemu/bitops.h"
  22#include "qemu/guest-random.h"
  23#include "qemu/log.h"
  24#include "qemu/module.h"
  25#include "qemu/units.h"
  26
  27#include "trace.h"
  28
  29enum NPCM7xxSMBusCommonRegister {
  30    NPCM7XX_SMB_SDA     = 0x0,
  31    NPCM7XX_SMB_ST      = 0x2,
  32    NPCM7XX_SMB_CST     = 0x4,
  33    NPCM7XX_SMB_CTL1    = 0x6,
  34    NPCM7XX_SMB_ADDR1   = 0x8,
  35    NPCM7XX_SMB_CTL2    = 0xa,
  36    NPCM7XX_SMB_ADDR2   = 0xc,
  37    NPCM7XX_SMB_CTL3    = 0xe,
  38    NPCM7XX_SMB_CST2    = 0x18,
  39    NPCM7XX_SMB_CST3    = 0x19,
  40    NPCM7XX_SMB_VER     = 0x1f,
  41};
  42
  43enum NPCM7xxSMBusBank0Register {
  44    NPCM7XX_SMB_ADDR3   = 0x10,
  45    NPCM7XX_SMB_ADDR7   = 0x11,
  46    NPCM7XX_SMB_ADDR4   = 0x12,
  47    NPCM7XX_SMB_ADDR8   = 0x13,
  48    NPCM7XX_SMB_ADDR5   = 0x14,
  49    NPCM7XX_SMB_ADDR9   = 0x15,
  50    NPCM7XX_SMB_ADDR6   = 0x16,
  51    NPCM7XX_SMB_ADDR10  = 0x17,
  52    NPCM7XX_SMB_CTL4    = 0x1a,
  53    NPCM7XX_SMB_CTL5    = 0x1b,
  54    NPCM7XX_SMB_SCLLT   = 0x1c,
  55    NPCM7XX_SMB_FIF_CTL = 0x1d,
  56    NPCM7XX_SMB_SCLHT   = 0x1e,
  57};
  58
  59enum NPCM7xxSMBusBank1Register {
  60    NPCM7XX_SMB_FIF_CTS  = 0x10,
  61    NPCM7XX_SMB_FAIR_PER = 0x11,
  62    NPCM7XX_SMB_TXF_CTL  = 0x12,
  63    NPCM7XX_SMB_T_OUT    = 0x14,
  64    NPCM7XX_SMB_TXF_STS  = 0x1a,
  65    NPCM7XX_SMB_RXF_STS  = 0x1c,
  66    NPCM7XX_SMB_RXF_CTL  = 0x1e,
  67};
  68
  69/* ST fields */
  70#define NPCM7XX_SMBST_STP           BIT(7)
  71#define NPCM7XX_SMBST_SDAST         BIT(6)
  72#define NPCM7XX_SMBST_BER           BIT(5)
  73#define NPCM7XX_SMBST_NEGACK        BIT(4)
  74#define NPCM7XX_SMBST_STASTR        BIT(3)
  75#define NPCM7XX_SMBST_NMATCH        BIT(2)
  76#define NPCM7XX_SMBST_MODE          BIT(1)
  77#define NPCM7XX_SMBST_XMIT          BIT(0)
  78
  79/* CST fields */
  80#define NPCM7XX_SMBCST_ARPMATCH        BIT(7)
  81#define NPCM7XX_SMBCST_MATCHAF         BIT(6)
  82#define NPCM7XX_SMBCST_TGSCL           BIT(5)
  83#define NPCM7XX_SMBCST_TSDA            BIT(4)
  84#define NPCM7XX_SMBCST_GCMATCH         BIT(3)
  85#define NPCM7XX_SMBCST_MATCH           BIT(2)
  86#define NPCM7XX_SMBCST_BB              BIT(1)
  87#define NPCM7XX_SMBCST_BUSY            BIT(0)
  88
  89/* CST2 fields */
  90#define NPCM7XX_SMBCST2_INTSTS         BIT(7)
  91#define NPCM7XX_SMBCST2_MATCH7F        BIT(6)
  92#define NPCM7XX_SMBCST2_MATCH6F        BIT(5)
  93#define NPCM7XX_SMBCST2_MATCH5F        BIT(4)
  94#define NPCM7XX_SMBCST2_MATCH4F        BIT(3)
  95#define NPCM7XX_SMBCST2_MATCH3F        BIT(2)
  96#define NPCM7XX_SMBCST2_MATCH2F        BIT(1)
  97#define NPCM7XX_SMBCST2_MATCH1F        BIT(0)
  98
  99/* CST3 fields */
 100#define NPCM7XX_SMBCST3_EO_BUSY        BIT(7)
 101#define NPCM7XX_SMBCST3_MATCH10F       BIT(2)
 102#define NPCM7XX_SMBCST3_MATCH9F        BIT(1)
 103#define NPCM7XX_SMBCST3_MATCH8F        BIT(0)
 104
 105/* CTL1 fields */
 106#define NPCM7XX_SMBCTL1_STASTRE     BIT(7)
 107#define NPCM7XX_SMBCTL1_NMINTE      BIT(6)
 108#define NPCM7XX_SMBCTL1_GCMEN       BIT(5)
 109#define NPCM7XX_SMBCTL1_ACK         BIT(4)
 110#define NPCM7XX_SMBCTL1_EOBINTE     BIT(3)
 111#define NPCM7XX_SMBCTL1_INTEN       BIT(2)
 112#define NPCM7XX_SMBCTL1_STOP        BIT(1)
 113#define NPCM7XX_SMBCTL1_START       BIT(0)
 114
 115/* CTL2 fields */
 116#define NPCM7XX_SMBCTL2_SCLFRQ(rv)  extract8((rv), 1, 6)
 117#define NPCM7XX_SMBCTL2_ENABLE      BIT(0)
 118
 119/* CTL3 fields */
 120#define NPCM7XX_SMBCTL3_SCL_LVL     BIT(7)
 121#define NPCM7XX_SMBCTL3_SDA_LVL     BIT(6)
 122#define NPCM7XX_SMBCTL3_BNK_SEL     BIT(5)
 123#define NPCM7XX_SMBCTL3_400K_MODE   BIT(4)
 124#define NPCM7XX_SMBCTL3_IDL_START   BIT(3)
 125#define NPCM7XX_SMBCTL3_ARPMEN      BIT(2)
 126#define NPCM7XX_SMBCTL3_SCLFRQ(rv)  extract8((rv), 0, 2)
 127
 128/* ADDR fields */
 129#define NPCM7XX_ADDR_EN             BIT(7)
 130#define NPCM7XX_ADDR_A(rv)          extract8((rv), 0, 6)
 131
 132/* FIFO Mode Register Fields */
 133/* FIF_CTL fields */
 134#define NPCM7XX_SMBFIF_CTL_FIFO_EN          BIT(4)
 135#define NPCM7XX_SMBFIF_CTL_FAIR_RDY_IE      BIT(2)
 136#define NPCM7XX_SMBFIF_CTL_FAIR_RDY         BIT(1)
 137#define NPCM7XX_SMBFIF_CTL_FAIR_BUSY        BIT(0)
 138/* FIF_CTS fields */
 139#define NPCM7XX_SMBFIF_CTS_STR              BIT(7)
 140#define NPCM7XX_SMBFIF_CTS_CLR_FIFO         BIT(6)
 141#define NPCM7XX_SMBFIF_CTS_RFTE_IE          BIT(3)
 142#define NPCM7XX_SMBFIF_CTS_RXF_TXE          BIT(1)
 143/* TXF_CTL fields */
 144#define NPCM7XX_SMBTXF_CTL_THR_TXIE         BIT(6)
 145#define NPCM7XX_SMBTXF_CTL_TX_THR(rv)       extract8((rv), 0, 5)
 146/* T_OUT fields */
 147#define NPCM7XX_SMBT_OUT_ST                 BIT(7)
 148#define NPCM7XX_SMBT_OUT_IE                 BIT(6)
 149#define NPCM7XX_SMBT_OUT_CLKDIV(rv)         extract8((rv), 0, 6)
 150/* TXF_STS fields */
 151#define NPCM7XX_SMBTXF_STS_TX_THST          BIT(6)
 152#define NPCM7XX_SMBTXF_STS_TX_BYTES(rv)     extract8((rv), 0, 5)
 153/* RXF_STS fields */
 154#define NPCM7XX_SMBRXF_STS_RX_THST          BIT(6)
 155#define NPCM7XX_SMBRXF_STS_RX_BYTES(rv)     extract8((rv), 0, 5)
 156/* RXF_CTL fields */
 157#define NPCM7XX_SMBRXF_CTL_THR_RXIE         BIT(6)
 158#define NPCM7XX_SMBRXF_CTL_LAST             BIT(5)
 159#define NPCM7XX_SMBRXF_CTL_RX_THR(rv)       extract8((rv), 0, 5)
 160
 161#define KEEP_OLD_BIT(o, n, b)       (((n) & (~(b))) | ((o) & (b)))
 162#define WRITE_ONE_CLEAR(o, n, b)    ((n) & (b) ? (o) & (~(b)) : (o))
 163
 164#define NPCM7XX_SMBUS_ENABLED(s)    ((s)->ctl2 & NPCM7XX_SMBCTL2_ENABLE)
 165#define NPCM7XX_SMBUS_FIFO_ENABLED(s) ((s)->fif_ctl & \
 166                                       NPCM7XX_SMBFIF_CTL_FIFO_EN)
 167
 168/* VERSION fields values, read-only. */
 169#define NPCM7XX_SMBUS_VERSION_NUMBER 1
 170#define NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED 1
 171
 172/* Reset values */
 173#define NPCM7XX_SMB_ST_INIT_VAL     0x00
 174#define NPCM7XX_SMB_CST_INIT_VAL    0x10
 175#define NPCM7XX_SMB_CST2_INIT_VAL   0x00
 176#define NPCM7XX_SMB_CST3_INIT_VAL   0x00
 177#define NPCM7XX_SMB_CTL1_INIT_VAL   0x00
 178#define NPCM7XX_SMB_CTL2_INIT_VAL   0x00
 179#define NPCM7XX_SMB_CTL3_INIT_VAL   0xc0
 180#define NPCM7XX_SMB_CTL4_INIT_VAL   0x07
 181#define NPCM7XX_SMB_CTL5_INIT_VAL   0x00
 182#define NPCM7XX_SMB_ADDR_INIT_VAL   0x00
 183#define NPCM7XX_SMB_SCLLT_INIT_VAL  0x00
 184#define NPCM7XX_SMB_SCLHT_INIT_VAL  0x00
 185#define NPCM7XX_SMB_FIF_CTL_INIT_VAL 0x00
 186#define NPCM7XX_SMB_FIF_CTS_INIT_VAL 0x00
 187#define NPCM7XX_SMB_FAIR_PER_INIT_VAL 0x00
 188#define NPCM7XX_SMB_TXF_CTL_INIT_VAL 0x00
 189#define NPCM7XX_SMB_T_OUT_INIT_VAL 0x3f
 190#define NPCM7XX_SMB_TXF_STS_INIT_VAL 0x00
 191#define NPCM7XX_SMB_RXF_STS_INIT_VAL 0x00
 192#define NPCM7XX_SMB_RXF_CTL_INIT_VAL 0x01
 193
 194static uint8_t npcm7xx_smbus_get_version(void)
 195{
 196    return NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED << 7 |
 197           NPCM7XX_SMBUS_VERSION_NUMBER;
 198}
 199
 200static void npcm7xx_smbus_update_irq(NPCM7xxSMBusState *s)
 201{
 202    int level;
 203
 204    if (s->ctl1 & NPCM7XX_SMBCTL1_INTEN) {
 205        level = !!((s->ctl1 & NPCM7XX_SMBCTL1_NMINTE &&
 206                    s->st & NPCM7XX_SMBST_NMATCH) ||
 207                   (s->st & NPCM7XX_SMBST_BER) ||
 208                   (s->st & NPCM7XX_SMBST_NEGACK) ||
 209                   (s->st & NPCM7XX_SMBST_SDAST) ||
 210                   (s->ctl1 & NPCM7XX_SMBCTL1_STASTRE &&
 211                    s->st & NPCM7XX_SMBST_SDAST) ||
 212                   (s->ctl1 & NPCM7XX_SMBCTL1_EOBINTE &&
 213                    s->cst3 & NPCM7XX_SMBCST3_EO_BUSY) ||
 214                   (s->rxf_ctl & NPCM7XX_SMBRXF_CTL_THR_RXIE &&
 215                    s->rxf_sts & NPCM7XX_SMBRXF_STS_RX_THST) ||
 216                   (s->txf_ctl & NPCM7XX_SMBTXF_CTL_THR_TXIE &&
 217                    s->txf_sts & NPCM7XX_SMBTXF_STS_TX_THST) ||
 218                   (s->fif_cts & NPCM7XX_SMBFIF_CTS_RFTE_IE &&
 219                    s->fif_cts & NPCM7XX_SMBFIF_CTS_RXF_TXE));
 220
 221        if (level) {
 222            s->cst2 |= NPCM7XX_SMBCST2_INTSTS;
 223        } else {
 224            s->cst2 &= ~NPCM7XX_SMBCST2_INTSTS;
 225        }
 226        qemu_set_irq(s->irq, level);
 227    }
 228}
 229
 230static void npcm7xx_smbus_nack(NPCM7xxSMBusState *s)
 231{
 232    s->st &= ~NPCM7XX_SMBST_SDAST;
 233    s->st |= NPCM7XX_SMBST_NEGACK;
 234    s->status = NPCM7XX_SMBUS_STATUS_NEGACK;
 235}
 236
 237static void npcm7xx_smbus_clear_buffer(NPCM7xxSMBusState *s)
 238{
 239    s->fif_cts &= ~NPCM7XX_SMBFIF_CTS_RXF_TXE;
 240    s->txf_sts = 0;
 241    s->rxf_sts = 0;
 242}
 243
 244static void npcm7xx_smbus_send_byte(NPCM7xxSMBusState *s, uint8_t value)
 245{
 246    int rv = i2c_send(s->bus, value);
 247
 248    if (rv) {
 249        npcm7xx_smbus_nack(s);
 250    } else {
 251        s->st |= NPCM7XX_SMBST_SDAST;
 252        if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
 253            s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
 254            if (NPCM7XX_SMBTXF_STS_TX_BYTES(s->txf_sts) ==
 255                NPCM7XX_SMBTXF_CTL_TX_THR(s->txf_ctl)) {
 256                s->txf_sts = NPCM7XX_SMBTXF_STS_TX_THST;
 257            } else {
 258                s->txf_sts = 0;
 259            }
 260        }
 261    }
 262    trace_npcm7xx_smbus_send_byte((DEVICE(s)->canonical_path), value, !rv);
 263    npcm7xx_smbus_update_irq(s);
 264}
 265
 266static void npcm7xx_smbus_recv_byte(NPCM7xxSMBusState *s)
 267{
 268    s->sda = i2c_recv(s->bus);
 269    s->st |= NPCM7XX_SMBST_SDAST;
 270    if (s->st & NPCM7XX_SMBCTL1_ACK) {
 271        trace_npcm7xx_smbus_nack(DEVICE(s)->canonical_path);
 272        i2c_nack(s->bus);
 273        s->st &= NPCM7XX_SMBCTL1_ACK;
 274    }
 275    trace_npcm7xx_smbus_recv_byte((DEVICE(s)->canonical_path), s->sda);
 276    npcm7xx_smbus_update_irq(s);
 277}
 278
 279static void npcm7xx_smbus_recv_fifo(NPCM7xxSMBusState *s)
 280{
 281    uint8_t expected_bytes = NPCM7XX_SMBRXF_CTL_RX_THR(s->rxf_ctl);
 282    uint8_t received_bytes = NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts);
 283    uint8_t pos;
 284
 285    if (received_bytes == expected_bytes) {
 286        return;
 287    }
 288
 289    while (received_bytes < expected_bytes &&
 290           received_bytes < NPCM7XX_SMBUS_FIFO_SIZE) {
 291        pos = (s->rx_cur + received_bytes) % NPCM7XX_SMBUS_FIFO_SIZE;
 292        s->rx_fifo[pos] = i2c_recv(s->bus);
 293        trace_npcm7xx_smbus_recv_byte((DEVICE(s)->canonical_path),
 294                                      s->rx_fifo[pos]);
 295        ++received_bytes;
 296    }
 297
 298    trace_npcm7xx_smbus_recv_fifo((DEVICE(s)->canonical_path),
 299                                  received_bytes, expected_bytes);
 300    s->rxf_sts = received_bytes;
 301    if (unlikely(received_bytes < expected_bytes)) {
 302        qemu_log_mask(LOG_GUEST_ERROR,
 303                      "%s: invalid rx_thr value: 0x%02x\n",
 304                      DEVICE(s)->canonical_path, expected_bytes);
 305        return;
 306    }
 307
 308    s->rxf_sts |= NPCM7XX_SMBRXF_STS_RX_THST;
 309    if (s->rxf_ctl & NPCM7XX_SMBRXF_CTL_LAST) {
 310        trace_npcm7xx_smbus_nack(DEVICE(s)->canonical_path);
 311        i2c_nack(s->bus);
 312        s->rxf_ctl &= ~NPCM7XX_SMBRXF_CTL_LAST;
 313    }
 314    if (received_bytes == NPCM7XX_SMBUS_FIFO_SIZE) {
 315        s->st |= NPCM7XX_SMBST_SDAST;
 316        s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
 317    } else if (!(s->rxf_ctl & NPCM7XX_SMBRXF_CTL_THR_RXIE)) {
 318        s->st |= NPCM7XX_SMBST_SDAST;
 319    } else {
 320        s->st &= ~NPCM7XX_SMBST_SDAST;
 321    }
 322    npcm7xx_smbus_update_irq(s);
 323}
 324
 325static void npcm7xx_smbus_read_byte_fifo(NPCM7xxSMBusState *s)
 326{
 327    uint8_t received_bytes = NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts);
 328
 329    if (received_bytes == 0) {
 330        npcm7xx_smbus_recv_fifo(s);
 331        return;
 332    }
 333
 334    s->sda = s->rx_fifo[s->rx_cur];
 335    s->rx_cur = (s->rx_cur + 1u) % NPCM7XX_SMBUS_FIFO_SIZE;
 336    --s->rxf_sts;
 337    npcm7xx_smbus_update_irq(s);
 338}
 339
 340static void npcm7xx_smbus_start(NPCM7xxSMBusState *s)
 341{
 342    /*
 343     * We can start the bus if one of these is true:
 344     * 1. The bus is idle (so we can request it)
 345     * 2. We are the occupier (it's a repeated start condition.)
 346     */
 347    int available = !i2c_bus_busy(s->bus) ||
 348                    s->status != NPCM7XX_SMBUS_STATUS_IDLE;
 349
 350    if (available) {
 351        s->st |= NPCM7XX_SMBST_MODE | NPCM7XX_SMBST_XMIT | NPCM7XX_SMBST_SDAST;
 352        s->cst |= NPCM7XX_SMBCST_BUSY;
 353        if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
 354            s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
 355        }
 356    } else {
 357        s->st &= ~NPCM7XX_SMBST_MODE;
 358        s->cst &= ~NPCM7XX_SMBCST_BUSY;
 359        s->st |= NPCM7XX_SMBST_BER;
 360    }
 361
 362    trace_npcm7xx_smbus_start(DEVICE(s)->canonical_path, available);
 363    s->cst |= NPCM7XX_SMBCST_BB;
 364    s->status = NPCM7XX_SMBUS_STATUS_IDLE;
 365    npcm7xx_smbus_update_irq(s);
 366}
 367
 368static void npcm7xx_smbus_send_address(NPCM7xxSMBusState *s, uint8_t value)
 369{
 370    int recv;
 371    int rv;
 372
 373    recv = value & BIT(0);
 374    rv = i2c_start_transfer(s->bus, value >> 1, recv);
 375    trace_npcm7xx_smbus_send_address(DEVICE(s)->canonical_path,
 376                                     value >> 1, recv, !rv);
 377    if (rv) {
 378        qemu_log_mask(LOG_GUEST_ERROR,
 379                      "%s: requesting i2c bus for 0x%02x failed: %d\n",
 380                      DEVICE(s)->canonical_path, value, rv);
 381        /* Failed to start transfer. NACK to reject.*/
 382        if (recv) {
 383            s->st &= ~NPCM7XX_SMBST_XMIT;
 384        } else {
 385            s->st |= NPCM7XX_SMBST_XMIT;
 386        }
 387        npcm7xx_smbus_nack(s);
 388        npcm7xx_smbus_update_irq(s);
 389        return;
 390    }
 391
 392    s->st &= ~NPCM7XX_SMBST_NEGACK;
 393    if (recv) {
 394        s->status = NPCM7XX_SMBUS_STATUS_RECEIVING;
 395        s->st &= ~NPCM7XX_SMBST_XMIT;
 396    } else {
 397        s->status = NPCM7XX_SMBUS_STATUS_SENDING;
 398        s->st |= NPCM7XX_SMBST_XMIT;
 399    }
 400
 401    if (s->ctl1 & NPCM7XX_SMBCTL1_STASTRE) {
 402        s->st |= NPCM7XX_SMBST_STASTR;
 403        if (!recv) {
 404            s->st |= NPCM7XX_SMBST_SDAST;
 405        }
 406    } else if (recv) {
 407        s->st |= NPCM7XX_SMBST_SDAST;
 408        if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
 409            npcm7xx_smbus_recv_fifo(s);
 410        } else {
 411            npcm7xx_smbus_recv_byte(s);
 412        }
 413    } else if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
 414        s->st |= NPCM7XX_SMBST_SDAST;
 415        s->fif_cts |= NPCM7XX_SMBFIF_CTS_RXF_TXE;
 416    }
 417    npcm7xx_smbus_update_irq(s);
 418}
 419
 420static void npcm7xx_smbus_execute_stop(NPCM7xxSMBusState *s)
 421{
 422    i2c_end_transfer(s->bus);
 423    s->st = 0;
 424    s->cst = 0;
 425    s->status = NPCM7XX_SMBUS_STATUS_IDLE;
 426    s->cst3 |= NPCM7XX_SMBCST3_EO_BUSY;
 427    trace_npcm7xx_smbus_stop(DEVICE(s)->canonical_path);
 428    npcm7xx_smbus_update_irq(s);
 429}
 430
 431
 432static void npcm7xx_smbus_stop(NPCM7xxSMBusState *s)
 433{
 434    if (s->st & NPCM7XX_SMBST_MODE) {
 435        switch (s->status) {
 436        case NPCM7XX_SMBUS_STATUS_RECEIVING:
 437        case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
 438            s->status = NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE;
 439            break;
 440
 441        case NPCM7XX_SMBUS_STATUS_NEGACK:
 442            s->status = NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK;
 443            break;
 444
 445        default:
 446            npcm7xx_smbus_execute_stop(s);
 447            break;
 448        }
 449    }
 450}
 451
 452static uint8_t npcm7xx_smbus_read_sda(NPCM7xxSMBusState *s)
 453{
 454    uint8_t value = s->sda;
 455
 456    switch (s->status) {
 457    case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
 458        if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
 459            if (NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts) <= 1) {
 460                npcm7xx_smbus_execute_stop(s);
 461            }
 462            if (NPCM7XX_SMBRXF_STS_RX_BYTES(s->rxf_sts) == 0) {
 463                qemu_log_mask(LOG_GUEST_ERROR,
 464                              "%s: read to SDA with an empty rx-fifo buffer, "
 465                              "result undefined: %u\n",
 466                              DEVICE(s)->canonical_path, s->sda);
 467                break;
 468            }
 469            npcm7xx_smbus_read_byte_fifo(s);
 470            value = s->sda;
 471        } else {
 472            npcm7xx_smbus_execute_stop(s);
 473        }
 474        break;
 475
 476    case NPCM7XX_SMBUS_STATUS_RECEIVING:
 477        if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
 478            npcm7xx_smbus_read_byte_fifo(s);
 479            value = s->sda;
 480        } else {
 481            npcm7xx_smbus_recv_byte(s);
 482        }
 483        break;
 484
 485    default:
 486        /* Do nothing */
 487        break;
 488    }
 489
 490    return value;
 491}
 492
 493static void npcm7xx_smbus_write_sda(NPCM7xxSMBusState *s, uint8_t value)
 494{
 495    s->sda = value;
 496    if (s->st & NPCM7XX_SMBST_MODE) {
 497        switch (s->status) {
 498        case NPCM7XX_SMBUS_STATUS_IDLE:
 499            npcm7xx_smbus_send_address(s, value);
 500            break;
 501        case NPCM7XX_SMBUS_STATUS_SENDING:
 502            npcm7xx_smbus_send_byte(s, value);
 503            break;
 504        default:
 505            qemu_log_mask(LOG_GUEST_ERROR,
 506                          "%s: write to SDA in invalid status %d: %u\n",
 507                          DEVICE(s)->canonical_path, s->status, value);
 508            break;
 509        }
 510    }
 511}
 512
 513static void npcm7xx_smbus_write_st(NPCM7xxSMBusState *s, uint8_t value)
 514{
 515    s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_STP);
 516    s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_BER);
 517    s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_STASTR);
 518    s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_NMATCH);
 519
 520    if (value & NPCM7XX_SMBST_NEGACK) {
 521        s->st &= ~NPCM7XX_SMBST_NEGACK;
 522        if (s->status == NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK) {
 523            npcm7xx_smbus_execute_stop(s);
 524        }
 525    }
 526
 527    if (value & NPCM7XX_SMBST_STASTR &&
 528        s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
 529        if (NPCM7XX_SMBUS_FIFO_ENABLED(s)) {
 530            npcm7xx_smbus_recv_fifo(s);
 531        } else {
 532            npcm7xx_smbus_recv_byte(s);
 533        }
 534    }
 535
 536    npcm7xx_smbus_update_irq(s);
 537}
 538
 539static void npcm7xx_smbus_write_cst(NPCM7xxSMBusState *s, uint8_t value)
 540{
 541    uint8_t new_value = s->cst;
 542
 543    s->cst = WRITE_ONE_CLEAR(new_value, value, NPCM7XX_SMBCST_BB);
 544    npcm7xx_smbus_update_irq(s);
 545}
 546
 547static void npcm7xx_smbus_write_cst3(NPCM7xxSMBusState *s, uint8_t value)
 548{
 549    s->cst3 = WRITE_ONE_CLEAR(s->cst3, value, NPCM7XX_SMBCST3_EO_BUSY);
 550    npcm7xx_smbus_update_irq(s);
 551}
 552
 553static void npcm7xx_smbus_write_ctl1(NPCM7xxSMBusState *s, uint8_t value)
 554{
 555    s->ctl1 = KEEP_OLD_BIT(s->ctl1, value,
 556            NPCM7XX_SMBCTL1_START | NPCM7XX_SMBCTL1_STOP | NPCM7XX_SMBCTL1_ACK);
 557
 558    if (value & NPCM7XX_SMBCTL1_START) {
 559        npcm7xx_smbus_start(s);
 560    }
 561
 562    if (value & NPCM7XX_SMBCTL1_STOP) {
 563        npcm7xx_smbus_stop(s);
 564    }
 565
 566    npcm7xx_smbus_update_irq(s);
 567}
 568
 569static void npcm7xx_smbus_write_ctl2(NPCM7xxSMBusState *s, uint8_t value)
 570{
 571    s->ctl2 = value;
 572
 573    if (!NPCM7XX_SMBUS_ENABLED(s)) {
 574        /* Disable this SMBus module. */
 575        s->ctl1 = 0;
 576        s->st = 0;
 577        s->cst3 = s->cst3 & (~NPCM7XX_SMBCST3_EO_BUSY);
 578        s->cst = 0;
 579        npcm7xx_smbus_clear_buffer(s);
 580    }
 581}
 582
 583static void npcm7xx_smbus_write_ctl3(NPCM7xxSMBusState *s, uint8_t value)
 584{
 585    uint8_t old_ctl3 = s->ctl3;
 586
 587    /* Write to SDA and SCL bits are ignored. */
 588    s->ctl3 =  KEEP_OLD_BIT(old_ctl3, value,
 589                            NPCM7XX_SMBCTL3_SCL_LVL | NPCM7XX_SMBCTL3_SDA_LVL);
 590}
 591
 592static void npcm7xx_smbus_write_fif_ctl(NPCM7xxSMBusState *s, uint8_t value)
 593{
 594    uint8_t new_ctl = value;
 595
 596    new_ctl = KEEP_OLD_BIT(s->fif_ctl, new_ctl, NPCM7XX_SMBFIF_CTL_FAIR_RDY);
 597    new_ctl = WRITE_ONE_CLEAR(new_ctl, value, NPCM7XX_SMBFIF_CTL_FAIR_RDY);
 598    new_ctl = KEEP_OLD_BIT(s->fif_ctl, new_ctl, NPCM7XX_SMBFIF_CTL_FAIR_BUSY);
 599    s->fif_ctl = new_ctl;
 600}
 601
 602static void npcm7xx_smbus_write_fif_cts(NPCM7xxSMBusState *s, uint8_t value)
 603{
 604    s->fif_cts = WRITE_ONE_CLEAR(s->fif_cts, value, NPCM7XX_SMBFIF_CTS_STR);
 605    s->fif_cts = WRITE_ONE_CLEAR(s->fif_cts, value, NPCM7XX_SMBFIF_CTS_RXF_TXE);
 606    s->fif_cts = KEEP_OLD_BIT(value, s->fif_cts, NPCM7XX_SMBFIF_CTS_RFTE_IE);
 607
 608    if (value & NPCM7XX_SMBFIF_CTS_CLR_FIFO) {
 609        npcm7xx_smbus_clear_buffer(s);
 610    }
 611}
 612
 613static void npcm7xx_smbus_write_txf_ctl(NPCM7xxSMBusState *s, uint8_t value)
 614{
 615    s->txf_ctl = value;
 616}
 617
 618static void npcm7xx_smbus_write_t_out(NPCM7xxSMBusState *s, uint8_t value)
 619{
 620    uint8_t new_t_out = value;
 621
 622    if ((value & NPCM7XX_SMBT_OUT_ST) || (!(s->t_out & NPCM7XX_SMBT_OUT_ST))) {
 623        new_t_out &= ~NPCM7XX_SMBT_OUT_ST;
 624    } else {
 625        new_t_out |= NPCM7XX_SMBT_OUT_ST;
 626    }
 627
 628    s->t_out = new_t_out;
 629}
 630
 631static void npcm7xx_smbus_write_txf_sts(NPCM7xxSMBusState *s, uint8_t value)
 632{
 633    s->txf_sts = WRITE_ONE_CLEAR(s->txf_sts, value, NPCM7XX_SMBTXF_STS_TX_THST);
 634}
 635
 636static void npcm7xx_smbus_write_rxf_sts(NPCM7xxSMBusState *s, uint8_t value)
 637{
 638    if (value & NPCM7XX_SMBRXF_STS_RX_THST) {
 639        s->rxf_sts &= ~NPCM7XX_SMBRXF_STS_RX_THST;
 640        if (s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
 641            npcm7xx_smbus_recv_fifo(s);
 642        }
 643    }
 644}
 645
 646static void npcm7xx_smbus_write_rxf_ctl(NPCM7xxSMBusState *s, uint8_t value)
 647{
 648    uint8_t new_ctl = value;
 649
 650    if (!(value & NPCM7XX_SMBRXF_CTL_LAST)) {
 651        new_ctl = KEEP_OLD_BIT(s->rxf_ctl, new_ctl, NPCM7XX_SMBRXF_CTL_LAST);
 652    }
 653    s->rxf_ctl = new_ctl;
 654}
 655
 656static uint64_t npcm7xx_smbus_read(void *opaque, hwaddr offset, unsigned size)
 657{
 658    NPCM7xxSMBusState *s = opaque;
 659    uint64_t value = 0;
 660    uint8_t bank = s->ctl3 & NPCM7XX_SMBCTL3_BNK_SEL;
 661
 662    /* The order of the registers are their order in memory. */
 663    switch (offset) {
 664    case NPCM7XX_SMB_SDA:
 665        value = npcm7xx_smbus_read_sda(s);
 666        break;
 667
 668    case NPCM7XX_SMB_ST:
 669        value = s->st;
 670        break;
 671
 672    case NPCM7XX_SMB_CST:
 673        value = s->cst;
 674        break;
 675
 676    case NPCM7XX_SMB_CTL1:
 677        value = s->ctl1;
 678        break;
 679
 680    case NPCM7XX_SMB_ADDR1:
 681        value = s->addr[0];
 682        break;
 683
 684    case NPCM7XX_SMB_CTL2:
 685        value = s->ctl2;
 686        break;
 687
 688    case NPCM7XX_SMB_ADDR2:
 689        value = s->addr[1];
 690        break;
 691
 692    case NPCM7XX_SMB_CTL3:
 693        value = s->ctl3;
 694        break;
 695
 696    case NPCM7XX_SMB_CST2:
 697        value = s->cst2;
 698        break;
 699
 700    case NPCM7XX_SMB_CST3:
 701        value = s->cst3;
 702        break;
 703
 704    case NPCM7XX_SMB_VER:
 705        value = npcm7xx_smbus_get_version();
 706        break;
 707
 708    /* This register is either invalid or banked at this point. */
 709    default:
 710        if (bank) {
 711            /* Bank 1 */
 712            switch (offset) {
 713            case NPCM7XX_SMB_FIF_CTS:
 714                value = s->fif_cts;
 715                break;
 716
 717            case NPCM7XX_SMB_FAIR_PER:
 718                value = s->fair_per;
 719                break;
 720
 721            case NPCM7XX_SMB_TXF_CTL:
 722                value = s->txf_ctl;
 723                break;
 724
 725            case NPCM7XX_SMB_T_OUT:
 726                value = s->t_out;
 727                break;
 728
 729            case NPCM7XX_SMB_TXF_STS:
 730                value = s->txf_sts;
 731                break;
 732
 733            case NPCM7XX_SMB_RXF_STS:
 734                value = s->rxf_sts;
 735                break;
 736
 737            case NPCM7XX_SMB_RXF_CTL:
 738                value = s->rxf_ctl;
 739                break;
 740
 741            default:
 742                qemu_log_mask(LOG_GUEST_ERROR,
 743                        "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
 744                        DEVICE(s)->canonical_path, offset);
 745                break;
 746            }
 747        } else {
 748            /* Bank 0 */
 749            switch (offset) {
 750            case NPCM7XX_SMB_ADDR3:
 751                value = s->addr[2];
 752                break;
 753
 754            case NPCM7XX_SMB_ADDR7:
 755                value = s->addr[6];
 756                break;
 757
 758            case NPCM7XX_SMB_ADDR4:
 759                value = s->addr[3];
 760                break;
 761
 762            case NPCM7XX_SMB_ADDR8:
 763                value = s->addr[7];
 764                break;
 765
 766            case NPCM7XX_SMB_ADDR5:
 767                value = s->addr[4];
 768                break;
 769
 770            case NPCM7XX_SMB_ADDR9:
 771                value = s->addr[8];
 772                break;
 773
 774            case NPCM7XX_SMB_ADDR6:
 775                value = s->addr[5];
 776                break;
 777
 778            case NPCM7XX_SMB_ADDR10:
 779                value = s->addr[9];
 780                break;
 781
 782            case NPCM7XX_SMB_CTL4:
 783                value = s->ctl4;
 784                break;
 785
 786            case NPCM7XX_SMB_CTL5:
 787                value = s->ctl5;
 788                break;
 789
 790            case NPCM7XX_SMB_SCLLT:
 791                value = s->scllt;
 792                break;
 793
 794            case NPCM7XX_SMB_FIF_CTL:
 795                value = s->fif_ctl;
 796                break;
 797
 798            case NPCM7XX_SMB_SCLHT:
 799                value = s->sclht;
 800                break;
 801
 802            default:
 803                qemu_log_mask(LOG_GUEST_ERROR,
 804                        "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
 805                        DEVICE(s)->canonical_path, offset);
 806                break;
 807            }
 808        }
 809        break;
 810    }
 811
 812    trace_npcm7xx_smbus_read(DEVICE(s)->canonical_path, offset, value, size);
 813
 814    return value;
 815}
 816
 817static void npcm7xx_smbus_write(void *opaque, hwaddr offset, uint64_t value,
 818                              unsigned size)
 819{
 820    NPCM7xxSMBusState *s = opaque;
 821    uint8_t bank = s->ctl3 & NPCM7XX_SMBCTL3_BNK_SEL;
 822
 823    trace_npcm7xx_smbus_write(DEVICE(s)->canonical_path, offset, value, size);
 824
 825    /* The order of the registers are their order in memory. */
 826    switch (offset) {
 827    case NPCM7XX_SMB_SDA:
 828        npcm7xx_smbus_write_sda(s, value);
 829        break;
 830
 831    case NPCM7XX_SMB_ST:
 832        npcm7xx_smbus_write_st(s, value);
 833        break;
 834
 835    case NPCM7XX_SMB_CST:
 836        npcm7xx_smbus_write_cst(s, value);
 837        break;
 838
 839    case NPCM7XX_SMB_CTL1:
 840        npcm7xx_smbus_write_ctl1(s, value);
 841        break;
 842
 843    case NPCM7XX_SMB_ADDR1:
 844        s->addr[0] = value;
 845        break;
 846
 847    case NPCM7XX_SMB_CTL2:
 848        npcm7xx_smbus_write_ctl2(s, value);
 849        break;
 850
 851    case NPCM7XX_SMB_ADDR2:
 852        s->addr[1] = value;
 853        break;
 854
 855    case NPCM7XX_SMB_CTL3:
 856        npcm7xx_smbus_write_ctl3(s, value);
 857        break;
 858
 859    case NPCM7XX_SMB_CST2:
 860        qemu_log_mask(LOG_GUEST_ERROR,
 861                "%s: write to read-only reg: offset 0x%" HWADDR_PRIx "\n",
 862                DEVICE(s)->canonical_path, offset);
 863        break;
 864
 865    case NPCM7XX_SMB_CST3:
 866        npcm7xx_smbus_write_cst3(s, value);
 867        break;
 868
 869    case NPCM7XX_SMB_VER:
 870        qemu_log_mask(LOG_GUEST_ERROR,
 871                "%s: write to read-only reg: offset 0x%" HWADDR_PRIx "\n",
 872                DEVICE(s)->canonical_path, offset);
 873        break;
 874
 875    /* This register is either invalid or banked at this point. */
 876    default:
 877        if (bank) {
 878            /* Bank 1 */
 879            switch (offset) {
 880            case NPCM7XX_SMB_FIF_CTS:
 881                npcm7xx_smbus_write_fif_cts(s, value);
 882                break;
 883
 884            case NPCM7XX_SMB_FAIR_PER:
 885                s->fair_per = value;
 886                break;
 887
 888            case NPCM7XX_SMB_TXF_CTL:
 889                npcm7xx_smbus_write_txf_ctl(s, value);
 890                break;
 891
 892            case NPCM7XX_SMB_T_OUT:
 893                npcm7xx_smbus_write_t_out(s, value);
 894                break;
 895
 896            case NPCM7XX_SMB_TXF_STS:
 897                npcm7xx_smbus_write_txf_sts(s, value);
 898                break;
 899
 900            case NPCM7XX_SMB_RXF_STS:
 901                npcm7xx_smbus_write_rxf_sts(s, value);
 902                break;
 903
 904            case NPCM7XX_SMB_RXF_CTL:
 905                npcm7xx_smbus_write_rxf_ctl(s, value);
 906                break;
 907
 908            default:
 909                qemu_log_mask(LOG_GUEST_ERROR,
 910                        "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
 911                        DEVICE(s)->canonical_path, offset);
 912                break;
 913            }
 914        } else {
 915            /* Bank 0 */
 916            switch (offset) {
 917            case NPCM7XX_SMB_ADDR3:
 918                s->addr[2] = value;
 919                break;
 920
 921            case NPCM7XX_SMB_ADDR7:
 922                s->addr[6] = value;
 923                break;
 924
 925            case NPCM7XX_SMB_ADDR4:
 926                s->addr[3] = value;
 927                break;
 928
 929            case NPCM7XX_SMB_ADDR8:
 930                s->addr[7] = value;
 931                break;
 932
 933            case NPCM7XX_SMB_ADDR5:
 934                s->addr[4] = value;
 935                break;
 936
 937            case NPCM7XX_SMB_ADDR9:
 938                s->addr[8] = value;
 939                break;
 940
 941            case NPCM7XX_SMB_ADDR6:
 942                s->addr[5] = value;
 943                break;
 944
 945            case NPCM7XX_SMB_ADDR10:
 946                s->addr[9] = value;
 947                break;
 948
 949            case NPCM7XX_SMB_CTL4:
 950                s->ctl4 = value;
 951                break;
 952
 953            case NPCM7XX_SMB_CTL5:
 954                s->ctl5 = value;
 955                break;
 956
 957            case NPCM7XX_SMB_SCLLT:
 958                s->scllt = value;
 959                break;
 960
 961            case NPCM7XX_SMB_FIF_CTL:
 962                npcm7xx_smbus_write_fif_ctl(s, value);
 963                break;
 964
 965            case NPCM7XX_SMB_SCLHT:
 966                s->sclht = value;
 967                break;
 968
 969            default:
 970                qemu_log_mask(LOG_GUEST_ERROR,
 971                        "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
 972                        DEVICE(s)->canonical_path, offset);
 973                break;
 974            }
 975        }
 976        break;
 977    }
 978}
 979
 980static const MemoryRegionOps npcm7xx_smbus_ops = {
 981    .read = npcm7xx_smbus_read,
 982    .write = npcm7xx_smbus_write,
 983    .endianness = DEVICE_LITTLE_ENDIAN,
 984    .valid = {
 985        .min_access_size = 1,
 986        .max_access_size = 1,
 987        .unaligned = false,
 988    },
 989};
 990
 991static void npcm7xx_smbus_enter_reset(Object *obj, ResetType type)
 992{
 993    NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
 994
 995    s->st = NPCM7XX_SMB_ST_INIT_VAL;
 996    s->cst = NPCM7XX_SMB_CST_INIT_VAL;
 997    s->cst2 = NPCM7XX_SMB_CST2_INIT_VAL;
 998    s->cst3 = NPCM7XX_SMB_CST3_INIT_VAL;
 999    s->ctl1 = NPCM7XX_SMB_CTL1_INIT_VAL;
1000    s->ctl2 = NPCM7XX_SMB_CTL2_INIT_VAL;
1001    s->ctl3 = NPCM7XX_SMB_CTL3_INIT_VAL;
1002    s->ctl4 = NPCM7XX_SMB_CTL4_INIT_VAL;
1003    s->ctl5 = NPCM7XX_SMB_CTL5_INIT_VAL;
1004
1005    for (int i = 0; i < NPCM7XX_SMBUS_NR_ADDRS; ++i) {
1006        s->addr[i] = NPCM7XX_SMB_ADDR_INIT_VAL;
1007    }
1008    s->scllt = NPCM7XX_SMB_SCLLT_INIT_VAL;
1009    s->sclht = NPCM7XX_SMB_SCLHT_INIT_VAL;
1010
1011    s->fif_ctl = NPCM7XX_SMB_FIF_CTL_INIT_VAL;
1012    s->fif_cts = NPCM7XX_SMB_FIF_CTS_INIT_VAL;
1013    s->fair_per = NPCM7XX_SMB_FAIR_PER_INIT_VAL;
1014    s->txf_ctl = NPCM7XX_SMB_TXF_CTL_INIT_VAL;
1015    s->t_out = NPCM7XX_SMB_T_OUT_INIT_VAL;
1016    s->txf_sts = NPCM7XX_SMB_TXF_STS_INIT_VAL;
1017    s->rxf_sts = NPCM7XX_SMB_RXF_STS_INIT_VAL;
1018    s->rxf_ctl = NPCM7XX_SMB_RXF_CTL_INIT_VAL;
1019
1020    npcm7xx_smbus_clear_buffer(s);
1021    s->status = NPCM7XX_SMBUS_STATUS_IDLE;
1022    s->rx_cur = 0;
1023}
1024
1025static void npcm7xx_smbus_hold_reset(Object *obj)
1026{
1027    NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
1028
1029    qemu_irq_lower(s->irq);
1030}
1031
1032static void npcm7xx_smbus_init(Object *obj)
1033{
1034    NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
1035    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
1036
1037    sysbus_init_irq(sbd, &s->irq);
1038    memory_region_init_io(&s->iomem, obj, &npcm7xx_smbus_ops, s,
1039                          "regs", 4 * KiB);
1040    sysbus_init_mmio(sbd, &s->iomem);
1041
1042    s->bus = i2c_init_bus(DEVICE(s), "i2c-bus");
1043}
1044
1045static const VMStateDescription vmstate_npcm7xx_smbus = {
1046    .name = "npcm7xx-smbus",
1047    .version_id = 0,
1048    .minimum_version_id = 0,
1049    .fields = (VMStateField[]) {
1050        VMSTATE_UINT8(sda, NPCM7xxSMBusState),
1051        VMSTATE_UINT8(st, NPCM7xxSMBusState),
1052        VMSTATE_UINT8(cst, NPCM7xxSMBusState),
1053        VMSTATE_UINT8(cst2, NPCM7xxSMBusState),
1054        VMSTATE_UINT8(cst3, NPCM7xxSMBusState),
1055        VMSTATE_UINT8(ctl1, NPCM7xxSMBusState),
1056        VMSTATE_UINT8(ctl2, NPCM7xxSMBusState),
1057        VMSTATE_UINT8(ctl3, NPCM7xxSMBusState),
1058        VMSTATE_UINT8(ctl4, NPCM7xxSMBusState),
1059        VMSTATE_UINT8(ctl5, NPCM7xxSMBusState),
1060        VMSTATE_UINT8_ARRAY(addr, NPCM7xxSMBusState, NPCM7XX_SMBUS_NR_ADDRS),
1061        VMSTATE_UINT8(scllt, NPCM7xxSMBusState),
1062        VMSTATE_UINT8(sclht, NPCM7xxSMBusState),
1063        VMSTATE_UINT8(fif_ctl, NPCM7xxSMBusState),
1064        VMSTATE_UINT8(fif_cts, NPCM7xxSMBusState),
1065        VMSTATE_UINT8(fair_per, NPCM7xxSMBusState),
1066        VMSTATE_UINT8(txf_ctl, NPCM7xxSMBusState),
1067        VMSTATE_UINT8(t_out, NPCM7xxSMBusState),
1068        VMSTATE_UINT8(txf_sts, NPCM7xxSMBusState),
1069        VMSTATE_UINT8(rxf_sts, NPCM7xxSMBusState),
1070        VMSTATE_UINT8(rxf_ctl, NPCM7xxSMBusState),
1071        VMSTATE_UINT8_ARRAY(rx_fifo, NPCM7xxSMBusState,
1072                            NPCM7XX_SMBUS_FIFO_SIZE),
1073        VMSTATE_UINT8(rx_cur, NPCM7xxSMBusState),
1074        VMSTATE_END_OF_LIST(),
1075    },
1076};
1077
1078static void npcm7xx_smbus_class_init(ObjectClass *klass, void *data)
1079{
1080    ResettableClass *rc = RESETTABLE_CLASS(klass);
1081    DeviceClass *dc = DEVICE_CLASS(klass);
1082
1083    dc->desc = "NPCM7xx System Management Bus";
1084    dc->vmsd = &vmstate_npcm7xx_smbus;
1085    rc->phases.enter = npcm7xx_smbus_enter_reset;
1086    rc->phases.hold = npcm7xx_smbus_hold_reset;
1087}
1088
1089static const TypeInfo npcm7xx_smbus_types[] = {
1090    {
1091        .name = TYPE_NPCM7XX_SMBUS,
1092        .parent = TYPE_SYS_BUS_DEVICE,
1093        .instance_size = sizeof(NPCM7xxSMBusState),
1094        .class_init = npcm7xx_smbus_class_init,
1095        .instance_init = npcm7xx_smbus_init,
1096    },
1097};
1098DEFINE_TYPES(npcm7xx_smbus_types);
1099