xref: /qemu/hw/i2c/npcm7xx_smbus.c (revision 94e778793954afc6ed47ef8e161044c79488e446)
1*94e77879SHao Wu /*
2*94e77879SHao Wu  * Nuvoton NPCM7xx SMBus Module.
3*94e77879SHao Wu  *
4*94e77879SHao Wu  * Copyright 2020 Google LLC
5*94e77879SHao Wu  *
6*94e77879SHao Wu  * This program is free software; you can redistribute it and/or modify it
7*94e77879SHao Wu  * under the terms of the GNU General Public License as published by the
8*94e77879SHao Wu  * Free Software Foundation; either version 2 of the License, or
9*94e77879SHao Wu  * (at your option) any later version.
10*94e77879SHao Wu  *
11*94e77879SHao Wu  * This program is distributed in the hope that it will be useful, but WITHOUT
12*94e77879SHao Wu  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*94e77879SHao Wu  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14*94e77879SHao Wu  * for more details.
15*94e77879SHao Wu  */
16*94e77879SHao Wu 
17*94e77879SHao Wu #include "qemu/osdep.h"
18*94e77879SHao Wu 
19*94e77879SHao Wu #include "hw/i2c/npcm7xx_smbus.h"
20*94e77879SHao Wu #include "migration/vmstate.h"
21*94e77879SHao Wu #include "qemu/bitops.h"
22*94e77879SHao Wu #include "qemu/guest-random.h"
23*94e77879SHao Wu #include "qemu/log.h"
24*94e77879SHao Wu #include "qemu/module.h"
25*94e77879SHao Wu #include "qemu/units.h"
26*94e77879SHao Wu 
27*94e77879SHao Wu #include "trace.h"
28*94e77879SHao Wu 
29*94e77879SHao Wu enum NPCM7xxSMBusCommonRegister {
30*94e77879SHao Wu     NPCM7XX_SMB_SDA     = 0x0,
31*94e77879SHao Wu     NPCM7XX_SMB_ST      = 0x2,
32*94e77879SHao Wu     NPCM7XX_SMB_CST     = 0x4,
33*94e77879SHao Wu     NPCM7XX_SMB_CTL1    = 0x6,
34*94e77879SHao Wu     NPCM7XX_SMB_ADDR1   = 0x8,
35*94e77879SHao Wu     NPCM7XX_SMB_CTL2    = 0xa,
36*94e77879SHao Wu     NPCM7XX_SMB_ADDR2   = 0xc,
37*94e77879SHao Wu     NPCM7XX_SMB_CTL3    = 0xe,
38*94e77879SHao Wu     NPCM7XX_SMB_CST2    = 0x18,
39*94e77879SHao Wu     NPCM7XX_SMB_CST3    = 0x19,
40*94e77879SHao Wu     NPCM7XX_SMB_VER     = 0x1f,
41*94e77879SHao Wu };
42*94e77879SHao Wu 
43*94e77879SHao Wu enum NPCM7xxSMBusBank0Register {
44*94e77879SHao Wu     NPCM7XX_SMB_ADDR3   = 0x10,
45*94e77879SHao Wu     NPCM7XX_SMB_ADDR7   = 0x11,
46*94e77879SHao Wu     NPCM7XX_SMB_ADDR4   = 0x12,
47*94e77879SHao Wu     NPCM7XX_SMB_ADDR8   = 0x13,
48*94e77879SHao Wu     NPCM7XX_SMB_ADDR5   = 0x14,
49*94e77879SHao Wu     NPCM7XX_SMB_ADDR9   = 0x15,
50*94e77879SHao Wu     NPCM7XX_SMB_ADDR6   = 0x16,
51*94e77879SHao Wu     NPCM7XX_SMB_ADDR10  = 0x17,
52*94e77879SHao Wu     NPCM7XX_SMB_CTL4    = 0x1a,
53*94e77879SHao Wu     NPCM7XX_SMB_CTL5    = 0x1b,
54*94e77879SHao Wu     NPCM7XX_SMB_SCLLT   = 0x1c,
55*94e77879SHao Wu     NPCM7XX_SMB_FIF_CTL = 0x1d,
56*94e77879SHao Wu     NPCM7XX_SMB_SCLHT   = 0x1e,
57*94e77879SHao Wu };
58*94e77879SHao Wu 
59*94e77879SHao Wu enum NPCM7xxSMBusBank1Register {
60*94e77879SHao Wu     NPCM7XX_SMB_FIF_CTS  = 0x10,
61*94e77879SHao Wu     NPCM7XX_SMB_FAIR_PER = 0x11,
62*94e77879SHao Wu     NPCM7XX_SMB_TXF_CTL  = 0x12,
63*94e77879SHao Wu     NPCM7XX_SMB_T_OUT    = 0x14,
64*94e77879SHao Wu     NPCM7XX_SMB_TXF_STS  = 0x1a,
65*94e77879SHao Wu     NPCM7XX_SMB_RXF_STS  = 0x1c,
66*94e77879SHao Wu     NPCM7XX_SMB_RXF_CTL  = 0x1e,
67*94e77879SHao Wu };
68*94e77879SHao Wu 
69*94e77879SHao Wu /* ST fields */
70*94e77879SHao Wu #define NPCM7XX_SMBST_STP           BIT(7)
71*94e77879SHao Wu #define NPCM7XX_SMBST_SDAST         BIT(6)
72*94e77879SHao Wu #define NPCM7XX_SMBST_BER           BIT(5)
73*94e77879SHao Wu #define NPCM7XX_SMBST_NEGACK        BIT(4)
74*94e77879SHao Wu #define NPCM7XX_SMBST_STASTR        BIT(3)
75*94e77879SHao Wu #define NPCM7XX_SMBST_NMATCH        BIT(2)
76*94e77879SHao Wu #define NPCM7XX_SMBST_MODE          BIT(1)
77*94e77879SHao Wu #define NPCM7XX_SMBST_XMIT          BIT(0)
78*94e77879SHao Wu 
79*94e77879SHao Wu /* CST fields */
80*94e77879SHao Wu #define NPCM7XX_SMBCST_ARPMATCH        BIT(7)
81*94e77879SHao Wu #define NPCM7XX_SMBCST_MATCHAF         BIT(6)
82*94e77879SHao Wu #define NPCM7XX_SMBCST_TGSCL           BIT(5)
83*94e77879SHao Wu #define NPCM7XX_SMBCST_TSDA            BIT(4)
84*94e77879SHao Wu #define NPCM7XX_SMBCST_GCMATCH         BIT(3)
85*94e77879SHao Wu #define NPCM7XX_SMBCST_MATCH           BIT(2)
86*94e77879SHao Wu #define NPCM7XX_SMBCST_BB              BIT(1)
87*94e77879SHao Wu #define NPCM7XX_SMBCST_BUSY            BIT(0)
88*94e77879SHao Wu 
89*94e77879SHao Wu /* CST2 fields */
90*94e77879SHao Wu #define NPCM7XX_SMBCST2_INTSTS         BIT(7)
91*94e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH7F        BIT(6)
92*94e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH6F        BIT(5)
93*94e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH5F        BIT(4)
94*94e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH4F        BIT(3)
95*94e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH3F        BIT(2)
96*94e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH2F        BIT(1)
97*94e77879SHao Wu #define NPCM7XX_SMBCST2_MATCH1F        BIT(0)
98*94e77879SHao Wu 
99*94e77879SHao Wu /* CST3 fields */
100*94e77879SHao Wu #define NPCM7XX_SMBCST3_EO_BUSY        BIT(7)
101*94e77879SHao Wu #define NPCM7XX_SMBCST3_MATCH10F       BIT(2)
102*94e77879SHao Wu #define NPCM7XX_SMBCST3_MATCH9F        BIT(1)
103*94e77879SHao Wu #define NPCM7XX_SMBCST3_MATCH8F        BIT(0)
104*94e77879SHao Wu 
105*94e77879SHao Wu /* CTL1 fields */
106*94e77879SHao Wu #define NPCM7XX_SMBCTL1_STASTRE     BIT(7)
107*94e77879SHao Wu #define NPCM7XX_SMBCTL1_NMINTE      BIT(6)
108*94e77879SHao Wu #define NPCM7XX_SMBCTL1_GCMEN       BIT(5)
109*94e77879SHao Wu #define NPCM7XX_SMBCTL1_ACK         BIT(4)
110*94e77879SHao Wu #define NPCM7XX_SMBCTL1_EOBINTE     BIT(3)
111*94e77879SHao Wu #define NPCM7XX_SMBCTL1_INTEN       BIT(2)
112*94e77879SHao Wu #define NPCM7XX_SMBCTL1_STOP        BIT(1)
113*94e77879SHao Wu #define NPCM7XX_SMBCTL1_START       BIT(0)
114*94e77879SHao Wu 
115*94e77879SHao Wu /* CTL2 fields */
116*94e77879SHao Wu #define NPCM7XX_SMBCTL2_SCLFRQ(rv)  extract8((rv), 1, 6)
117*94e77879SHao Wu #define NPCM7XX_SMBCTL2_ENABLE      BIT(0)
118*94e77879SHao Wu 
119*94e77879SHao Wu /* CTL3 fields */
120*94e77879SHao Wu #define NPCM7XX_SMBCTL3_SCL_LVL     BIT(7)
121*94e77879SHao Wu #define NPCM7XX_SMBCTL3_SDA_LVL     BIT(6)
122*94e77879SHao Wu #define NPCM7XX_SMBCTL3_BNK_SEL     BIT(5)
123*94e77879SHao Wu #define NPCM7XX_SMBCTL3_400K_MODE   BIT(4)
124*94e77879SHao Wu #define NPCM7XX_SMBCTL3_IDL_START   BIT(3)
125*94e77879SHao Wu #define NPCM7XX_SMBCTL3_ARPMEN      BIT(2)
126*94e77879SHao Wu #define NPCM7XX_SMBCTL3_SCLFRQ(rv)  extract8((rv), 0, 2)
127*94e77879SHao Wu 
128*94e77879SHao Wu /* ADDR fields */
129*94e77879SHao Wu #define NPCM7XX_ADDR_EN             BIT(7)
130*94e77879SHao Wu #define NPCM7XX_ADDR_A(rv)          extract8((rv), 0, 6)
131*94e77879SHao Wu 
132*94e77879SHao Wu #define KEEP_OLD_BIT(o, n, b)       (((n) & (~(b))) | ((o) & (b)))
133*94e77879SHao Wu #define WRITE_ONE_CLEAR(o, n, b)    ((n) & (b) ? (o) & (~(b)) : (o))
134*94e77879SHao Wu 
135*94e77879SHao Wu #define NPCM7XX_SMBUS_ENABLED(s)    ((s)->ctl2 & NPCM7XX_SMBCTL2_ENABLE)
136*94e77879SHao Wu 
137*94e77879SHao Wu /* VERSION fields values, read-only. */
138*94e77879SHao Wu #define NPCM7XX_SMBUS_VERSION_NUMBER 1
139*94e77879SHao Wu #define NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED 0
140*94e77879SHao Wu 
141*94e77879SHao Wu /* Reset values */
142*94e77879SHao Wu #define NPCM7XX_SMB_ST_INIT_VAL     0x00
143*94e77879SHao Wu #define NPCM7XX_SMB_CST_INIT_VAL    0x10
144*94e77879SHao Wu #define NPCM7XX_SMB_CST2_INIT_VAL   0x00
145*94e77879SHao Wu #define NPCM7XX_SMB_CST3_INIT_VAL   0x00
146*94e77879SHao Wu #define NPCM7XX_SMB_CTL1_INIT_VAL   0x00
147*94e77879SHao Wu #define NPCM7XX_SMB_CTL2_INIT_VAL   0x00
148*94e77879SHao Wu #define NPCM7XX_SMB_CTL3_INIT_VAL   0xc0
149*94e77879SHao Wu #define NPCM7XX_SMB_CTL4_INIT_VAL   0x07
150*94e77879SHao Wu #define NPCM7XX_SMB_CTL5_INIT_VAL   0x00
151*94e77879SHao Wu #define NPCM7XX_SMB_ADDR_INIT_VAL   0x00
152*94e77879SHao Wu #define NPCM7XX_SMB_SCLLT_INIT_VAL  0x00
153*94e77879SHao Wu #define NPCM7XX_SMB_SCLHT_INIT_VAL  0x00
154*94e77879SHao Wu 
155*94e77879SHao Wu static uint8_t npcm7xx_smbus_get_version(void)
156*94e77879SHao Wu {
157*94e77879SHao Wu     return NPCM7XX_SMBUS_VERSION_FIFO_SUPPORTED << 7 |
158*94e77879SHao Wu            NPCM7XX_SMBUS_VERSION_NUMBER;
159*94e77879SHao Wu }
160*94e77879SHao Wu 
161*94e77879SHao Wu static void npcm7xx_smbus_update_irq(NPCM7xxSMBusState *s)
162*94e77879SHao Wu {
163*94e77879SHao Wu     int level;
164*94e77879SHao Wu 
165*94e77879SHao Wu     if (s->ctl1 & NPCM7XX_SMBCTL1_INTEN) {
166*94e77879SHao Wu         level = !!((s->ctl1 & NPCM7XX_SMBCTL1_NMINTE &&
167*94e77879SHao Wu                     s->st & NPCM7XX_SMBST_NMATCH) ||
168*94e77879SHao Wu                    (s->st & NPCM7XX_SMBST_BER) ||
169*94e77879SHao Wu                    (s->st & NPCM7XX_SMBST_NEGACK) ||
170*94e77879SHao Wu                    (s->st & NPCM7XX_SMBST_SDAST) ||
171*94e77879SHao Wu                    (s->ctl1 & NPCM7XX_SMBCTL1_STASTRE &&
172*94e77879SHao Wu                     s->st & NPCM7XX_SMBST_SDAST) ||
173*94e77879SHao Wu                    (s->ctl1 & NPCM7XX_SMBCTL1_EOBINTE &&
174*94e77879SHao Wu                     s->cst3 & NPCM7XX_SMBCST3_EO_BUSY));
175*94e77879SHao Wu 
176*94e77879SHao Wu         if (level) {
177*94e77879SHao Wu             s->cst2 |= NPCM7XX_SMBCST2_INTSTS;
178*94e77879SHao Wu         } else {
179*94e77879SHao Wu             s->cst2 &= ~NPCM7XX_SMBCST2_INTSTS;
180*94e77879SHao Wu         }
181*94e77879SHao Wu         qemu_set_irq(s->irq, level);
182*94e77879SHao Wu     }
183*94e77879SHao Wu }
184*94e77879SHao Wu 
185*94e77879SHao Wu static void npcm7xx_smbus_nack(NPCM7xxSMBusState *s)
186*94e77879SHao Wu {
187*94e77879SHao Wu     s->st &= ~NPCM7XX_SMBST_SDAST;
188*94e77879SHao Wu     s->st |= NPCM7XX_SMBST_NEGACK;
189*94e77879SHao Wu     s->status = NPCM7XX_SMBUS_STATUS_NEGACK;
190*94e77879SHao Wu }
191*94e77879SHao Wu 
192*94e77879SHao Wu static void npcm7xx_smbus_send_byte(NPCM7xxSMBusState *s, uint8_t value)
193*94e77879SHao Wu {
194*94e77879SHao Wu     int rv = i2c_send(s->bus, value);
195*94e77879SHao Wu 
196*94e77879SHao Wu     if (rv) {
197*94e77879SHao Wu         npcm7xx_smbus_nack(s);
198*94e77879SHao Wu     } else {
199*94e77879SHao Wu         s->st |= NPCM7XX_SMBST_SDAST;
200*94e77879SHao Wu     }
201*94e77879SHao Wu     trace_npcm7xx_smbus_send_byte((DEVICE(s)->canonical_path), value, !rv);
202*94e77879SHao Wu     npcm7xx_smbus_update_irq(s);
203*94e77879SHao Wu }
204*94e77879SHao Wu 
205*94e77879SHao Wu static void npcm7xx_smbus_recv_byte(NPCM7xxSMBusState *s)
206*94e77879SHao Wu {
207*94e77879SHao Wu     s->sda = i2c_recv(s->bus);
208*94e77879SHao Wu     s->st |= NPCM7XX_SMBST_SDAST;
209*94e77879SHao Wu     if (s->st & NPCM7XX_SMBCTL1_ACK) {
210*94e77879SHao Wu         trace_npcm7xx_smbus_nack(DEVICE(s)->canonical_path);
211*94e77879SHao Wu         i2c_nack(s->bus);
212*94e77879SHao Wu         s->st &= NPCM7XX_SMBCTL1_ACK;
213*94e77879SHao Wu     }
214*94e77879SHao Wu     trace_npcm7xx_smbus_recv_byte((DEVICE(s)->canonical_path), s->sda);
215*94e77879SHao Wu     npcm7xx_smbus_update_irq(s);
216*94e77879SHao Wu }
217*94e77879SHao Wu 
218*94e77879SHao Wu static void npcm7xx_smbus_start(NPCM7xxSMBusState *s)
219*94e77879SHao Wu {
220*94e77879SHao Wu     /*
221*94e77879SHao Wu      * We can start the bus if one of these is true:
222*94e77879SHao Wu      * 1. The bus is idle (so we can request it)
223*94e77879SHao Wu      * 2. We are the occupier (it's a repeated start condition.)
224*94e77879SHao Wu      */
225*94e77879SHao Wu     int available = !i2c_bus_busy(s->bus) ||
226*94e77879SHao Wu                     s->status != NPCM7XX_SMBUS_STATUS_IDLE;
227*94e77879SHao Wu 
228*94e77879SHao Wu     if (available) {
229*94e77879SHao Wu         s->st |= NPCM7XX_SMBST_MODE | NPCM7XX_SMBST_XMIT | NPCM7XX_SMBST_SDAST;
230*94e77879SHao Wu         s->cst |= NPCM7XX_SMBCST_BUSY;
231*94e77879SHao Wu     } else {
232*94e77879SHao Wu         s->st &= ~NPCM7XX_SMBST_MODE;
233*94e77879SHao Wu         s->cst &= ~NPCM7XX_SMBCST_BUSY;
234*94e77879SHao Wu         s->st |= NPCM7XX_SMBST_BER;
235*94e77879SHao Wu     }
236*94e77879SHao Wu 
237*94e77879SHao Wu     trace_npcm7xx_smbus_start(DEVICE(s)->canonical_path, available);
238*94e77879SHao Wu     s->cst |= NPCM7XX_SMBCST_BB;
239*94e77879SHao Wu     s->status = NPCM7XX_SMBUS_STATUS_IDLE;
240*94e77879SHao Wu     npcm7xx_smbus_update_irq(s);
241*94e77879SHao Wu }
242*94e77879SHao Wu 
243*94e77879SHao Wu static void npcm7xx_smbus_send_address(NPCM7xxSMBusState *s, uint8_t value)
244*94e77879SHao Wu {
245*94e77879SHao Wu     int recv;
246*94e77879SHao Wu     int rv;
247*94e77879SHao Wu 
248*94e77879SHao Wu     recv = value & BIT(0);
249*94e77879SHao Wu     rv = i2c_start_transfer(s->bus, value >> 1, recv);
250*94e77879SHao Wu     trace_npcm7xx_smbus_send_address(DEVICE(s)->canonical_path,
251*94e77879SHao Wu                                      value >> 1, recv, !rv);
252*94e77879SHao Wu     if (rv) {
253*94e77879SHao Wu         qemu_log_mask(LOG_GUEST_ERROR,
254*94e77879SHao Wu                       "%s: requesting i2c bus for 0x%02x failed: %d\n",
255*94e77879SHao Wu                       DEVICE(s)->canonical_path, value, rv);
256*94e77879SHao Wu         /* Failed to start transfer. NACK to reject.*/
257*94e77879SHao Wu         if (recv) {
258*94e77879SHao Wu             s->st &= ~NPCM7XX_SMBST_XMIT;
259*94e77879SHao Wu         } else {
260*94e77879SHao Wu             s->st |= NPCM7XX_SMBST_XMIT;
261*94e77879SHao Wu         }
262*94e77879SHao Wu         npcm7xx_smbus_nack(s);
263*94e77879SHao Wu         npcm7xx_smbus_update_irq(s);
264*94e77879SHao Wu         return;
265*94e77879SHao Wu     }
266*94e77879SHao Wu 
267*94e77879SHao Wu     s->st &= ~NPCM7XX_SMBST_NEGACK;
268*94e77879SHao Wu     if (recv) {
269*94e77879SHao Wu         s->status = NPCM7XX_SMBUS_STATUS_RECEIVING;
270*94e77879SHao Wu         s->st &= ~NPCM7XX_SMBST_XMIT;
271*94e77879SHao Wu     } else {
272*94e77879SHao Wu         s->status = NPCM7XX_SMBUS_STATUS_SENDING;
273*94e77879SHao Wu         s->st |= NPCM7XX_SMBST_XMIT;
274*94e77879SHao Wu     }
275*94e77879SHao Wu 
276*94e77879SHao Wu     if (s->ctl1 & NPCM7XX_SMBCTL1_STASTRE) {
277*94e77879SHao Wu         s->st |= NPCM7XX_SMBST_STASTR;
278*94e77879SHao Wu         if (!recv) {
279*94e77879SHao Wu             s->st |= NPCM7XX_SMBST_SDAST;
280*94e77879SHao Wu         }
281*94e77879SHao Wu     } else if (recv) {
282*94e77879SHao Wu         npcm7xx_smbus_recv_byte(s);
283*94e77879SHao Wu     }
284*94e77879SHao Wu     npcm7xx_smbus_update_irq(s);
285*94e77879SHao Wu }
286*94e77879SHao Wu 
287*94e77879SHao Wu static void npcm7xx_smbus_execute_stop(NPCM7xxSMBusState *s)
288*94e77879SHao Wu {
289*94e77879SHao Wu     i2c_end_transfer(s->bus);
290*94e77879SHao Wu     s->st = 0;
291*94e77879SHao Wu     s->cst = 0;
292*94e77879SHao Wu     s->status = NPCM7XX_SMBUS_STATUS_IDLE;
293*94e77879SHao Wu     s->cst3 |= NPCM7XX_SMBCST3_EO_BUSY;
294*94e77879SHao Wu     trace_npcm7xx_smbus_stop(DEVICE(s)->canonical_path);
295*94e77879SHao Wu     npcm7xx_smbus_update_irq(s);
296*94e77879SHao Wu }
297*94e77879SHao Wu 
298*94e77879SHao Wu 
299*94e77879SHao Wu static void npcm7xx_smbus_stop(NPCM7xxSMBusState *s)
300*94e77879SHao Wu {
301*94e77879SHao Wu     if (s->st & NPCM7XX_SMBST_MODE) {
302*94e77879SHao Wu         switch (s->status) {
303*94e77879SHao Wu         case NPCM7XX_SMBUS_STATUS_RECEIVING:
304*94e77879SHao Wu         case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
305*94e77879SHao Wu             s->status = NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE;
306*94e77879SHao Wu             break;
307*94e77879SHao Wu 
308*94e77879SHao Wu         case NPCM7XX_SMBUS_STATUS_NEGACK:
309*94e77879SHao Wu             s->status = NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK;
310*94e77879SHao Wu             break;
311*94e77879SHao Wu 
312*94e77879SHao Wu         default:
313*94e77879SHao Wu             npcm7xx_smbus_execute_stop(s);
314*94e77879SHao Wu             break;
315*94e77879SHao Wu         }
316*94e77879SHao Wu     }
317*94e77879SHao Wu }
318*94e77879SHao Wu 
319*94e77879SHao Wu static uint8_t npcm7xx_smbus_read_sda(NPCM7xxSMBusState *s)
320*94e77879SHao Wu {
321*94e77879SHao Wu     uint8_t value = s->sda;
322*94e77879SHao Wu 
323*94e77879SHao Wu     switch (s->status) {
324*94e77879SHao Wu     case NPCM7XX_SMBUS_STATUS_STOPPING_LAST_RECEIVE:
325*94e77879SHao Wu         npcm7xx_smbus_execute_stop(s);
326*94e77879SHao Wu         break;
327*94e77879SHao Wu 
328*94e77879SHao Wu     case NPCM7XX_SMBUS_STATUS_RECEIVING:
329*94e77879SHao Wu         npcm7xx_smbus_recv_byte(s);
330*94e77879SHao Wu         break;
331*94e77879SHao Wu 
332*94e77879SHao Wu     default:
333*94e77879SHao Wu         /* Do nothing */
334*94e77879SHao Wu         break;
335*94e77879SHao Wu     }
336*94e77879SHao Wu 
337*94e77879SHao Wu     return value;
338*94e77879SHao Wu }
339*94e77879SHao Wu 
340*94e77879SHao Wu static void npcm7xx_smbus_write_sda(NPCM7xxSMBusState *s, uint8_t value)
341*94e77879SHao Wu {
342*94e77879SHao Wu     s->sda = value;
343*94e77879SHao Wu     if (s->st & NPCM7XX_SMBST_MODE) {
344*94e77879SHao Wu         switch (s->status) {
345*94e77879SHao Wu         case NPCM7XX_SMBUS_STATUS_IDLE:
346*94e77879SHao Wu             npcm7xx_smbus_send_address(s, value);
347*94e77879SHao Wu             break;
348*94e77879SHao Wu         case NPCM7XX_SMBUS_STATUS_SENDING:
349*94e77879SHao Wu             npcm7xx_smbus_send_byte(s, value);
350*94e77879SHao Wu             break;
351*94e77879SHao Wu         default:
352*94e77879SHao Wu             qemu_log_mask(LOG_GUEST_ERROR,
353*94e77879SHao Wu                           "%s: write to SDA in invalid status %d: %u\n",
354*94e77879SHao Wu                           DEVICE(s)->canonical_path, s->status, value);
355*94e77879SHao Wu             break;
356*94e77879SHao Wu         }
357*94e77879SHao Wu     }
358*94e77879SHao Wu }
359*94e77879SHao Wu 
360*94e77879SHao Wu static void npcm7xx_smbus_write_st(NPCM7xxSMBusState *s, uint8_t value)
361*94e77879SHao Wu {
362*94e77879SHao Wu     s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_STP);
363*94e77879SHao Wu     s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_BER);
364*94e77879SHao Wu     s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_STASTR);
365*94e77879SHao Wu     s->st = WRITE_ONE_CLEAR(s->st, value, NPCM7XX_SMBST_NMATCH);
366*94e77879SHao Wu 
367*94e77879SHao Wu     if (value & NPCM7XX_SMBST_NEGACK) {
368*94e77879SHao Wu         s->st &= ~NPCM7XX_SMBST_NEGACK;
369*94e77879SHao Wu         if (s->status == NPCM7XX_SMBUS_STATUS_STOPPING_NEGACK) {
370*94e77879SHao Wu             npcm7xx_smbus_execute_stop(s);
371*94e77879SHao Wu         }
372*94e77879SHao Wu     }
373*94e77879SHao Wu 
374*94e77879SHao Wu     if (value & NPCM7XX_SMBST_STASTR &&
375*94e77879SHao Wu             s->status == NPCM7XX_SMBUS_STATUS_RECEIVING) {
376*94e77879SHao Wu         npcm7xx_smbus_recv_byte(s);
377*94e77879SHao Wu     }
378*94e77879SHao Wu 
379*94e77879SHao Wu     npcm7xx_smbus_update_irq(s);
380*94e77879SHao Wu }
381*94e77879SHao Wu 
382*94e77879SHao Wu static void npcm7xx_smbus_write_cst(NPCM7xxSMBusState *s, uint8_t value)
383*94e77879SHao Wu {
384*94e77879SHao Wu     uint8_t new_value = s->cst;
385*94e77879SHao Wu 
386*94e77879SHao Wu     s->cst = WRITE_ONE_CLEAR(new_value, value, NPCM7XX_SMBCST_BB);
387*94e77879SHao Wu     npcm7xx_smbus_update_irq(s);
388*94e77879SHao Wu }
389*94e77879SHao Wu 
390*94e77879SHao Wu static void npcm7xx_smbus_write_cst3(NPCM7xxSMBusState *s, uint8_t value)
391*94e77879SHao Wu {
392*94e77879SHao Wu     s->cst3 = WRITE_ONE_CLEAR(s->cst3, value, NPCM7XX_SMBCST3_EO_BUSY);
393*94e77879SHao Wu     npcm7xx_smbus_update_irq(s);
394*94e77879SHao Wu }
395*94e77879SHao Wu 
396*94e77879SHao Wu static void npcm7xx_smbus_write_ctl1(NPCM7xxSMBusState *s, uint8_t value)
397*94e77879SHao Wu {
398*94e77879SHao Wu     s->ctl1 = KEEP_OLD_BIT(s->ctl1, value,
399*94e77879SHao Wu             NPCM7XX_SMBCTL1_START | NPCM7XX_SMBCTL1_STOP | NPCM7XX_SMBCTL1_ACK);
400*94e77879SHao Wu 
401*94e77879SHao Wu     if (value & NPCM7XX_SMBCTL1_START) {
402*94e77879SHao Wu         npcm7xx_smbus_start(s);
403*94e77879SHao Wu     }
404*94e77879SHao Wu 
405*94e77879SHao Wu     if (value & NPCM7XX_SMBCTL1_STOP) {
406*94e77879SHao Wu         npcm7xx_smbus_stop(s);
407*94e77879SHao Wu     }
408*94e77879SHao Wu 
409*94e77879SHao Wu     npcm7xx_smbus_update_irq(s);
410*94e77879SHao Wu }
411*94e77879SHao Wu 
412*94e77879SHao Wu static void npcm7xx_smbus_write_ctl2(NPCM7xxSMBusState *s, uint8_t value)
413*94e77879SHao Wu {
414*94e77879SHao Wu     s->ctl2 = value;
415*94e77879SHao Wu 
416*94e77879SHao Wu     if (!NPCM7XX_SMBUS_ENABLED(s)) {
417*94e77879SHao Wu         /* Disable this SMBus module. */
418*94e77879SHao Wu         s->ctl1 = 0;
419*94e77879SHao Wu         s->st = 0;
420*94e77879SHao Wu         s->cst3 = s->cst3 & (~NPCM7XX_SMBCST3_EO_BUSY);
421*94e77879SHao Wu         s->cst = 0;
422*94e77879SHao Wu     }
423*94e77879SHao Wu }
424*94e77879SHao Wu 
425*94e77879SHao Wu static void npcm7xx_smbus_write_ctl3(NPCM7xxSMBusState *s, uint8_t value)
426*94e77879SHao Wu {
427*94e77879SHao Wu     uint8_t old_ctl3 = s->ctl3;
428*94e77879SHao Wu 
429*94e77879SHao Wu     /* Write to SDA and SCL bits are ignored. */
430*94e77879SHao Wu     s->ctl3 =  KEEP_OLD_BIT(old_ctl3, value,
431*94e77879SHao Wu                             NPCM7XX_SMBCTL3_SCL_LVL | NPCM7XX_SMBCTL3_SDA_LVL);
432*94e77879SHao Wu }
433*94e77879SHao Wu 
434*94e77879SHao Wu static uint64_t npcm7xx_smbus_read(void *opaque, hwaddr offset, unsigned size)
435*94e77879SHao Wu {
436*94e77879SHao Wu     NPCM7xxSMBusState *s = opaque;
437*94e77879SHao Wu     uint64_t value = 0;
438*94e77879SHao Wu     uint8_t bank = s->ctl3 & NPCM7XX_SMBCTL3_BNK_SEL;
439*94e77879SHao Wu 
440*94e77879SHao Wu     /* The order of the registers are their order in memory. */
441*94e77879SHao Wu     switch (offset) {
442*94e77879SHao Wu     case NPCM7XX_SMB_SDA:
443*94e77879SHao Wu         value = npcm7xx_smbus_read_sda(s);
444*94e77879SHao Wu         break;
445*94e77879SHao Wu 
446*94e77879SHao Wu     case NPCM7XX_SMB_ST:
447*94e77879SHao Wu         value = s->st;
448*94e77879SHao Wu         break;
449*94e77879SHao Wu 
450*94e77879SHao Wu     case NPCM7XX_SMB_CST:
451*94e77879SHao Wu         value = s->cst;
452*94e77879SHao Wu         break;
453*94e77879SHao Wu 
454*94e77879SHao Wu     case NPCM7XX_SMB_CTL1:
455*94e77879SHao Wu         value = s->ctl1;
456*94e77879SHao Wu         break;
457*94e77879SHao Wu 
458*94e77879SHao Wu     case NPCM7XX_SMB_ADDR1:
459*94e77879SHao Wu         value = s->addr[0];
460*94e77879SHao Wu         break;
461*94e77879SHao Wu 
462*94e77879SHao Wu     case NPCM7XX_SMB_CTL2:
463*94e77879SHao Wu         value = s->ctl2;
464*94e77879SHao Wu         break;
465*94e77879SHao Wu 
466*94e77879SHao Wu     case NPCM7XX_SMB_ADDR2:
467*94e77879SHao Wu         value = s->addr[1];
468*94e77879SHao Wu         break;
469*94e77879SHao Wu 
470*94e77879SHao Wu     case NPCM7XX_SMB_CTL3:
471*94e77879SHao Wu         value = s->ctl3;
472*94e77879SHao Wu         break;
473*94e77879SHao Wu 
474*94e77879SHao Wu     case NPCM7XX_SMB_CST2:
475*94e77879SHao Wu         value = s->cst2;
476*94e77879SHao Wu         break;
477*94e77879SHao Wu 
478*94e77879SHao Wu     case NPCM7XX_SMB_CST3:
479*94e77879SHao Wu         value = s->cst3;
480*94e77879SHao Wu         break;
481*94e77879SHao Wu 
482*94e77879SHao Wu     case NPCM7XX_SMB_VER:
483*94e77879SHao Wu         value = npcm7xx_smbus_get_version();
484*94e77879SHao Wu         break;
485*94e77879SHao Wu 
486*94e77879SHao Wu     /* This register is either invalid or banked at this point. */
487*94e77879SHao Wu     default:
488*94e77879SHao Wu         if (bank) {
489*94e77879SHao Wu             /* Bank 1 */
490*94e77879SHao Wu             qemu_log_mask(LOG_GUEST_ERROR,
491*94e77879SHao Wu                     "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
492*94e77879SHao Wu                     DEVICE(s)->canonical_path, offset);
493*94e77879SHao Wu         } else {
494*94e77879SHao Wu             /* Bank 0 */
495*94e77879SHao Wu             switch (offset) {
496*94e77879SHao Wu             case NPCM7XX_SMB_ADDR3:
497*94e77879SHao Wu                 value = s->addr[2];
498*94e77879SHao Wu                 break;
499*94e77879SHao Wu 
500*94e77879SHao Wu             case NPCM7XX_SMB_ADDR7:
501*94e77879SHao Wu                 value = s->addr[6];
502*94e77879SHao Wu                 break;
503*94e77879SHao Wu 
504*94e77879SHao Wu             case NPCM7XX_SMB_ADDR4:
505*94e77879SHao Wu                 value = s->addr[3];
506*94e77879SHao Wu                 break;
507*94e77879SHao Wu 
508*94e77879SHao Wu             case NPCM7XX_SMB_ADDR8:
509*94e77879SHao Wu                 value = s->addr[7];
510*94e77879SHao Wu                 break;
511*94e77879SHao Wu 
512*94e77879SHao Wu             case NPCM7XX_SMB_ADDR5:
513*94e77879SHao Wu                 value = s->addr[4];
514*94e77879SHao Wu                 break;
515*94e77879SHao Wu 
516*94e77879SHao Wu             case NPCM7XX_SMB_ADDR9:
517*94e77879SHao Wu                 value = s->addr[8];
518*94e77879SHao Wu                 break;
519*94e77879SHao Wu 
520*94e77879SHao Wu             case NPCM7XX_SMB_ADDR6:
521*94e77879SHao Wu                 value = s->addr[5];
522*94e77879SHao Wu                 break;
523*94e77879SHao Wu 
524*94e77879SHao Wu             case NPCM7XX_SMB_ADDR10:
525*94e77879SHao Wu                 value = s->addr[9];
526*94e77879SHao Wu                 break;
527*94e77879SHao Wu 
528*94e77879SHao Wu             case NPCM7XX_SMB_CTL4:
529*94e77879SHao Wu                 value = s->ctl4;
530*94e77879SHao Wu                 break;
531*94e77879SHao Wu 
532*94e77879SHao Wu             case NPCM7XX_SMB_CTL5:
533*94e77879SHao Wu                 value = s->ctl5;
534*94e77879SHao Wu                 break;
535*94e77879SHao Wu 
536*94e77879SHao Wu             case NPCM7XX_SMB_SCLLT:
537*94e77879SHao Wu                 value = s->scllt;
538*94e77879SHao Wu                 break;
539*94e77879SHao Wu 
540*94e77879SHao Wu             case NPCM7XX_SMB_SCLHT:
541*94e77879SHao Wu                 value = s->sclht;
542*94e77879SHao Wu                 break;
543*94e77879SHao Wu 
544*94e77879SHao Wu             default:
545*94e77879SHao Wu                 qemu_log_mask(LOG_GUEST_ERROR,
546*94e77879SHao Wu                         "%s: read from invalid offset 0x%" HWADDR_PRIx "\n",
547*94e77879SHao Wu                         DEVICE(s)->canonical_path, offset);
548*94e77879SHao Wu                 break;
549*94e77879SHao Wu             }
550*94e77879SHao Wu         }
551*94e77879SHao Wu         break;
552*94e77879SHao Wu     }
553*94e77879SHao Wu 
554*94e77879SHao Wu     trace_npcm7xx_smbus_read(DEVICE(s)->canonical_path, offset, value, size);
555*94e77879SHao Wu 
556*94e77879SHao Wu     return value;
557*94e77879SHao Wu }
558*94e77879SHao Wu 
559*94e77879SHao Wu static void npcm7xx_smbus_write(void *opaque, hwaddr offset, uint64_t value,
560*94e77879SHao Wu                               unsigned size)
561*94e77879SHao Wu {
562*94e77879SHao Wu     NPCM7xxSMBusState *s = opaque;
563*94e77879SHao Wu     uint8_t bank = s->ctl3 & NPCM7XX_SMBCTL3_BNK_SEL;
564*94e77879SHao Wu 
565*94e77879SHao Wu     trace_npcm7xx_smbus_write(DEVICE(s)->canonical_path, offset, value, size);
566*94e77879SHao Wu 
567*94e77879SHao Wu     /* The order of the registers are their order in memory. */
568*94e77879SHao Wu     switch (offset) {
569*94e77879SHao Wu     case NPCM7XX_SMB_SDA:
570*94e77879SHao Wu         npcm7xx_smbus_write_sda(s, value);
571*94e77879SHao Wu         break;
572*94e77879SHao Wu 
573*94e77879SHao Wu     case NPCM7XX_SMB_ST:
574*94e77879SHao Wu         npcm7xx_smbus_write_st(s, value);
575*94e77879SHao Wu         break;
576*94e77879SHao Wu 
577*94e77879SHao Wu     case NPCM7XX_SMB_CST:
578*94e77879SHao Wu         npcm7xx_smbus_write_cst(s, value);
579*94e77879SHao Wu         break;
580*94e77879SHao Wu 
581*94e77879SHao Wu     case NPCM7XX_SMB_CTL1:
582*94e77879SHao Wu         npcm7xx_smbus_write_ctl1(s, value);
583*94e77879SHao Wu         break;
584*94e77879SHao Wu 
585*94e77879SHao Wu     case NPCM7XX_SMB_ADDR1:
586*94e77879SHao Wu         s->addr[0] = value;
587*94e77879SHao Wu         break;
588*94e77879SHao Wu 
589*94e77879SHao Wu     case NPCM7XX_SMB_CTL2:
590*94e77879SHao Wu         npcm7xx_smbus_write_ctl2(s, value);
591*94e77879SHao Wu         break;
592*94e77879SHao Wu 
593*94e77879SHao Wu     case NPCM7XX_SMB_ADDR2:
594*94e77879SHao Wu         s->addr[1] = value;
595*94e77879SHao Wu         break;
596*94e77879SHao Wu 
597*94e77879SHao Wu     case NPCM7XX_SMB_CTL3:
598*94e77879SHao Wu         npcm7xx_smbus_write_ctl3(s, value);
599*94e77879SHao Wu         break;
600*94e77879SHao Wu 
601*94e77879SHao Wu     case NPCM7XX_SMB_CST2:
602*94e77879SHao Wu         qemu_log_mask(LOG_GUEST_ERROR,
603*94e77879SHao Wu                 "%s: write to read-only reg: offset 0x%" HWADDR_PRIx "\n",
604*94e77879SHao Wu                 DEVICE(s)->canonical_path, offset);
605*94e77879SHao Wu         break;
606*94e77879SHao Wu 
607*94e77879SHao Wu     case NPCM7XX_SMB_CST3:
608*94e77879SHao Wu         npcm7xx_smbus_write_cst3(s, value);
609*94e77879SHao Wu         break;
610*94e77879SHao Wu 
611*94e77879SHao Wu     case NPCM7XX_SMB_VER:
612*94e77879SHao Wu         qemu_log_mask(LOG_GUEST_ERROR,
613*94e77879SHao Wu                 "%s: write to read-only reg: offset 0x%" HWADDR_PRIx "\n",
614*94e77879SHao Wu                 DEVICE(s)->canonical_path, offset);
615*94e77879SHao Wu         break;
616*94e77879SHao Wu 
617*94e77879SHao Wu     /* This register is either invalid or banked at this point. */
618*94e77879SHao Wu     default:
619*94e77879SHao Wu         if (bank) {
620*94e77879SHao Wu             /* Bank 1 */
621*94e77879SHao Wu             qemu_log_mask(LOG_GUEST_ERROR,
622*94e77879SHao Wu                     "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
623*94e77879SHao Wu                     DEVICE(s)->canonical_path, offset);
624*94e77879SHao Wu         } else {
625*94e77879SHao Wu             /* Bank 0 */
626*94e77879SHao Wu             switch (offset) {
627*94e77879SHao Wu             case NPCM7XX_SMB_ADDR3:
628*94e77879SHao Wu                 s->addr[2] = value;
629*94e77879SHao Wu                 break;
630*94e77879SHao Wu 
631*94e77879SHao Wu             case NPCM7XX_SMB_ADDR7:
632*94e77879SHao Wu                 s->addr[6] = value;
633*94e77879SHao Wu                 break;
634*94e77879SHao Wu 
635*94e77879SHao Wu             case NPCM7XX_SMB_ADDR4:
636*94e77879SHao Wu                 s->addr[3] = value;
637*94e77879SHao Wu                 break;
638*94e77879SHao Wu 
639*94e77879SHao Wu             case NPCM7XX_SMB_ADDR8:
640*94e77879SHao Wu                 s->addr[7] = value;
641*94e77879SHao Wu                 break;
642*94e77879SHao Wu 
643*94e77879SHao Wu             case NPCM7XX_SMB_ADDR5:
644*94e77879SHao Wu                 s->addr[4] = value;
645*94e77879SHao Wu                 break;
646*94e77879SHao Wu 
647*94e77879SHao Wu             case NPCM7XX_SMB_ADDR9:
648*94e77879SHao Wu                 s->addr[8] = value;
649*94e77879SHao Wu                 break;
650*94e77879SHao Wu 
651*94e77879SHao Wu             case NPCM7XX_SMB_ADDR6:
652*94e77879SHao Wu                 s->addr[5] = value;
653*94e77879SHao Wu                 break;
654*94e77879SHao Wu 
655*94e77879SHao Wu             case NPCM7XX_SMB_ADDR10:
656*94e77879SHao Wu                 s->addr[9] = value;
657*94e77879SHao Wu                 break;
658*94e77879SHao Wu 
659*94e77879SHao Wu             case NPCM7XX_SMB_CTL4:
660*94e77879SHao Wu                 s->ctl4 = value;
661*94e77879SHao Wu                 break;
662*94e77879SHao Wu 
663*94e77879SHao Wu             case NPCM7XX_SMB_CTL5:
664*94e77879SHao Wu                 s->ctl5 = value;
665*94e77879SHao Wu                 break;
666*94e77879SHao Wu 
667*94e77879SHao Wu             case NPCM7XX_SMB_SCLLT:
668*94e77879SHao Wu                 s->scllt = value;
669*94e77879SHao Wu                 break;
670*94e77879SHao Wu 
671*94e77879SHao Wu             case NPCM7XX_SMB_SCLHT:
672*94e77879SHao Wu                 s->sclht = value;
673*94e77879SHao Wu                 break;
674*94e77879SHao Wu 
675*94e77879SHao Wu             default:
676*94e77879SHao Wu                 qemu_log_mask(LOG_GUEST_ERROR,
677*94e77879SHao Wu                         "%s: write to invalid offset 0x%" HWADDR_PRIx "\n",
678*94e77879SHao Wu                         DEVICE(s)->canonical_path, offset);
679*94e77879SHao Wu                 break;
680*94e77879SHao Wu             }
681*94e77879SHao Wu         }
682*94e77879SHao Wu         break;
683*94e77879SHao Wu     }
684*94e77879SHao Wu }
685*94e77879SHao Wu 
686*94e77879SHao Wu static const MemoryRegionOps npcm7xx_smbus_ops = {
687*94e77879SHao Wu     .read = npcm7xx_smbus_read,
688*94e77879SHao Wu     .write = npcm7xx_smbus_write,
689*94e77879SHao Wu     .endianness = DEVICE_LITTLE_ENDIAN,
690*94e77879SHao Wu     .valid = {
691*94e77879SHao Wu         .min_access_size = 1,
692*94e77879SHao Wu         .max_access_size = 1,
693*94e77879SHao Wu         .unaligned = false,
694*94e77879SHao Wu     },
695*94e77879SHao Wu };
696*94e77879SHao Wu 
697*94e77879SHao Wu static void npcm7xx_smbus_enter_reset(Object *obj, ResetType type)
698*94e77879SHao Wu {
699*94e77879SHao Wu     NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
700*94e77879SHao Wu 
701*94e77879SHao Wu     s->st = NPCM7XX_SMB_ST_INIT_VAL;
702*94e77879SHao Wu     s->cst = NPCM7XX_SMB_CST_INIT_VAL;
703*94e77879SHao Wu     s->cst2 = NPCM7XX_SMB_CST2_INIT_VAL;
704*94e77879SHao Wu     s->cst3 = NPCM7XX_SMB_CST3_INIT_VAL;
705*94e77879SHao Wu     s->ctl1 = NPCM7XX_SMB_CTL1_INIT_VAL;
706*94e77879SHao Wu     s->ctl2 = NPCM7XX_SMB_CTL2_INIT_VAL;
707*94e77879SHao Wu     s->ctl3 = NPCM7XX_SMB_CTL3_INIT_VAL;
708*94e77879SHao Wu     s->ctl4 = NPCM7XX_SMB_CTL4_INIT_VAL;
709*94e77879SHao Wu     s->ctl5 = NPCM7XX_SMB_CTL5_INIT_VAL;
710*94e77879SHao Wu 
711*94e77879SHao Wu     for (int i = 0; i < NPCM7XX_SMBUS_NR_ADDRS; ++i) {
712*94e77879SHao Wu         s->addr[i] = NPCM7XX_SMB_ADDR_INIT_VAL;
713*94e77879SHao Wu     }
714*94e77879SHao Wu     s->scllt = NPCM7XX_SMB_SCLLT_INIT_VAL;
715*94e77879SHao Wu     s->sclht = NPCM7XX_SMB_SCLHT_INIT_VAL;
716*94e77879SHao Wu 
717*94e77879SHao Wu     s->status = NPCM7XX_SMBUS_STATUS_IDLE;
718*94e77879SHao Wu }
719*94e77879SHao Wu 
720*94e77879SHao Wu static void npcm7xx_smbus_hold_reset(Object *obj)
721*94e77879SHao Wu {
722*94e77879SHao Wu     NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
723*94e77879SHao Wu 
724*94e77879SHao Wu     qemu_irq_lower(s->irq);
725*94e77879SHao Wu }
726*94e77879SHao Wu 
727*94e77879SHao Wu static void npcm7xx_smbus_init(Object *obj)
728*94e77879SHao Wu {
729*94e77879SHao Wu     NPCM7xxSMBusState *s = NPCM7XX_SMBUS(obj);
730*94e77879SHao Wu     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
731*94e77879SHao Wu 
732*94e77879SHao Wu     sysbus_init_irq(sbd, &s->irq);
733*94e77879SHao Wu     memory_region_init_io(&s->iomem, obj, &npcm7xx_smbus_ops, s,
734*94e77879SHao Wu                           "regs", 4 * KiB);
735*94e77879SHao Wu     sysbus_init_mmio(sbd, &s->iomem);
736*94e77879SHao Wu 
737*94e77879SHao Wu     s->bus = i2c_init_bus(DEVICE(s), "i2c-bus");
738*94e77879SHao Wu     s->status = NPCM7XX_SMBUS_STATUS_IDLE;
739*94e77879SHao Wu }
740*94e77879SHao Wu 
741*94e77879SHao Wu static const VMStateDescription vmstate_npcm7xx_smbus = {
742*94e77879SHao Wu     .name = "npcm7xx-smbus",
743*94e77879SHao Wu     .version_id = 0,
744*94e77879SHao Wu     .minimum_version_id = 0,
745*94e77879SHao Wu     .fields = (VMStateField[]) {
746*94e77879SHao Wu         VMSTATE_UINT8(sda, NPCM7xxSMBusState),
747*94e77879SHao Wu         VMSTATE_UINT8(st, NPCM7xxSMBusState),
748*94e77879SHao Wu         VMSTATE_UINT8(cst, NPCM7xxSMBusState),
749*94e77879SHao Wu         VMSTATE_UINT8(cst2, NPCM7xxSMBusState),
750*94e77879SHao Wu         VMSTATE_UINT8(cst3, NPCM7xxSMBusState),
751*94e77879SHao Wu         VMSTATE_UINT8(ctl1, NPCM7xxSMBusState),
752*94e77879SHao Wu         VMSTATE_UINT8(ctl2, NPCM7xxSMBusState),
753*94e77879SHao Wu         VMSTATE_UINT8(ctl3, NPCM7xxSMBusState),
754*94e77879SHao Wu         VMSTATE_UINT8(ctl4, NPCM7xxSMBusState),
755*94e77879SHao Wu         VMSTATE_UINT8(ctl5, NPCM7xxSMBusState),
756*94e77879SHao Wu         VMSTATE_UINT8_ARRAY(addr, NPCM7xxSMBusState, NPCM7XX_SMBUS_NR_ADDRS),
757*94e77879SHao Wu         VMSTATE_UINT8(scllt, NPCM7xxSMBusState),
758*94e77879SHao Wu         VMSTATE_UINT8(sclht, NPCM7xxSMBusState),
759*94e77879SHao Wu         VMSTATE_END_OF_LIST(),
760*94e77879SHao Wu     },
761*94e77879SHao Wu };
762*94e77879SHao Wu 
763*94e77879SHao Wu static void npcm7xx_smbus_class_init(ObjectClass *klass, void *data)
764*94e77879SHao Wu {
765*94e77879SHao Wu     ResettableClass *rc = RESETTABLE_CLASS(klass);
766*94e77879SHao Wu     DeviceClass *dc = DEVICE_CLASS(klass);
767*94e77879SHao Wu 
768*94e77879SHao Wu     dc->desc = "NPCM7xx System Management Bus";
769*94e77879SHao Wu     dc->vmsd = &vmstate_npcm7xx_smbus;
770*94e77879SHao Wu     rc->phases.enter = npcm7xx_smbus_enter_reset;
771*94e77879SHao Wu     rc->phases.hold = npcm7xx_smbus_hold_reset;
772*94e77879SHao Wu }
773*94e77879SHao Wu 
774*94e77879SHao Wu static const TypeInfo npcm7xx_smbus_types[] = {
775*94e77879SHao Wu     {
776*94e77879SHao Wu         .name = TYPE_NPCM7XX_SMBUS,
777*94e77879SHao Wu         .parent = TYPE_SYS_BUS_DEVICE,
778*94e77879SHao Wu         .instance_size = sizeof(NPCM7xxSMBusState),
779*94e77879SHao Wu         .class_init = npcm7xx_smbus_class_init,
780*94e77879SHao Wu         .instance_init = npcm7xx_smbus_init,
781*94e77879SHao Wu     },
782*94e77879SHao Wu };
783*94e77879SHao Wu DEFINE_TYPES(npcm7xx_smbus_types);
784