2 * PMBus device for Renesas Digital Multiphase Voltage Regulators
4 * Copyright 2021 Google LLC
6 * SPDX-License-Identifier: GPL-2.0-or-later
9 #include "qemu/osdep.h"
10 #include "hw/sensor/isl_pmbus_vr.h"
11 #include "hw/qdev-properties.h"
12 #include "qapi/visitor.h"
14 #include "qemu/module.h"
16 static uint8_t isl_pmbus_vr_read_byte(PMBusDevice
*pmdev
)
18 ISLState
*s
= ISL69260(pmdev
);
20 switch (pmdev
->code
) {
21 case PMBUS_IC_DEVICE_ID
:
22 if (!s
->ic_device_id_len
) {
25 pmbus_send(pmdev
, s
->ic_device_id
, s
->ic_device_id_len
);
30 qemu_log_mask(LOG_GUEST_ERROR
,
31 "%s: reading from unsupported register: 0x%02x\n",
32 __func__
, pmdev
->code
);
33 return PMBUS_ERR_BYTE
;
36 static int isl_pmbus_vr_write_data(PMBusDevice
*pmdev
, const uint8_t *buf
,
39 qemu_log_mask(LOG_GUEST_ERROR
,
40 "%s: write to unsupported register: 0x%02x\n",
41 __func__
, pmdev
->code
);
42 return PMBUS_ERR_BYTE
;
45 /* TODO: Implement coefficients support in pmbus_device.c for qmp */
46 static void isl_pmbus_vr_get(Object
*obj
, Visitor
*v
, const char *name
,
47 void *opaque
, Error
**errp
)
49 visit_type_uint16(v
, name
, (uint16_t *)opaque
, errp
);
52 static void isl_pmbus_vr_set(Object
*obj
, Visitor
*v
, const char *name
,
53 void *opaque
, Error
**errp
)
55 PMBusDevice
*pmdev
= PMBUS_DEVICE(obj
);
56 uint16_t *internal
= opaque
;
58 if (!visit_type_uint16(v
, name
, &value
, errp
)) {
63 pmbus_check_limits(pmdev
);
66 static void isl_pmbus_vr_exit_reset(Object
*obj
, ResetType type
)
68 PMBusDevice
*pmdev
= PMBUS_DEVICE(obj
);
71 pmdev
->capability
= ISL_CAPABILITY_DEFAULT
;
72 for (int i
= 0; i
< pmdev
->num_pages
; i
++) {
73 pmdev
->pages
[i
].operation
= ISL_OPERATION_DEFAULT
;
74 pmdev
->pages
[i
].on_off_config
= ISL_ON_OFF_CONFIG_DEFAULT
;
75 pmdev
->pages
[i
].vout_mode
= ISL_VOUT_MODE_DEFAULT
;
76 pmdev
->pages
[i
].vout_command
= ISL_VOUT_COMMAND_DEFAULT
;
77 pmdev
->pages
[i
].vout_max
= ISL_VOUT_MAX_DEFAULT
;
78 pmdev
->pages
[i
].vout_margin_high
= ISL_VOUT_MARGIN_HIGH_DEFAULT
;
79 pmdev
->pages
[i
].vout_margin_low
= ISL_VOUT_MARGIN_LOW_DEFAULT
;
80 pmdev
->pages
[i
].vout_transition_rate
= ISL_VOUT_TRANSITION_RATE_DEFAULT
;
81 pmdev
->pages
[i
].vout_ov_fault_limit
= ISL_VOUT_OV_FAULT_LIMIT_DEFAULT
;
82 pmdev
->pages
[i
].ot_fault_limit
= ISL_OT_FAULT_LIMIT_DEFAULT
;
83 pmdev
->pages
[i
].ot_warn_limit
= ISL_OT_WARN_LIMIT_DEFAULT
;
84 pmdev
->pages
[i
].vin_ov_warn_limit
= ISL_VIN_OV_WARN_LIMIT_DEFAULT
;
85 pmdev
->pages
[i
].vin_uv_warn_limit
= ISL_VIN_UV_WARN_LIMIT_DEFAULT
;
86 pmdev
->pages
[i
].iin_oc_fault_limit
= ISL_IIN_OC_FAULT_LIMIT_DEFAULT
;
87 pmdev
->pages
[i
].ton_delay
= ISL_TON_DELAY_DEFAULT
;
88 pmdev
->pages
[i
].ton_rise
= ISL_TON_RISE_DEFAULT
;
89 pmdev
->pages
[i
].toff_fall
= ISL_TOFF_FALL_DEFAULT
;
90 pmdev
->pages
[i
].revision
= ISL_REVISION_DEFAULT
;
92 pmdev
->pages
[i
].read_vout
= ISL_READ_VOUT_DEFAULT
;
93 pmdev
->pages
[i
].read_iout
= ISL_READ_IOUT_DEFAULT
;
94 pmdev
->pages
[i
].read_pout
= ISL_READ_POUT_DEFAULT
;
95 pmdev
->pages
[i
].read_vin
= ISL_READ_VIN_DEFAULT
;
96 pmdev
->pages
[i
].read_iin
= ISL_READ_IIN_DEFAULT
;
97 pmdev
->pages
[i
].read_pin
= ISL_READ_PIN_DEFAULT
;
98 pmdev
->pages
[i
].read_temperature_1
= ISL_READ_TEMP_DEFAULT
;
99 pmdev
->pages
[i
].read_temperature_2
= ISL_READ_TEMP_DEFAULT
;
100 pmdev
->pages
[i
].read_temperature_3
= ISL_READ_TEMP_DEFAULT
;
104 /* The raa228000 uses different direct mode coefficients from most isl devices */
105 static void raa228000_exit_reset(Object
*obj
, ResetType type
)
107 PMBusDevice
*pmdev
= PMBUS_DEVICE(obj
);
109 isl_pmbus_vr_exit_reset(obj
, type
);
111 pmdev
->pages
[0].read_iout
= 0;
112 pmdev
->pages
[0].read_pout
= 0;
113 pmdev
->pages
[0].read_vout
= 0;
114 pmdev
->pages
[0].read_vin
= 0;
115 pmdev
->pages
[0].read_iin
= 0;
116 pmdev
->pages
[0].read_pin
= 0;
117 pmdev
->pages
[0].read_temperature_1
= 0;
118 pmdev
->pages
[0].read_temperature_2
= 0;
119 pmdev
->pages
[0].read_temperature_3
= 0;
122 static void isl69259_exit_reset(Object
*obj
, ResetType type
)
124 ISLState
*s
= ISL69260(obj
);
125 static const uint8_t ic_device_id
[] = {0x04, 0x00, 0x81, 0xD2, 0x49, 0x3c};
126 g_assert(sizeof(ic_device_id
) <= sizeof(s
->ic_device_id
));
128 isl_pmbus_vr_exit_reset(obj
, type
);
130 s
->ic_device_id_len
= sizeof(ic_device_id
);
131 memcpy(s
->ic_device_id
, ic_device_id
, sizeof(ic_device_id
));
134 static void isl_pmbus_vr_add_props(Object
*obj
, uint64_t *flags
, uint8_t pages
)
136 PMBusDevice
*pmdev
= PMBUS_DEVICE(obj
);
137 for (int i
= 0; i
< pages
; i
++) {
138 if (flags
[i
] & PB_HAS_VIN
) {
139 object_property_add(obj
, "vin[*]", "uint16",
142 NULL
, &pmdev
->pages
[i
].read_vin
);
145 if (flags
[i
] & PB_HAS_VOUT
) {
146 object_property_add(obj
, "vout[*]", "uint16",
149 NULL
, &pmdev
->pages
[i
].read_vout
);
152 if (flags
[i
] & PB_HAS_IIN
) {
153 object_property_add(obj
, "iin[*]", "uint16",
156 NULL
, &pmdev
->pages
[i
].read_iin
);
159 if (flags
[i
] & PB_HAS_IOUT
) {
160 object_property_add(obj
, "iout[*]", "uint16",
163 NULL
, &pmdev
->pages
[i
].read_iout
);
166 if (flags
[i
] & PB_HAS_PIN
) {
167 object_property_add(obj
, "pin[*]", "uint16",
170 NULL
, &pmdev
->pages
[i
].read_pin
);
173 if (flags
[i
] & PB_HAS_POUT
) {
174 object_property_add(obj
, "pout[*]", "uint16",
177 NULL
, &pmdev
->pages
[i
].read_pout
);
180 if (flags
[i
] & PB_HAS_TEMPERATURE
) {
181 object_property_add(obj
, "temp1[*]", "uint16",
184 NULL
, &pmdev
->pages
[i
].read_temperature_1
);
187 if (flags
[i
] & PB_HAS_TEMP2
) {
188 object_property_add(obj
, "temp2[*]", "uint16",
191 NULL
, &pmdev
->pages
[i
].read_temperature_2
);
194 if (flags
[i
] & PB_HAS_TEMP3
) {
195 object_property_add(obj
, "temp3[*]", "uint16",
198 NULL
, &pmdev
->pages
[i
].read_temperature_3
);
203 static void raa22xx_init(Object
*obj
)
205 PMBusDevice
*pmdev
= PMBUS_DEVICE(obj
);
208 flags
[0] = PB_HAS_VIN
| PB_HAS_VOUT
| PB_HAS_VOUT_MODE
|
209 PB_HAS_VOUT_RATING
| PB_HAS_VOUT_MARGIN
| PB_HAS_IIN
|
210 PB_HAS_IOUT
| PB_HAS_PIN
| PB_HAS_POUT
| PB_HAS_TEMPERATURE
|
211 PB_HAS_TEMP2
| PB_HAS_TEMP3
| PB_HAS_STATUS_MFR_SPECIFIC
;
212 flags
[1] = PB_HAS_IIN
| PB_HAS_PIN
| PB_HAS_TEMPERATURE
| PB_HAS_TEMP3
|
213 PB_HAS_VOUT
| PB_HAS_VOUT_MODE
| PB_HAS_VOUT_MARGIN
|
214 PB_HAS_VOUT_RATING
| PB_HAS_IOUT
| PB_HAS_POUT
|
215 PB_HAS_STATUS_MFR_SPECIFIC
;
217 pmbus_page_config(pmdev
, 0, flags
[0]);
218 pmbus_page_config(pmdev
, 1, flags
[1]);
219 isl_pmbus_vr_add_props(obj
, flags
, ARRAY_SIZE(flags
));
222 static void raa228000_init(Object
*obj
)
224 PMBusDevice
*pmdev
= PMBUS_DEVICE(obj
);
227 flags
[0] = PB_HAS_VIN
| PB_HAS_VOUT
| PB_HAS_VOUT_MODE
|
228 PB_HAS_VOUT_RATING
| PB_HAS_VOUT_MARGIN
| PB_HAS_IIN
|
229 PB_HAS_IOUT
| PB_HAS_PIN
| PB_HAS_POUT
| PB_HAS_TEMPERATURE
|
230 PB_HAS_TEMP2
| PB_HAS_TEMP3
| PB_HAS_STATUS_MFR_SPECIFIC
;
232 pmbus_page_config(pmdev
, 0, flags
[0]);
233 isl_pmbus_vr_add_props(obj
, flags
, 1);
236 static void isl_pmbus_vr_class_init(ObjectClass
*klass
, void *data
,
239 PMBusDeviceClass
*k
= PMBUS_DEVICE_CLASS(klass
);
240 k
->write_data
= isl_pmbus_vr_write_data
;
241 k
->receive_byte
= isl_pmbus_vr_read_byte
;
242 k
->device_num_pages
= pages
;
245 static void isl69260_class_init(ObjectClass
*klass
, void *data
)
247 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
248 DeviceClass
*dc
= DEVICE_CLASS(klass
);
249 dc
->desc
= "Renesas ISL69260 Digital Multiphase Voltage Regulator";
250 rc
->phases
.exit
= isl_pmbus_vr_exit_reset
;
251 isl_pmbus_vr_class_init(klass
, data
, 2);
254 static void raa228000_class_init(ObjectClass
*klass
, void *data
)
256 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
257 DeviceClass
*dc
= DEVICE_CLASS(klass
);
258 dc
->desc
= "Renesas 228000 Digital Multiphase Voltage Regulator";
259 rc
->phases
.exit
= raa228000_exit_reset
;
260 isl_pmbus_vr_class_init(klass
, data
, 1);
263 static void raa229004_class_init(ObjectClass
*klass
, void *data
)
265 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
266 DeviceClass
*dc
= DEVICE_CLASS(klass
);
267 dc
->desc
= "Renesas 229004 Digital Multiphase Voltage Regulator";
268 rc
->phases
.exit
= isl_pmbus_vr_exit_reset
;
269 isl_pmbus_vr_class_init(klass
, data
, 2);
272 static void isl69259_class_init(ObjectClass
*klass
, void *data
)
274 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
275 DeviceClass
*dc
= DEVICE_CLASS(klass
);
276 dc
->desc
= "Renesas ISL69259 Digital Multiphase Voltage Regulator";
277 rc
->phases
.exit
= isl69259_exit_reset
;
278 isl_pmbus_vr_class_init(klass
, data
, 2);
281 static const TypeInfo isl69259_info
= {
282 .name
= TYPE_ISL69259
,
283 .parent
= TYPE_ISL69260
,
284 .class_init
= isl69259_class_init
,
287 static const TypeInfo isl69260_info
= {
288 .name
= TYPE_ISL69260
,
289 .parent
= TYPE_PMBUS_DEVICE
,
290 .instance_size
= sizeof(ISLState
),
291 .instance_init
= raa22xx_init
,
292 .class_init
= isl69260_class_init
,
295 static const TypeInfo raa229004_info
= {
296 .name
= TYPE_RAA229004
,
297 .parent
= TYPE_PMBUS_DEVICE
,
298 .instance_size
= sizeof(ISLState
),
299 .instance_init
= raa22xx_init
,
300 .class_init
= raa229004_class_init
,
303 static const TypeInfo raa228000_info
= {
304 .name
= TYPE_RAA228000
,
305 .parent
= TYPE_PMBUS_DEVICE
,
306 .instance_size
= sizeof(ISLState
),
307 .instance_init
= raa228000_init
,
308 .class_init
= raa228000_class_init
,
311 static void isl_pmbus_vr_register_types(void)
313 type_register_static(&isl69259_info
);
314 type_register_static(&isl69260_info
);
315 type_register_static(&raa228000_info
);
316 type_register_static(&raa229004_info
);
319 type_init(isl_pmbus_vr_register_types
)