1 /*
2 * IBM CFF power supplies device
3 *
4 * Copyright (c) 2019 IBM Corporation.
5 *
6 * This code is licensed under the GPL version 2 or later. See the
7 * COPYING file in the top-level directory.
8 */
9
10 #include "qemu/osdep.h"
11 #include "hw/hw.h"
12 #include "hw/i2c/i2c.h"
13 #include "qapi/error.h"
14 #include "qapi/visitor.h"
15 #include "hw/misc/pmbus_regs.h"
16 #include "migration/vmstate.h"
17
18 #define IR35221_MFR_VIN_PEAK 0xc5
19 #define IR35221_MFR_VOUT_PEAK 0xc6
20 #define IR35221_MFR_IOUT_PEAK 0xc7
21 #define IR35221_MFR_TEMP_PEAK 0xc8
22 #define IR35221_MFR_VIN_VALLEY 0xc9
23 #define IR35221_MFR_VOUT_VALLEY 0xca
24 #define IR35221_MFR_IOUT_VALLEY 0xcb
25 #define IR35221_MFR_TEMP_VALLEY 0xcc
26
27 typedef struct Ir35221State {
28 /*< private >*/
29 I2CSlave i2c;
30 /*< public >*/
31
32 uint8_t regs[0x100];
33
34 uint8_t len;
35 uint8_t buf[32];
36 uint8_t pointer;
37
38 } Ir35221State;
39
40 #define TYPE_IR35221 "ir35221"
41 #define IR35221(obj) OBJECT_CHECK(Ir35221State, (obj), TYPE_IR35221)
42
ir35221_read(Ir35221State * s)43 static void ir35221_read(Ir35221State *s)
44 {
45 s->len = 0;
46
47 switch (s->pointer) {
48 case PMBUS_MFR_ID:
49 s->buf[s->len++] = 2; /* Byte count */
50 s->buf[s->len++] = 'R';
51 s->buf[s->len++] = 'I';
52 break;
53 case PMBUS_MFR_MODEL:
54 s->buf[s->len++] = 2; /* Byte count */
55 s->buf[s->len++] = 0x6c;
56 s->buf[s->len++] = 0x00;
57 break;
58 default:
59 s->buf[s->len++] = s->regs[s->pointer];
60 break;
61 }
62 }
63
ir35221_write(Ir35221State * s)64 static void ir35221_write(Ir35221State *s)
65 {
66 /* No writes */
67 }
68
ir35221_recv(I2CSlave * i2c)69 static uint8_t ir35221_recv(I2CSlave *i2c)
70 {
71 Ir35221State *s = IR35221(i2c);
72
73 if (s->len < sizeof(s->buf)) {
74 return s->buf[s->len++];
75 } else {
76 return 0xff;
77 }
78 }
79
ir35221_send(I2CSlave * i2c,uint8_t data)80 static int ir35221_send(I2CSlave *i2c, uint8_t data)
81 {
82 Ir35221State *s = IR35221(i2c);
83
84 if (s->len == 0) {
85 /*
86 * first byte is the register pointer for a read or write
87 * operation
88 */
89 s->pointer = data;
90 s->len++;
91 } else {
92 /*
93 * next bytes are data to write.
94 */
95 if (s->len <= sizeof(s->buf)) {
96 s->buf[s->len - 1] = data;
97 }
98 s->len++;
99 ir35221_write(s);
100 }
101
102 return 0;
103 }
104
ir35221_event(I2CSlave * i2c,enum i2c_event event)105 static int ir35221_event(I2CSlave *i2c, enum i2c_event event)
106 {
107 Ir35221State *s = IR35221(i2c);
108
109 /* TODO: handle SMBus "block read" */
110
111 switch (event) {
112 case I2C_START_RECV:
113 ir35221_read(s);
114 break;
115 case I2C_START_SEND:
116 case I2C_NACK:
117 case I2C_FINISH:
118 s->pointer = 0xFF;
119 break;
120 default:
121 return -1;
122 }
123
124 s->len = 0;
125 return 0;
126 }
127
128 static const VMStateDescription vmstate_ir35221 = {
129 .name = TYPE_IR35221,
130 .version_id = 0,
131 .minimum_version_id = 0,
132 .fields = (VMStateField[]) {
133 VMSTATE_UINT8(len, Ir35221State),
134 VMSTATE_UINT8_ARRAY(buf, Ir35221State, 32),
135 VMSTATE_UINT8(pointer, Ir35221State),
136 VMSTATE_UINT8_ARRAY(regs, Ir35221State, 0x100),
137 VMSTATE_I2C_SLAVE(i2c, Ir35221State),
138 VMSTATE_END_OF_LIST()
139 }
140 };
141
ir35221_reset(DeviceState * dev)142 static void ir35221_reset(DeviceState *dev)
143 {
144 Ir35221State *s = IR35221(dev);
145
146 memset(s->regs, 0, sizeof(s->regs));
147 s->pointer = 0xFF;
148 }
149
ir35221_realize(DeviceState * dev,Error ** errp)150 static void ir35221_realize(DeviceState *dev, Error **errp)
151 {
152 ;
153 }
154
ir35221_class_init(ObjectClass * klass,void * data)155 static void ir35221_class_init(ObjectClass *klass, void *data)
156 {
157 DeviceClass *dc = DEVICE_CLASS(klass);
158 I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
159
160 dc->realize = ir35221_realize;
161 device_class_set_legacy_reset(dc, ir35221_reset);
162 k->event = ir35221_event;
163 k->recv = ir35221_recv;
164 k->send = ir35221_send;
165 dc->vmsd = &vmstate_ir35221;
166 }
167
168 static const TypeInfo ir35221_info = {
169 .name = TYPE_IR35221,
170 .parent = TYPE_I2C_SLAVE,
171 .instance_size = sizeof(Ir35221State),
172 .class_init = ir35221_class_init,
173 };
174
ir35221_register_types(void)175 static void ir35221_register_types(void)
176 {
177 type_register_static(&ir35221_info);
178 }
179
180 type_init(ir35221_register_types)
181