
* Update to QEMU v9.0.0 --------- Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Fabiano Rosas <farosas@suse.de> Signed-off-by: Peter Xu <peterx@redhat.com> Signed-off-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Cédric Le Goater <clg@redhat.com> Signed-off-by: Zheyu Ma <zheyuma97@gmail.com> Signed-off-by: Ido Plat <ido.plat@ibm.com> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Markus Armbruster <armbru@redhat.com> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Signed-off-by: David Hildenbrand <david@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> Signed-off-by: Gregory Price <gregory.price@memverge.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Lorenz Brun <lorenz@brun.one> Signed-off-by: Yao Xingtao <yaoxt.fnst@fujitsu.com> Signed-off-by: Arnaud Minier <arnaud.minier@telecom-paris.fr> Signed-off-by: Inès Varhol <ines.varhol@telecom-paris.fr> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> Signed-off-by: Igor Mammedov <imammedo@redhat.com> Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Sven Schnelle <svens@stackframe.org> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com> Signed-off-by: Jason Wang <jasowang@redhat.com> Signed-off-by: Helge Deller <deller@gmx.de> Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Benjamin Gray <bgray@linux.ibm.com> Signed-off-by: Avihai Horon <avihaih@nvidia.com> Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> Signed-off-by: Joonas Kankaala <joonas.a.kankaala@gmail.com> Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Signed-off-by: Stefan Weil <sw@weilnetz.de> Signed-off-by: Zhao Liu <zhao1.liu@intel.com> Signed-off-by: Glenn Miles <milesg@linux.ibm.com> Signed-off-by: Oleg Sviridov <oleg.sviridov@red-soft.ru> Signed-off-by: Artem Chernyshev <artem.chernyshev@red-soft.ru> Signed-off-by: Yajun Wu <yajunw@nvidia.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Signed-off-by: Pierre-Clément Tosi <ptosi@google.com> Signed-off-by: Lei Wang <lei4.wang@intel.com> Signed-off-by: Wei Wang <wei.w.wang@intel.com> Signed-off-by: Martin Hundebøll <martin@geanix.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Signed-off-by: Wafer <wafer@jaguarmicro.com> Signed-off-by: Yuxue Liu <yuxue.liu@jaguarmicro.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com> Signed-off-by: Nguyen Dinh Phi <phind.uet@gmail.com> Signed-off-by: Zack Buhman <zack@buhman.org> Signed-off-by: Keith Packard <keithp@keithp.com> Signed-off-by: Yuquan Wang wangyuquan1236@phytium.com.cn Signed-off-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com> Signed-off-by: Cindy Lu <lulu@redhat.com> Co-authored-by: Peter Maydell <peter.maydell@linaro.org> Co-authored-by: Fabiano Rosas <farosas@suse.de> Co-authored-by: Peter Xu <peterx@redhat.com> Co-authored-by: Thomas Huth <thuth@redhat.com> Co-authored-by: Cédric Le Goater <clg@redhat.com> Co-authored-by: Zheyu Ma <zheyuma97@gmail.com> Co-authored-by: Ido Plat <ido.plat@ibm.com> Co-authored-by: Ilya Leoshkevich <iii@linux.ibm.com> Co-authored-by: Markus Armbruster <armbru@redhat.com> Co-authored-by: Marc-André Lureau <marcandre.lureau@redhat.com> Co-authored-by: Paolo Bonzini <pbonzini@redhat.com> Co-authored-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Co-authored-by: David Hildenbrand <david@redhat.com> Co-authored-by: Kevin Wolf <kwolf@redhat.com> Co-authored-by: Stefan Reiter <s.reiter@proxmox.com> Co-authored-by: Fiona Ebner <f.ebner@proxmox.com> Co-authored-by: Gregory Price <gregory.price@memverge.com> Co-authored-by: Lorenz Brun <lorenz@brun.one> Co-authored-by: Yao Xingtao <yaoxt.fnst@fujitsu.com> Co-authored-by: Philippe Mathieu-Daudé <philmd@linaro.org> Co-authored-by: Arnaud Minier <arnaud.minier@telecom-paris.fr> Co-authored-by: BALATON Zoltan <balaton@eik.bme.hu> Co-authored-by: Igor Mammedov <imammedo@redhat.com> Co-authored-by: Akihiko Odaki <akihiko.odaki@daynix.com> Co-authored-by: Richard Henderson <richard.henderson@linaro.org> Co-authored-by: Sven Schnelle <svens@stackframe.org> Co-authored-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Co-authored-by: Helge Deller <deller@kernel.org> Co-authored-by: Harsh Prateek Bora <harshpb@linux.ibm.com> Co-authored-by: Benjamin Gray <bgray@linux.ibm.com> Co-authored-by: Nicholas Piggin <npiggin@gmail.com> Co-authored-by: Avihai Horon <avihaih@nvidia.com> Co-authored-by: Michael Tokarev <mjt@tls.msk.ru> Co-authored-by: Joonas Kankaala <joonas.a.kankaala@gmail.com> Co-authored-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org> Co-authored-by: Stefan Weil <sw@weilnetz.de> Co-authored-by: Dayu Liu <liu.dayu@zte.com.cn> Co-authored-by: Zhao Liu <zhao1.liu@intel.com> Co-authored-by: Glenn Miles <milesg@linux.vnet.ibm.com> Co-authored-by: Artem Chernyshev <artem.chernyshev@red-soft.ru> Co-authored-by: Yajun Wu <yajunw@nvidia.com> Co-authored-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Co-authored-by: Pierre-Clément Tosi <ptosi@google.com> Co-authored-by: Wei Wang <wei.w.wang@intel.com> Co-authored-by: Martin Hundebøll <martin@geanix.com> Co-authored-by: Michael S. Tsirkin <mst@redhat.com> Co-authored-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Co-authored-by: Wafer <wafer@jaguarmicro.com> Co-authored-by: lyx634449800 <yuxue.liu@jaguarmicro.com> Co-authored-by: Gerd Hoffmann <kraxel@redhat.com> Co-authored-by: Nguyen Dinh Phi <phind.uet@gmail.com> Co-authored-by: Zack Buhman <zack@buhman.org> Co-authored-by: Keith Packard <keithp@keithp.com> Co-authored-by: Yuquan Wang <wangyuquan1236@phytium.com.cn> Co-authored-by: Matheus Tavares Bernardino <quic_mathbern@quicinc.com> Co-authored-by: Cindy Lu <lulu@redhat.com>
574 lines
22 KiB
C
574 lines
22 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Maxim MAX31785 PMBus 6-Channel Fan Controller
|
|
*
|
|
* Datasheet:
|
|
* https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf
|
|
*
|
|
* Copyright(c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "hw/i2c/pmbus_device.h"
|
|
#include "hw/irq.h"
|
|
#include "migration/vmstate.h"
|
|
#include "qapi/error.h"
|
|
#include "qapi/visitor.h"
|
|
#include "qemu/log.h"
|
|
#include "qemu/module.h"
|
|
|
|
#define TYPE_MAX31785 "max31785"
|
|
#define MAX31785(obj) OBJECT_CHECK(MAX31785State, (obj), TYPE_MAX31785)
|
|
|
|
/* MAX31785 mfr specific PMBus commands */
|
|
#define MAX31785_MFR_MODE 0xD1
|
|
#define MAX31785_MFR_PSEN_CONFIG 0xD2
|
|
#define MAX31785_MFR_VOUT_PEAK 0xD4
|
|
#define MAX31785_MFR_TEMPERATURE_PEAK 0xD6
|
|
#define MAX31785_MFR_VOUT_MIN 0xD7
|
|
#define MAX31785_MFR_FAULT_RESPONSE 0xD9
|
|
#define MAX31785_MFR_NV_FAULT_LOG 0xDC
|
|
#define MAX31785_MFR_TIME_COUNT 0xDD
|
|
#define MAX31785_MFR_TEMP_SENSOR_CONFIG 0xF0
|
|
#define MAX31785_MFR_FAN_CONFIG 0xF1
|
|
#define MAX31785_MFR_FAN_LUT 0xF2
|
|
#define MAX31785_MFR_READ_FAN_PWM 0xF3
|
|
#define MAX31785_MFR_FAN_FAULT_LIMIT 0xF5
|
|
#define MAX31785_MFR_FAN_WARN_LIMIT 0xF6
|
|
#define MAX31785_MFR_FAN_RUN_TIME 0xF7
|
|
#define MAX31785_MFR_FAN_PWM_AVG 0xF8
|
|
#define MAX31785_MFR_FAN_PWM2RPM 0xF9
|
|
|
|
/* defaults as per the data sheet */
|
|
#define MAX31785_DEFAULT_CAPABILITY 0x10
|
|
#define MAX31785_DEFAULT_VOUT_MODE 0x40
|
|
#define MAX31785_DEFAULT_VOUT_SCALE_MONITOR 0x7FFF
|
|
#define MAX31785_DEFAULT_FAN_COMMAND_1 0x7FFF
|
|
#define MAX31785_DEFAULT_OV_FAULT_LIMIT 0x7FFF
|
|
#define MAX31785_DEFAULT_OV_WARN_LIMIT 0x7FFF
|
|
#define MAX31785_DEFAULT_OT_FAULT_LIMIT 0x7FFF
|
|
#define MAX31785_DEFAULT_OT_WARN_LIMIT 0x7FFF
|
|
#define MAX31785_DEFAULT_PMBUS_REVISION 0x11
|
|
#define MAX31785_DEFAULT_MFR_ID 0x4D
|
|
#define MAX31785_DEFAULT_MFR_MODEL 0x53
|
|
#define MAX31785_DEFAULT_MFR_REVISION 0x3030
|
|
#define MAX31785A_DEFAULT_MFR_REVISION 0x3040
|
|
#define MAX31785B_DEFAULT_MFR_REVISION 0x3061
|
|
#define MAX31785B_DEFAULT_MFR_TEMPERATURE_PEAK 0x8000
|
|
#define MAX31785B_DEFAULT_MFR_VOUT_MIN 0x7FFF
|
|
#define MAX31785_DEFAULT_TEXT 0x3130313031303130
|
|
|
|
/* MAX31785 pages */
|
|
#define MAX31785_TOTAL_NUM_PAGES 23
|
|
#define MAX31785_FAN_PAGES 6
|
|
#define MAX31785_MIN_FAN_PAGE 0
|
|
#define MAX31785_MAX_FAN_PAGE 5
|
|
#define MAX31785_MIN_TEMP_PAGE 6
|
|
#define MAX31785_MAX_TEMP_PAGE 16
|
|
#define MAX31785_MIN_ADC_VOLTAGE_PAGE 17
|
|
#define MAX31785_MAX_ADC_VOLTAGE_PAGE 22
|
|
|
|
/* FAN_CONFIG_1_2 */
|
|
#define MAX31785_MFR_FAN_CONFIG 0xF1
|
|
#define MAX31785_FAN_CONFIG_ENABLE BIT(7)
|
|
#define MAX31785_FAN_CONFIG_RPM_PWM BIT(6)
|
|
#define MAX31785_FAN_CONFIG_PULSE(pulse) (pulse << 4)
|
|
#define MAX31785_DEFAULT_FAN_CONFIG_1_2(pulse) \
|
|
(MAX31785_FAN_CONFIG_ENABLE | MAX31785_FAN_CONFIG_PULSE(pulse))
|
|
#define MAX31785_DEFAULT_MFR_FAN_CONFIG 0x0000
|
|
|
|
/* fan speed in RPM */
|
|
#define MAX31785_DEFAULT_FAN_SPEED 0x7fff
|
|
#define MAX31785_DEFAULT_FAN_STATUS 0x00
|
|
|
|
#define MAX31785_DEFAULT_FAN_MAX_PWM 0x2710
|
|
|
|
/*
|
|
* MAX31785State:
|
|
* @code: The command code received
|
|
* @page: Each page corresponds to a device monitored by the Max 31785
|
|
* The page register determines the available commands depending on device
|
|
* _____________________________________________________________________________
|
|
* | 0 | Fan Connected to PWM0 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 1 | Fan Connected to PWM1 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 2 | Fan Connected to PWM2 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 3 | Fan Connected to PWM3 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 4 | Fan Connected to PWM4 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 5 | Fan Connected to PWM5 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 6 | Remote Thermal Diode Connected to ADC 0 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 7 | Remote Thermal Diode Connected to ADC 1 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 8 | Remote Thermal Diode Connected to ADC 2 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 9 | Remote Thermal Diode Connected to ADC 3 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 10 | Remote Thermal Diode Connected to ADC 4 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 11 | Remote Thermal Diode Connected to ADC 5 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 12 | Internal Temperature Sensor |
|
|
* |_______|___________________________________________________________________|
|
|
* | 13 | Remote I2C Temperature Sensor with Address 0 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 14 | Remote I2C Temperature Sensor with Address 1 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 15 | Remote I2C Temperature Sensor with Address 2 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 16 | Remote I2C Temperature Sensor with Address 3 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 17 | Remote I2C Temperature Sensor with Address 4 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 17 | Remote Voltage Connected to ADC0 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 18 | Remote Voltage Connected to ADC1 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 19 | Remote Voltage Connected to ADC2 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 20 | Remote Voltage Connected to ADC3 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 21 | Remote Voltage Connected to ADC4 |
|
|
* |_______|___________________________________________________________________|
|
|
* | 22 | Remote Voltage Connected to ADC5 |
|
|
* |_______|___________________________________________________________________|
|
|
* |23-254 | Reserved |
|
|
* |_______|___________________________________________________________________|
|
|
* | 255 | Applies to all pages |
|
|
* |_______|___________________________________________________________________|
|
|
*/
|
|
|
|
/* Place holder to save the max31785 mfr specific registers */
|
|
typedef struct MAX31785State {
|
|
PMBusDevice parent;
|
|
uint16_t mfr_mode[MAX31785_TOTAL_NUM_PAGES];
|
|
uint16_t vout_peak[MAX31785_TOTAL_NUM_PAGES];
|
|
uint16_t temperature_peak[MAX31785_TOTAL_NUM_PAGES];
|
|
uint16_t vout_min[MAX31785_TOTAL_NUM_PAGES];
|
|
uint8_t fault_response[MAX31785_TOTAL_NUM_PAGES];
|
|
uint32_t time_count[MAX31785_TOTAL_NUM_PAGES];
|
|
uint16_t temp_sensor_config[MAX31785_TOTAL_NUM_PAGES];
|
|
uint16_t fan_config[MAX31785_TOTAL_NUM_PAGES];
|
|
uint16_t read_fan_pwm[MAX31785_TOTAL_NUM_PAGES];
|
|
uint16_t fan_fault_limit[MAX31785_TOTAL_NUM_PAGES];
|
|
uint16_t fan_warn_limit[MAX31785_TOTAL_NUM_PAGES];
|
|
uint16_t fan_run_time[MAX31785_TOTAL_NUM_PAGES];
|
|
uint16_t fan_pwm_avg[MAX31785_TOTAL_NUM_PAGES];
|
|
uint64_t fan_pwm2rpm[MAX31785_TOTAL_NUM_PAGES];
|
|
uint64_t mfr_location;
|
|
uint64_t mfr_date;
|
|
uint64_t mfr_serial;
|
|
uint16_t mfr_revision;
|
|
} MAX31785State;
|
|
|
|
static uint8_t max31785_read_byte(PMBusDevice *pmdev)
|
|
{
|
|
MAX31785State *s = MAX31785(pmdev);
|
|
switch (pmdev->code) {
|
|
|
|
case PMBUS_FAN_CONFIG_1_2:
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send8(pmdev, pmdev->pages[pmdev->page].fan_config_1_2);
|
|
}
|
|
break;
|
|
|
|
case PMBUS_FAN_COMMAND_1:
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send16(pmdev, pmdev->pages[pmdev->page].fan_command_1);
|
|
}
|
|
break;
|
|
|
|
case PMBUS_READ_FAN_SPEED_1:
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send16(pmdev, pmdev->pages[pmdev->page].read_fan_speed_1);
|
|
}
|
|
break;
|
|
|
|
case PMBUS_STATUS_FANS_1_2:
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send16(pmdev, pmdev->pages[pmdev->page].status_fans_1_2);
|
|
}
|
|
break;
|
|
|
|
case PMBUS_MFR_REVISION:
|
|
pmbus_send16(pmdev, MAX31785_DEFAULT_MFR_REVISION);
|
|
break;
|
|
|
|
case PMBUS_MFR_ID:
|
|
pmbus_send8(pmdev, 0x4d); /* Maxim */
|
|
break;
|
|
|
|
case PMBUS_MFR_MODEL:
|
|
pmbus_send8(pmdev, 0x53);
|
|
break;
|
|
|
|
case PMBUS_MFR_LOCATION:
|
|
pmbus_send64(pmdev, s->mfr_location);
|
|
break;
|
|
|
|
case PMBUS_MFR_DATE:
|
|
pmbus_send64(pmdev, s->mfr_date);
|
|
break;
|
|
|
|
case PMBUS_MFR_SERIAL:
|
|
pmbus_send64(pmdev, s->mfr_serial);
|
|
break;
|
|
|
|
case MAX31785_MFR_MODE:
|
|
pmbus_send16(pmdev, s->mfr_mode[pmdev->page]);
|
|
break;
|
|
|
|
case MAX31785_MFR_VOUT_PEAK:
|
|
if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) &&
|
|
(pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) {
|
|
pmbus_send16(pmdev, s->vout_peak[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_TEMPERATURE_PEAK:
|
|
if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) &&
|
|
(pmdev->page <= MAX31785_MAX_TEMP_PAGE)) {
|
|
pmbus_send16(pmdev, s->temperature_peak[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_VOUT_MIN:
|
|
if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) &&
|
|
(pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) {
|
|
pmbus_send16(pmdev, s->vout_min[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAULT_RESPONSE:
|
|
pmbus_send8(pmdev, s->fault_response[pmdev->page]);
|
|
break;
|
|
|
|
case MAX31785_MFR_TIME_COUNT: /* R/W 32 */
|
|
pmbus_send32(pmdev, s->time_count[pmdev->page]);
|
|
break;
|
|
|
|
case MAX31785_MFR_TEMP_SENSOR_CONFIG: /* R/W 16 */
|
|
if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) &&
|
|
(pmdev->page <= MAX31785_MAX_TEMP_PAGE)) {
|
|
pmbus_send16(pmdev, s->temp_sensor_config[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_CONFIG: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send16(pmdev, s->fan_config[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_READ_FAN_PWM: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send16(pmdev, s->read_fan_pwm[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_FAULT_LIMIT: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send16(pmdev, s->fan_fault_limit[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_WARN_LIMIT: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send16(pmdev, s->fan_warn_limit[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_RUN_TIME: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send16(pmdev, s->fan_run_time[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_PWM_AVG: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send16(pmdev, s->fan_pwm_avg[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_PWM2RPM: /* R/W 64 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmbus_send64(pmdev, s->fan_pwm2rpm[pmdev->page]);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
qemu_log_mask(LOG_GUEST_ERROR,
|
|
"%s: reading from unsupported register: 0x%02x\n",
|
|
__func__, pmdev->code);
|
|
break;
|
|
}
|
|
|
|
return 0xFF;
|
|
}
|
|
|
|
static int max31785_write_data(PMBusDevice *pmdev, const uint8_t *buf,
|
|
uint8_t len)
|
|
{
|
|
MAX31785State *s = MAX31785(pmdev);
|
|
if (len == 0) {
|
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
pmdev->code = buf[0]; /* PMBus command code */
|
|
|
|
if (len == 1) {
|
|
return 0;
|
|
}
|
|
|
|
/* Exclude command code from buffer */
|
|
buf++;
|
|
len--;
|
|
|
|
switch (pmdev->code) {
|
|
|
|
case PMBUS_FAN_CONFIG_1_2:
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmdev->pages[pmdev->page].fan_config_1_2 = pmbus_receive8(pmdev);
|
|
}
|
|
break;
|
|
|
|
case PMBUS_FAN_COMMAND_1:
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
pmdev->pages[pmdev->page].fan_command_1 = pmbus_receive16(pmdev);
|
|
pmdev->pages[pmdev->page].read_fan_speed_1 =
|
|
((MAX31785_DEFAULT_FAN_SPEED / MAX31785_DEFAULT_FAN_MAX_PWM) *
|
|
pmdev->pages[pmdev->page].fan_command_1);
|
|
}
|
|
break;
|
|
|
|
case PMBUS_MFR_LOCATION: /* R/W 64 */
|
|
s->mfr_location = pmbus_receive64(pmdev);
|
|
break;
|
|
|
|
case PMBUS_MFR_DATE: /* R/W 64 */
|
|
s->mfr_date = pmbus_receive64(pmdev);
|
|
break;
|
|
|
|
case PMBUS_MFR_SERIAL: /* R/W 64 */
|
|
s->mfr_serial = pmbus_receive64(pmdev);
|
|
break;
|
|
|
|
case MAX31785_MFR_MODE: /* R/W word */
|
|
s->mfr_mode[pmdev->page] = pmbus_receive16(pmdev);
|
|
break;
|
|
|
|
case MAX31785_MFR_VOUT_PEAK: /* R/W word */
|
|
if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) &&
|
|
(pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) {
|
|
s->vout_peak[pmdev->page] = pmbus_receive16(pmdev);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_TEMPERATURE_PEAK: /* R/W word */
|
|
if ((pmdev->page >= 6) && (pmdev->page <= 16)) {
|
|
s->temperature_peak[pmdev->page] = pmbus_receive16(pmdev);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_VOUT_MIN: /* R/W word */
|
|
if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) &&
|
|
(pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) {
|
|
s->vout_min[pmdev->page] = pmbus_receive16(pmdev);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAULT_RESPONSE: /* R/W 8 */
|
|
s->fault_response[pmdev->page] = pmbus_receive8(pmdev);
|
|
break;
|
|
|
|
case MAX31785_MFR_TIME_COUNT: /* R/W 32 */
|
|
s->time_count[pmdev->page] = pmbus_receive32(pmdev);
|
|
break;
|
|
|
|
case MAX31785_MFR_TEMP_SENSOR_CONFIG: /* R/W 16 */
|
|
if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) &&
|
|
(pmdev->page <= MAX31785_MAX_TEMP_PAGE)) {
|
|
s->temp_sensor_config[pmdev->page] = pmbus_receive16(pmdev);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_CONFIG: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
s->fan_config[pmdev->page] = pmbus_receive16(pmdev);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_FAULT_LIMIT: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
s->fan_fault_limit[pmdev->page] = pmbus_receive16(pmdev);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_WARN_LIMIT: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
s->fan_warn_limit[pmdev->page] = pmbus_receive16(pmdev);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_RUN_TIME: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
s->fan_run_time[pmdev->page] = pmbus_receive16(pmdev);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_PWM_AVG: /* R/W 16 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
s->fan_pwm_avg[pmdev->page] = pmbus_receive16(pmdev);
|
|
}
|
|
break;
|
|
|
|
case MAX31785_MFR_FAN_PWM2RPM: /* R/W 64 */
|
|
if (pmdev->page <= MAX31785_MAX_FAN_PAGE) {
|
|
s->fan_pwm2rpm[pmdev->page] = pmbus_receive64(pmdev);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
qemu_log_mask(LOG_GUEST_ERROR,
|
|
"%s: writing to unsupported register: 0x%02x\n",
|
|
__func__, pmdev->code);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void max31785_exit_reset(Object *obj)
|
|
{
|
|
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
|
|
MAX31785State *s = MAX31785(obj);
|
|
|
|
pmdev->capability = MAX31785_DEFAULT_CAPABILITY;
|
|
|
|
for (int i = MAX31785_MIN_FAN_PAGE; i <= MAX31785_MAX_FAN_PAGE; i++) {
|
|
pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE;
|
|
pmdev->pages[i].fan_command_1 = MAX31785_DEFAULT_FAN_COMMAND_1;
|
|
pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION;
|
|
pmdev->pages[i].fan_config_1_2 = MAX31785_DEFAULT_FAN_CONFIG_1_2(0);
|
|
pmdev->pages[i].read_fan_speed_1 = MAX31785_DEFAULT_FAN_SPEED;
|
|
pmdev->pages[i].status_fans_1_2 = MAX31785_DEFAULT_FAN_STATUS;
|
|
}
|
|
|
|
for (int i = MAX31785_MIN_TEMP_PAGE; i <= MAX31785_MAX_TEMP_PAGE; i++) {
|
|
pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE;
|
|
pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION;
|
|
pmdev->pages[i].ot_fault_limit = MAX31785_DEFAULT_OT_FAULT_LIMIT;
|
|
pmdev->pages[i].ot_warn_limit = MAX31785_DEFAULT_OT_WARN_LIMIT;
|
|
}
|
|
|
|
for (int i = MAX31785_MIN_ADC_VOLTAGE_PAGE;
|
|
i <= MAX31785_MAX_ADC_VOLTAGE_PAGE;
|
|
i++) {
|
|
pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE;
|
|
pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION;
|
|
pmdev->pages[i].vout_scale_monitor =
|
|
MAX31785_DEFAULT_VOUT_SCALE_MONITOR;
|
|
pmdev->pages[i].vout_ov_fault_limit = MAX31785_DEFAULT_OV_FAULT_LIMIT;
|
|
pmdev->pages[i].vout_ov_warn_limit = MAX31785_DEFAULT_OV_WARN_LIMIT;
|
|
}
|
|
|
|
s->mfr_location = MAX31785_DEFAULT_TEXT;
|
|
s->mfr_date = MAX31785_DEFAULT_TEXT;
|
|
s->mfr_serial = MAX31785_DEFAULT_TEXT;
|
|
}
|
|
|
|
static const VMStateDescription vmstate_max31785 = {
|
|
.name = TYPE_MAX31785,
|
|
.version_id = 0,
|
|
.minimum_version_id = 0,
|
|
.fields = (const VMStateField[]){
|
|
VMSTATE_PMBUS_DEVICE(parent, MAX31785State),
|
|
VMSTATE_UINT16_ARRAY(mfr_mode, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT16_ARRAY(vout_peak, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT16_ARRAY(temperature_peak, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT16_ARRAY(vout_min, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT8_ARRAY(fault_response, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT32_ARRAY(time_count, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT16_ARRAY(temp_sensor_config, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT16_ARRAY(fan_config, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT16_ARRAY(read_fan_pwm, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT16_ARRAY(fan_fault_limit, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT16_ARRAY(fan_warn_limit, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT16_ARRAY(fan_run_time, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT16_ARRAY(fan_pwm_avg, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT64_ARRAY(fan_pwm2rpm, MAX31785State,
|
|
MAX31785_TOTAL_NUM_PAGES),
|
|
VMSTATE_UINT64(mfr_location, MAX31785State),
|
|
VMSTATE_UINT64(mfr_date, MAX31785State),
|
|
VMSTATE_UINT64(mfr_serial, MAX31785State),
|
|
VMSTATE_END_OF_LIST()
|
|
}
|
|
};
|
|
|
|
static void max31785_init(Object *obj)
|
|
{
|
|
PMBusDevice *pmdev = PMBUS_DEVICE(obj);
|
|
|
|
for (int i = MAX31785_MIN_FAN_PAGE; i <= MAX31785_MAX_FAN_PAGE; i++) {
|
|
pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE);
|
|
}
|
|
|
|
for (int i = MAX31785_MIN_TEMP_PAGE; i <= MAX31785_MAX_TEMP_PAGE; i++) {
|
|
pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE | PB_HAS_TEMPERATURE);
|
|
}
|
|
|
|
for (int i = MAX31785_MIN_ADC_VOLTAGE_PAGE;
|
|
i <= MAX31785_MAX_ADC_VOLTAGE_PAGE;
|
|
i++) {
|
|
pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE | PB_HAS_VOUT |
|
|
PB_HAS_VOUT_RATING);
|
|
}
|
|
}
|
|
|
|
static void max31785_class_init(ObjectClass *klass, void *data)
|
|
{
|
|
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
|
PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass);
|
|
dc->desc = "Maxim MAX31785 6-Channel Fan Controller";
|
|
dc->vmsd = &vmstate_max31785;
|
|
k->write_data = max31785_write_data;
|
|
k->receive_byte = max31785_read_byte;
|
|
k->device_num_pages = MAX31785_TOTAL_NUM_PAGES;
|
|
rc->phases.exit = max31785_exit_reset;
|
|
}
|
|
|
|
static const TypeInfo max31785_info = {
|
|
.name = TYPE_MAX31785,
|
|
.parent = TYPE_PMBUS_DEVICE,
|
|
.instance_size = sizeof(MAX31785State),
|
|
.instance_init = max31785_init,
|
|
.class_init = max31785_class_init,
|
|
};
|
|
|
|
static void max31785_register_types(void)
|
|
{
|
|
type_register_static(&max31785_info);
|
|
}
|
|
|
|
type_init(max31785_register_types)
|