162365482SMaheswara Kurapati // SPDX-License-Identifier: GPL-2.0-or-later 262365482SMaheswara Kurapati /* 362365482SMaheswara Kurapati * Maxim MAX31785 PMBus 6-Channel Fan Controller 462365482SMaheswara Kurapati * 562365482SMaheswara Kurapati * Datasheet: 662365482SMaheswara Kurapati * https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf 762365482SMaheswara Kurapati * 862365482SMaheswara Kurapati * Copyright(c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 962365482SMaheswara Kurapati */ 1062365482SMaheswara Kurapati 1162365482SMaheswara Kurapati #include "qemu/osdep.h" 1262365482SMaheswara Kurapati #include "hw/i2c/pmbus_device.h" 1362365482SMaheswara Kurapati #include "hw/irq.h" 1462365482SMaheswara Kurapati #include "migration/vmstate.h" 1562365482SMaheswara Kurapati #include "qapi/error.h" 1662365482SMaheswara Kurapati #include "qapi/visitor.h" 1762365482SMaheswara Kurapati #include "qemu/log.h" 1862365482SMaheswara Kurapati #include "qemu/module.h" 1962365482SMaheswara Kurapati 2062365482SMaheswara Kurapati #define TYPE_MAX31785 "max31785" 2162365482SMaheswara Kurapati #define MAX31785(obj) OBJECT_CHECK(MAX31785State, (obj), TYPE_MAX31785) 2262365482SMaheswara Kurapati 2362365482SMaheswara Kurapati /* MAX31785 mfr specific PMBus commands */ 2462365482SMaheswara Kurapati #define MAX31785_MFR_MODE 0xD1 2562365482SMaheswara Kurapati #define MAX31785_MFR_PSEN_CONFIG 0xD2 2662365482SMaheswara Kurapati #define MAX31785_MFR_VOUT_PEAK 0xD4 2762365482SMaheswara Kurapati #define MAX31785_MFR_TEMPERATURE_PEAK 0xD6 2862365482SMaheswara Kurapati #define MAX31785_MFR_VOUT_MIN 0xD7 2962365482SMaheswara Kurapati #define MAX31785_MFR_FAULT_RESPONSE 0xD9 3062365482SMaheswara Kurapati #define MAX31785_MFR_NV_FAULT_LOG 0xDC 3162365482SMaheswara Kurapati #define MAX31785_MFR_TIME_COUNT 0xDD 3262365482SMaheswara Kurapati #define MAX31785_MFR_TEMP_SENSOR_CONFIG 0xF0 3362365482SMaheswara Kurapati #define MAX31785_MFR_FAN_CONFIG 0xF1 3462365482SMaheswara Kurapati #define MAX31785_MFR_FAN_LUT 0xF2 3562365482SMaheswara Kurapati #define MAX31785_MFR_READ_FAN_PWM 0xF3 3662365482SMaheswara Kurapati #define MAX31785_MFR_FAN_FAULT_LIMIT 0xF5 3762365482SMaheswara Kurapati #define MAX31785_MFR_FAN_WARN_LIMIT 0xF6 3862365482SMaheswara Kurapati #define MAX31785_MFR_FAN_RUN_TIME 0xF7 3962365482SMaheswara Kurapati #define MAX31785_MFR_FAN_PWM_AVG 0xF8 4062365482SMaheswara Kurapati #define MAX31785_MFR_FAN_PWM2RPM 0xF9 4162365482SMaheswara Kurapati 4262365482SMaheswara Kurapati /* defaults as per the data sheet */ 4362365482SMaheswara Kurapati #define MAX31785_DEFAULT_CAPABILITY 0x10 4462365482SMaheswara Kurapati #define MAX31785_DEFAULT_VOUT_MODE 0x40 4562365482SMaheswara Kurapati #define MAX31785_DEFAULT_VOUT_SCALE_MONITOR 0x7FFF 4662365482SMaheswara Kurapati #define MAX31785_DEFAULT_FAN_COMMAND_1 0x7FFF 4762365482SMaheswara Kurapati #define MAX31785_DEFAULT_OV_FAULT_LIMIT 0x7FFF 4862365482SMaheswara Kurapati #define MAX31785_DEFAULT_OV_WARN_LIMIT 0x7FFF 4962365482SMaheswara Kurapati #define MAX31785_DEFAULT_OT_FAULT_LIMIT 0x7FFF 5062365482SMaheswara Kurapati #define MAX31785_DEFAULT_OT_WARN_LIMIT 0x7FFF 5162365482SMaheswara Kurapati #define MAX31785_DEFAULT_PMBUS_REVISION 0x11 5262365482SMaheswara Kurapati #define MAX31785_DEFAULT_MFR_ID 0x4D 5362365482SMaheswara Kurapati #define MAX31785_DEFAULT_MFR_MODEL 0x53 5462365482SMaheswara Kurapati #define MAX31785_DEFAULT_MFR_REVISION 0x3030 5562365482SMaheswara Kurapati #define MAX31785A_DEFAULT_MFR_REVISION 0x3040 5662365482SMaheswara Kurapati #define MAX31785B_DEFAULT_MFR_REVISION 0x3061 5762365482SMaheswara Kurapati #define MAX31785B_DEFAULT_MFR_TEMPERATURE_PEAK 0x8000 5862365482SMaheswara Kurapati #define MAX31785B_DEFAULT_MFR_VOUT_MIN 0x7FFF 5962365482SMaheswara Kurapati #define MAX31785_DEFAULT_TEXT 0x3130313031303130 6062365482SMaheswara Kurapati 6162365482SMaheswara Kurapati /* MAX31785 pages */ 6262365482SMaheswara Kurapati #define MAX31785_TOTAL_NUM_PAGES 23 6362365482SMaheswara Kurapati #define MAX31785_FAN_PAGES 6 6462365482SMaheswara Kurapati #define MAX31785_MIN_FAN_PAGE 0 6562365482SMaheswara Kurapati #define MAX31785_MAX_FAN_PAGE 5 6662365482SMaheswara Kurapati #define MAX31785_MIN_TEMP_PAGE 6 6762365482SMaheswara Kurapati #define MAX31785_MAX_TEMP_PAGE 16 6862365482SMaheswara Kurapati #define MAX31785_MIN_ADC_VOLTAGE_PAGE 17 6962365482SMaheswara Kurapati #define MAX31785_MAX_ADC_VOLTAGE_PAGE 22 7062365482SMaheswara Kurapati 7162365482SMaheswara Kurapati /* FAN_CONFIG_1_2 */ 7262365482SMaheswara Kurapati #define MAX31785_MFR_FAN_CONFIG 0xF1 7362365482SMaheswara Kurapati #define MAX31785_FAN_CONFIG_ENABLE BIT(7) 7462365482SMaheswara Kurapati #define MAX31785_FAN_CONFIG_RPM_PWM BIT(6) 7562365482SMaheswara Kurapati #define MAX31785_FAN_CONFIG_PULSE(pulse) (pulse << 4) 7662365482SMaheswara Kurapati #define MAX31785_DEFAULT_FAN_CONFIG_1_2(pulse) \ 7762365482SMaheswara Kurapati (MAX31785_FAN_CONFIG_ENABLE | MAX31785_FAN_CONFIG_PULSE(pulse)) 7862365482SMaheswara Kurapati #define MAX31785_DEFAULT_MFR_FAN_CONFIG 0x0000 7962365482SMaheswara Kurapati 8062365482SMaheswara Kurapati /* fan speed in RPM */ 8162365482SMaheswara Kurapati #define MAX31785_DEFAULT_FAN_SPEED 0x7fff 8262365482SMaheswara Kurapati #define MAX31785_DEFAULT_FAN_STATUS 0x00 8362365482SMaheswara Kurapati 8462365482SMaheswara Kurapati #define MAX31785_DEFAULT_FAN_MAX_PWM 0x2710 8562365482SMaheswara Kurapati 8662365482SMaheswara Kurapati /* 8762365482SMaheswara Kurapati * MAX31785State: 8862365482SMaheswara Kurapati * @code: The command code received 8962365482SMaheswara Kurapati * @page: Each page corresponds to a device monitored by the Max 31785 9062365482SMaheswara Kurapati * The page register determines the available commands depending on device 9162365482SMaheswara Kurapati * _____________________________________________________________________________ 9262365482SMaheswara Kurapati * | 0 | Fan Connected to PWM0 | 9362365482SMaheswara Kurapati * |_______|___________________________________________________________________| 9462365482SMaheswara Kurapati * | 1 | Fan Connected to PWM1 | 9562365482SMaheswara Kurapati * |_______|___________________________________________________________________| 9662365482SMaheswara Kurapati * | 2 | Fan Connected to PWM2 | 9762365482SMaheswara Kurapati * |_______|___________________________________________________________________| 9862365482SMaheswara Kurapati * | 3 | Fan Connected to PWM3 | 9962365482SMaheswara Kurapati * |_______|___________________________________________________________________| 10062365482SMaheswara Kurapati * | 4 | Fan Connected to PWM4 | 10162365482SMaheswara Kurapati * |_______|___________________________________________________________________| 10262365482SMaheswara Kurapati * | 5 | Fan Connected to PWM5 | 10362365482SMaheswara Kurapati * |_______|___________________________________________________________________| 10462365482SMaheswara Kurapati * | 6 | Remote Thermal Diode Connected to ADC 0 | 10562365482SMaheswara Kurapati * |_______|___________________________________________________________________| 10662365482SMaheswara Kurapati * | 7 | Remote Thermal Diode Connected to ADC 1 | 10762365482SMaheswara Kurapati * |_______|___________________________________________________________________| 10862365482SMaheswara Kurapati * | 8 | Remote Thermal Diode Connected to ADC 2 | 10962365482SMaheswara Kurapati * |_______|___________________________________________________________________| 11062365482SMaheswara Kurapati * | 9 | Remote Thermal Diode Connected to ADC 3 | 11162365482SMaheswara Kurapati * |_______|___________________________________________________________________| 11262365482SMaheswara Kurapati * | 10 | Remote Thermal Diode Connected to ADC 4 | 11362365482SMaheswara Kurapati * |_______|___________________________________________________________________| 11462365482SMaheswara Kurapati * | 11 | Remote Thermal Diode Connected to ADC 5 | 11562365482SMaheswara Kurapati * |_______|___________________________________________________________________| 11662365482SMaheswara Kurapati * | 12 | Internal Temperature Sensor | 11762365482SMaheswara Kurapati * |_______|___________________________________________________________________| 11862365482SMaheswara Kurapati * | 13 | Remote I2C Temperature Sensor with Address 0 | 11962365482SMaheswara Kurapati * |_______|___________________________________________________________________| 12062365482SMaheswara Kurapati * | 14 | Remote I2C Temperature Sensor with Address 1 | 12162365482SMaheswara Kurapati * |_______|___________________________________________________________________| 12262365482SMaheswara Kurapati * | 15 | Remote I2C Temperature Sensor with Address 2 | 12362365482SMaheswara Kurapati * |_______|___________________________________________________________________| 12462365482SMaheswara Kurapati * | 16 | Remote I2C Temperature Sensor with Address 3 | 12562365482SMaheswara Kurapati * |_______|___________________________________________________________________| 12662365482SMaheswara Kurapati * | 17 | Remote I2C Temperature Sensor with Address 4 | 12762365482SMaheswara Kurapati * |_______|___________________________________________________________________| 12862365482SMaheswara Kurapati * | 17 | Remote Voltage Connected to ADC0 | 12962365482SMaheswara Kurapati * |_______|___________________________________________________________________| 13062365482SMaheswara Kurapati * | 18 | Remote Voltage Connected to ADC1 | 13162365482SMaheswara Kurapati * |_______|___________________________________________________________________| 13262365482SMaheswara Kurapati * | 19 | Remote Voltage Connected to ADC2 | 13362365482SMaheswara Kurapati * |_______|___________________________________________________________________| 13462365482SMaheswara Kurapati * | 20 | Remote Voltage Connected to ADC3 | 13562365482SMaheswara Kurapati * |_______|___________________________________________________________________| 13662365482SMaheswara Kurapati * | 21 | Remote Voltage Connected to ADC4 | 13762365482SMaheswara Kurapati * |_______|___________________________________________________________________| 13862365482SMaheswara Kurapati * | 22 | Remote Voltage Connected to ADC5 | 13962365482SMaheswara Kurapati * |_______|___________________________________________________________________| 14062365482SMaheswara Kurapati * |23-254 | Reserved | 14162365482SMaheswara Kurapati * |_______|___________________________________________________________________| 14262365482SMaheswara Kurapati * | 255 | Applies to all pages | 14362365482SMaheswara Kurapati * |_______|___________________________________________________________________| 14462365482SMaheswara Kurapati */ 14562365482SMaheswara Kurapati 14662365482SMaheswara Kurapati /* Place holder to save the max31785 mfr specific registers */ 14762365482SMaheswara Kurapati typedef struct MAX31785State { 14862365482SMaheswara Kurapati PMBusDevice parent; 14962365482SMaheswara Kurapati uint16_t mfr_mode[MAX31785_TOTAL_NUM_PAGES]; 15062365482SMaheswara Kurapati uint16_t vout_peak[MAX31785_TOTAL_NUM_PAGES]; 15162365482SMaheswara Kurapati uint16_t temperature_peak[MAX31785_TOTAL_NUM_PAGES]; 15262365482SMaheswara Kurapati uint16_t vout_min[MAX31785_TOTAL_NUM_PAGES]; 15362365482SMaheswara Kurapati uint8_t fault_response[MAX31785_TOTAL_NUM_PAGES]; 15462365482SMaheswara Kurapati uint32_t time_count[MAX31785_TOTAL_NUM_PAGES]; 15562365482SMaheswara Kurapati uint16_t temp_sensor_config[MAX31785_TOTAL_NUM_PAGES]; 15662365482SMaheswara Kurapati uint16_t fan_config[MAX31785_TOTAL_NUM_PAGES]; 15762365482SMaheswara Kurapati uint16_t read_fan_pwm[MAX31785_TOTAL_NUM_PAGES]; 15862365482SMaheswara Kurapati uint16_t fan_fault_limit[MAX31785_TOTAL_NUM_PAGES]; 15962365482SMaheswara Kurapati uint16_t fan_warn_limit[MAX31785_TOTAL_NUM_PAGES]; 16062365482SMaheswara Kurapati uint16_t fan_run_time[MAX31785_TOTAL_NUM_PAGES]; 16162365482SMaheswara Kurapati uint16_t fan_pwm_avg[MAX31785_TOTAL_NUM_PAGES]; 16262365482SMaheswara Kurapati uint64_t fan_pwm2rpm[MAX31785_TOTAL_NUM_PAGES]; 16362365482SMaheswara Kurapati uint64_t mfr_location; 16462365482SMaheswara Kurapati uint64_t mfr_date; 16562365482SMaheswara Kurapati uint64_t mfr_serial; 16662365482SMaheswara Kurapati uint16_t mfr_revision; 16762365482SMaheswara Kurapati } MAX31785State; 16862365482SMaheswara Kurapati 16962365482SMaheswara Kurapati static uint8_t max31785_read_byte(PMBusDevice *pmdev) 17062365482SMaheswara Kurapati { 17162365482SMaheswara Kurapati MAX31785State *s = MAX31785(pmdev); 17262365482SMaheswara Kurapati switch (pmdev->code) { 17362365482SMaheswara Kurapati 17462365482SMaheswara Kurapati case PMBUS_FAN_CONFIG_1_2: 17562365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 17662365482SMaheswara Kurapati pmbus_send8(pmdev, pmdev->pages[pmdev->page].fan_config_1_2); 17762365482SMaheswara Kurapati } 17862365482SMaheswara Kurapati break; 17962365482SMaheswara Kurapati 18062365482SMaheswara Kurapati case PMBUS_FAN_COMMAND_1: 18162365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 18262365482SMaheswara Kurapati pmbus_send16(pmdev, pmdev->pages[pmdev->page].fan_command_1); 18362365482SMaheswara Kurapati } 18462365482SMaheswara Kurapati break; 18562365482SMaheswara Kurapati 18662365482SMaheswara Kurapati case PMBUS_READ_FAN_SPEED_1: 18762365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 18862365482SMaheswara Kurapati pmbus_send16(pmdev, pmdev->pages[pmdev->page].read_fan_speed_1); 18962365482SMaheswara Kurapati } 19062365482SMaheswara Kurapati break; 19162365482SMaheswara Kurapati 19262365482SMaheswara Kurapati case PMBUS_STATUS_FANS_1_2: 19362365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 19462365482SMaheswara Kurapati pmbus_send16(pmdev, pmdev->pages[pmdev->page].status_fans_1_2); 19562365482SMaheswara Kurapati } 19662365482SMaheswara Kurapati break; 19762365482SMaheswara Kurapati 19862365482SMaheswara Kurapati case PMBUS_MFR_REVISION: 19962365482SMaheswara Kurapati pmbus_send16(pmdev, MAX31785_DEFAULT_MFR_REVISION); 20062365482SMaheswara Kurapati break; 20162365482SMaheswara Kurapati 20262365482SMaheswara Kurapati case PMBUS_MFR_ID: 20362365482SMaheswara Kurapati pmbus_send8(pmdev, 0x4d); /* Maxim */ 20462365482SMaheswara Kurapati break; 20562365482SMaheswara Kurapati 20662365482SMaheswara Kurapati case PMBUS_MFR_MODEL: 20762365482SMaheswara Kurapati pmbus_send8(pmdev, 0x53); 20862365482SMaheswara Kurapati break; 20962365482SMaheswara Kurapati 21062365482SMaheswara Kurapati case PMBUS_MFR_LOCATION: 21162365482SMaheswara Kurapati pmbus_send64(pmdev, s->mfr_location); 21262365482SMaheswara Kurapati break; 21362365482SMaheswara Kurapati 21462365482SMaheswara Kurapati case PMBUS_MFR_DATE: 21562365482SMaheswara Kurapati pmbus_send64(pmdev, s->mfr_date); 21662365482SMaheswara Kurapati break; 21762365482SMaheswara Kurapati 21862365482SMaheswara Kurapati case PMBUS_MFR_SERIAL: 21962365482SMaheswara Kurapati pmbus_send64(pmdev, s->mfr_serial); 22062365482SMaheswara Kurapati break; 22162365482SMaheswara Kurapati 22262365482SMaheswara Kurapati case MAX31785_MFR_MODE: 22362365482SMaheswara Kurapati pmbus_send16(pmdev, s->mfr_mode[pmdev->page]); 22462365482SMaheswara Kurapati break; 22562365482SMaheswara Kurapati 22662365482SMaheswara Kurapati case MAX31785_MFR_VOUT_PEAK: 22762365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && 22862365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { 22962365482SMaheswara Kurapati pmbus_send16(pmdev, s->vout_peak[pmdev->page]); 23062365482SMaheswara Kurapati } 23162365482SMaheswara Kurapati break; 23262365482SMaheswara Kurapati 23362365482SMaheswara Kurapati case MAX31785_MFR_TEMPERATURE_PEAK: 23462365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) && 23562365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_TEMP_PAGE)) { 23662365482SMaheswara Kurapati pmbus_send16(pmdev, s->temperature_peak[pmdev->page]); 23762365482SMaheswara Kurapati } 23862365482SMaheswara Kurapati break; 23962365482SMaheswara Kurapati 24062365482SMaheswara Kurapati case MAX31785_MFR_VOUT_MIN: 24162365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && 24262365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { 24362365482SMaheswara Kurapati pmbus_send16(pmdev, s->vout_min[pmdev->page]); 24462365482SMaheswara Kurapati } 24562365482SMaheswara Kurapati break; 24662365482SMaheswara Kurapati 24762365482SMaheswara Kurapati case MAX31785_MFR_FAULT_RESPONSE: 24862365482SMaheswara Kurapati pmbus_send8(pmdev, s->fault_response[pmdev->page]); 24962365482SMaheswara Kurapati break; 25062365482SMaheswara Kurapati 25162365482SMaheswara Kurapati case MAX31785_MFR_TIME_COUNT: /* R/W 32 */ 25262365482SMaheswara Kurapati pmbus_send32(pmdev, s->time_count[pmdev->page]); 25362365482SMaheswara Kurapati break; 25462365482SMaheswara Kurapati 25562365482SMaheswara Kurapati case MAX31785_MFR_TEMP_SENSOR_CONFIG: /* R/W 16 */ 25662365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) && 25762365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_TEMP_PAGE)) { 25862365482SMaheswara Kurapati pmbus_send16(pmdev, s->temp_sensor_config[pmdev->page]); 25962365482SMaheswara Kurapati } 26062365482SMaheswara Kurapati break; 26162365482SMaheswara Kurapati 26262365482SMaheswara Kurapati case MAX31785_MFR_FAN_CONFIG: /* R/W 16 */ 26362365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 26462365482SMaheswara Kurapati pmbus_send16(pmdev, s->fan_config[pmdev->page]); 26562365482SMaheswara Kurapati } 26662365482SMaheswara Kurapati break; 26762365482SMaheswara Kurapati 26862365482SMaheswara Kurapati case MAX31785_MFR_READ_FAN_PWM: /* R/W 16 */ 26962365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 27062365482SMaheswara Kurapati pmbus_send16(pmdev, s->read_fan_pwm[pmdev->page]); 27162365482SMaheswara Kurapati } 27262365482SMaheswara Kurapati break; 27362365482SMaheswara Kurapati 27462365482SMaheswara Kurapati case MAX31785_MFR_FAN_FAULT_LIMIT: /* R/W 16 */ 27562365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 27662365482SMaheswara Kurapati pmbus_send16(pmdev, s->fan_fault_limit[pmdev->page]); 27762365482SMaheswara Kurapati } 27862365482SMaheswara Kurapati break; 27962365482SMaheswara Kurapati 28062365482SMaheswara Kurapati case MAX31785_MFR_FAN_WARN_LIMIT: /* R/W 16 */ 28162365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 28262365482SMaheswara Kurapati pmbus_send16(pmdev, s->fan_warn_limit[pmdev->page]); 28362365482SMaheswara Kurapati } 28462365482SMaheswara Kurapati break; 28562365482SMaheswara Kurapati 28662365482SMaheswara Kurapati case MAX31785_MFR_FAN_RUN_TIME: /* R/W 16 */ 28762365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 28862365482SMaheswara Kurapati pmbus_send16(pmdev, s->fan_run_time[pmdev->page]); 28962365482SMaheswara Kurapati } 29062365482SMaheswara Kurapati break; 29162365482SMaheswara Kurapati 29262365482SMaheswara Kurapati case MAX31785_MFR_FAN_PWM_AVG: /* R/W 16 */ 29362365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 29462365482SMaheswara Kurapati pmbus_send16(pmdev, s->fan_pwm_avg[pmdev->page]); 29562365482SMaheswara Kurapati } 29662365482SMaheswara Kurapati break; 29762365482SMaheswara Kurapati 29862365482SMaheswara Kurapati case MAX31785_MFR_FAN_PWM2RPM: /* R/W 64 */ 29962365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 30062365482SMaheswara Kurapati pmbus_send64(pmdev, s->fan_pwm2rpm[pmdev->page]); 30162365482SMaheswara Kurapati } 30262365482SMaheswara Kurapati break; 30362365482SMaheswara Kurapati 30462365482SMaheswara Kurapati default: 30562365482SMaheswara Kurapati qemu_log_mask(LOG_GUEST_ERROR, 30662365482SMaheswara Kurapati "%s: reading from unsupported register: 0x%02x\n", 30762365482SMaheswara Kurapati __func__, pmdev->code); 30862365482SMaheswara Kurapati break; 30962365482SMaheswara Kurapati } 31062365482SMaheswara Kurapati 31162365482SMaheswara Kurapati return 0xFF; 31262365482SMaheswara Kurapati } 31362365482SMaheswara Kurapati 31462365482SMaheswara Kurapati static int max31785_write_data(PMBusDevice *pmdev, const uint8_t *buf, 31562365482SMaheswara Kurapati uint8_t len) 31662365482SMaheswara Kurapati { 31762365482SMaheswara Kurapati MAX31785State *s = MAX31785(pmdev); 31862365482SMaheswara Kurapati if (len == 0) { 31962365482SMaheswara Kurapati qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__); 32062365482SMaheswara Kurapati return -1; 32162365482SMaheswara Kurapati } 32262365482SMaheswara Kurapati 32362365482SMaheswara Kurapati pmdev->code = buf[0]; /* PMBus command code */ 32462365482SMaheswara Kurapati 32562365482SMaheswara Kurapati if (len == 1) { 32662365482SMaheswara Kurapati return 0; 32762365482SMaheswara Kurapati } 32862365482SMaheswara Kurapati 32962365482SMaheswara Kurapati /* Exclude command code from buffer */ 33062365482SMaheswara Kurapati buf++; 33162365482SMaheswara Kurapati len--; 33262365482SMaheswara Kurapati 33362365482SMaheswara Kurapati switch (pmdev->code) { 33462365482SMaheswara Kurapati 33562365482SMaheswara Kurapati case PMBUS_FAN_CONFIG_1_2: 33662365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 33762365482SMaheswara Kurapati pmdev->pages[pmdev->page].fan_config_1_2 = pmbus_receive8(pmdev); 33862365482SMaheswara Kurapati } 33962365482SMaheswara Kurapati break; 34062365482SMaheswara Kurapati 34162365482SMaheswara Kurapati case PMBUS_FAN_COMMAND_1: 34262365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 34362365482SMaheswara Kurapati pmdev->pages[pmdev->page].fan_command_1 = pmbus_receive16(pmdev); 34462365482SMaheswara Kurapati pmdev->pages[pmdev->page].read_fan_speed_1 = 34562365482SMaheswara Kurapati ((MAX31785_DEFAULT_FAN_SPEED / MAX31785_DEFAULT_FAN_MAX_PWM) * 34662365482SMaheswara Kurapati pmdev->pages[pmdev->page].fan_command_1); 34762365482SMaheswara Kurapati } 34862365482SMaheswara Kurapati break; 34962365482SMaheswara Kurapati 35062365482SMaheswara Kurapati case PMBUS_MFR_LOCATION: /* R/W 64 */ 35162365482SMaheswara Kurapati s->mfr_location = pmbus_receive64(pmdev); 35262365482SMaheswara Kurapati break; 35362365482SMaheswara Kurapati 35462365482SMaheswara Kurapati case PMBUS_MFR_DATE: /* R/W 64 */ 35562365482SMaheswara Kurapati s->mfr_date = pmbus_receive64(pmdev); 35662365482SMaheswara Kurapati break; 35762365482SMaheswara Kurapati 35862365482SMaheswara Kurapati case PMBUS_MFR_SERIAL: /* R/W 64 */ 35962365482SMaheswara Kurapati s->mfr_serial = pmbus_receive64(pmdev); 36062365482SMaheswara Kurapati break; 36162365482SMaheswara Kurapati 36262365482SMaheswara Kurapati case MAX31785_MFR_MODE: /* R/W word */ 36362365482SMaheswara Kurapati s->mfr_mode[pmdev->page] = pmbus_receive16(pmdev); 36462365482SMaheswara Kurapati break; 36562365482SMaheswara Kurapati 36662365482SMaheswara Kurapati case MAX31785_MFR_VOUT_PEAK: /* R/W word */ 36762365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && 36862365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { 36962365482SMaheswara Kurapati s->vout_peak[pmdev->page] = pmbus_receive16(pmdev); 37062365482SMaheswara Kurapati } 37162365482SMaheswara Kurapati break; 37262365482SMaheswara Kurapati 37362365482SMaheswara Kurapati case MAX31785_MFR_TEMPERATURE_PEAK: /* R/W word */ 37462365482SMaheswara Kurapati if ((pmdev->page >= 6) && (pmdev->page <= 16)) { 37562365482SMaheswara Kurapati s->temperature_peak[pmdev->page] = pmbus_receive16(pmdev); 37662365482SMaheswara Kurapati } 37762365482SMaheswara Kurapati break; 37862365482SMaheswara Kurapati 37962365482SMaheswara Kurapati case MAX31785_MFR_VOUT_MIN: /* R/W word */ 38062365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && 38162365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { 38262365482SMaheswara Kurapati s->vout_min[pmdev->page] = pmbus_receive16(pmdev); 38362365482SMaheswara Kurapati } 38462365482SMaheswara Kurapati break; 38562365482SMaheswara Kurapati 38662365482SMaheswara Kurapati case MAX31785_MFR_FAULT_RESPONSE: /* R/W 8 */ 38762365482SMaheswara Kurapati s->fault_response[pmdev->page] = pmbus_receive8(pmdev); 38862365482SMaheswara Kurapati break; 38962365482SMaheswara Kurapati 39062365482SMaheswara Kurapati case MAX31785_MFR_TIME_COUNT: /* R/W 32 */ 39162365482SMaheswara Kurapati s->time_count[pmdev->page] = pmbus_receive32(pmdev); 39262365482SMaheswara Kurapati break; 39362365482SMaheswara Kurapati 39462365482SMaheswara Kurapati case MAX31785_MFR_TEMP_SENSOR_CONFIG: /* R/W 16 */ 39562365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) && 39662365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_TEMP_PAGE)) { 39762365482SMaheswara Kurapati s->temp_sensor_config[pmdev->page] = pmbus_receive16(pmdev); 39862365482SMaheswara Kurapati } 39962365482SMaheswara Kurapati break; 40062365482SMaheswara Kurapati 40162365482SMaheswara Kurapati case MAX31785_MFR_FAN_CONFIG: /* R/W 16 */ 40262365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 40362365482SMaheswara Kurapati s->fan_config[pmdev->page] = pmbus_receive16(pmdev); 40462365482SMaheswara Kurapati } 40562365482SMaheswara Kurapati break; 40662365482SMaheswara Kurapati 40762365482SMaheswara Kurapati case MAX31785_MFR_FAN_FAULT_LIMIT: /* R/W 16 */ 40862365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 40962365482SMaheswara Kurapati s->fan_fault_limit[pmdev->page] = pmbus_receive16(pmdev); 41062365482SMaheswara Kurapati } 41162365482SMaheswara Kurapati break; 41262365482SMaheswara Kurapati 41362365482SMaheswara Kurapati case MAX31785_MFR_FAN_WARN_LIMIT: /* R/W 16 */ 41462365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 41562365482SMaheswara Kurapati s->fan_warn_limit[pmdev->page] = pmbus_receive16(pmdev); 41662365482SMaheswara Kurapati } 41762365482SMaheswara Kurapati break; 41862365482SMaheswara Kurapati 41962365482SMaheswara Kurapati case MAX31785_MFR_FAN_RUN_TIME: /* R/W 16 */ 42062365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 42162365482SMaheswara Kurapati s->fan_run_time[pmdev->page] = pmbus_receive16(pmdev); 42262365482SMaheswara Kurapati } 42362365482SMaheswara Kurapati break; 42462365482SMaheswara Kurapati 42562365482SMaheswara Kurapati case MAX31785_MFR_FAN_PWM_AVG: /* R/W 16 */ 42662365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 42762365482SMaheswara Kurapati s->fan_pwm_avg[pmdev->page] = pmbus_receive16(pmdev); 42862365482SMaheswara Kurapati } 42962365482SMaheswara Kurapati break; 43062365482SMaheswara Kurapati 43162365482SMaheswara Kurapati case MAX31785_MFR_FAN_PWM2RPM: /* R/W 64 */ 43262365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 43362365482SMaheswara Kurapati s->fan_pwm2rpm[pmdev->page] = pmbus_receive64(pmdev); 43462365482SMaheswara Kurapati } 43562365482SMaheswara Kurapati break; 43662365482SMaheswara Kurapati 43762365482SMaheswara Kurapati default: 43862365482SMaheswara Kurapati qemu_log_mask(LOG_GUEST_ERROR, 43962365482SMaheswara Kurapati "%s: writing to unsupported register: 0x%02x\n", 44062365482SMaheswara Kurapati __func__, pmdev->code); 44162365482SMaheswara Kurapati break; 44262365482SMaheswara Kurapati } 44362365482SMaheswara Kurapati 44462365482SMaheswara Kurapati return 0; 44562365482SMaheswara Kurapati } 44662365482SMaheswara Kurapati 447ad80e367SPeter Maydell static void max31785_exit_reset(Object *obj, ResetType type) 44862365482SMaheswara Kurapati { 44962365482SMaheswara Kurapati PMBusDevice *pmdev = PMBUS_DEVICE(obj); 45062365482SMaheswara Kurapati MAX31785State *s = MAX31785(obj); 45162365482SMaheswara Kurapati 45262365482SMaheswara Kurapati pmdev->capability = MAX31785_DEFAULT_CAPABILITY; 45362365482SMaheswara Kurapati 45462365482SMaheswara Kurapati for (int i = MAX31785_MIN_FAN_PAGE; i <= MAX31785_MAX_FAN_PAGE; i++) { 45562365482SMaheswara Kurapati pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE; 45662365482SMaheswara Kurapati pmdev->pages[i].fan_command_1 = MAX31785_DEFAULT_FAN_COMMAND_1; 45762365482SMaheswara Kurapati pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION; 45862365482SMaheswara Kurapati pmdev->pages[i].fan_config_1_2 = MAX31785_DEFAULT_FAN_CONFIG_1_2(0); 45962365482SMaheswara Kurapati pmdev->pages[i].read_fan_speed_1 = MAX31785_DEFAULT_FAN_SPEED; 46062365482SMaheswara Kurapati pmdev->pages[i].status_fans_1_2 = MAX31785_DEFAULT_FAN_STATUS; 46162365482SMaheswara Kurapati } 46262365482SMaheswara Kurapati 46362365482SMaheswara Kurapati for (int i = MAX31785_MIN_TEMP_PAGE; i <= MAX31785_MAX_TEMP_PAGE; i++) { 46462365482SMaheswara Kurapati pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE; 46562365482SMaheswara Kurapati pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION; 46662365482SMaheswara Kurapati pmdev->pages[i].ot_fault_limit = MAX31785_DEFAULT_OT_FAULT_LIMIT; 46762365482SMaheswara Kurapati pmdev->pages[i].ot_warn_limit = MAX31785_DEFAULT_OT_WARN_LIMIT; 46862365482SMaheswara Kurapati } 46962365482SMaheswara Kurapati 47062365482SMaheswara Kurapati for (int i = MAX31785_MIN_ADC_VOLTAGE_PAGE; 47162365482SMaheswara Kurapati i <= MAX31785_MAX_ADC_VOLTAGE_PAGE; 47262365482SMaheswara Kurapati i++) { 47362365482SMaheswara Kurapati pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE; 47462365482SMaheswara Kurapati pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION; 47562365482SMaheswara Kurapati pmdev->pages[i].vout_scale_monitor = 47662365482SMaheswara Kurapati MAX31785_DEFAULT_VOUT_SCALE_MONITOR; 47762365482SMaheswara Kurapati pmdev->pages[i].vout_ov_fault_limit = MAX31785_DEFAULT_OV_FAULT_LIMIT; 47862365482SMaheswara Kurapati pmdev->pages[i].vout_ov_warn_limit = MAX31785_DEFAULT_OV_WARN_LIMIT; 47962365482SMaheswara Kurapati } 48062365482SMaheswara Kurapati 48162365482SMaheswara Kurapati s->mfr_location = MAX31785_DEFAULT_TEXT; 48262365482SMaheswara Kurapati s->mfr_date = MAX31785_DEFAULT_TEXT; 48362365482SMaheswara Kurapati s->mfr_serial = MAX31785_DEFAULT_TEXT; 48462365482SMaheswara Kurapati } 48562365482SMaheswara Kurapati 48662365482SMaheswara Kurapati static const VMStateDescription vmstate_max31785 = { 48762365482SMaheswara Kurapati .name = TYPE_MAX31785, 48862365482SMaheswara Kurapati .version_id = 0, 48962365482SMaheswara Kurapati .minimum_version_id = 0, 490af10fff2SRichard Henderson .fields = (const VMStateField[]){ 49162365482SMaheswara Kurapati VMSTATE_PMBUS_DEVICE(parent, MAX31785State), 49262365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(mfr_mode, MAX31785State, 49362365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 49462365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(vout_peak, MAX31785State, 49562365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 49662365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(temperature_peak, MAX31785State, 49762365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 49862365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(vout_min, MAX31785State, 49962365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 50062365482SMaheswara Kurapati VMSTATE_UINT8_ARRAY(fault_response, MAX31785State, 50162365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 50262365482SMaheswara Kurapati VMSTATE_UINT32_ARRAY(time_count, MAX31785State, 50362365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 50462365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(temp_sensor_config, MAX31785State, 50562365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 50662365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(fan_config, MAX31785State, 50762365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 50862365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(read_fan_pwm, MAX31785State, 50962365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 51062365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(fan_fault_limit, MAX31785State, 51162365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 51262365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(fan_warn_limit, MAX31785State, 51362365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 51462365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(fan_run_time, MAX31785State, 51562365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 51662365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(fan_pwm_avg, MAX31785State, 51762365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 51862365482SMaheswara Kurapati VMSTATE_UINT64_ARRAY(fan_pwm2rpm, MAX31785State, 51962365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 52062365482SMaheswara Kurapati VMSTATE_UINT64(mfr_location, MAX31785State), 52162365482SMaheswara Kurapati VMSTATE_UINT64(mfr_date, MAX31785State), 52262365482SMaheswara Kurapati VMSTATE_UINT64(mfr_serial, MAX31785State), 52362365482SMaheswara Kurapati VMSTATE_END_OF_LIST() 52462365482SMaheswara Kurapati } 52562365482SMaheswara Kurapati }; 52662365482SMaheswara Kurapati 52762365482SMaheswara Kurapati static void max31785_init(Object *obj) 52862365482SMaheswara Kurapati { 52962365482SMaheswara Kurapati PMBusDevice *pmdev = PMBUS_DEVICE(obj); 53062365482SMaheswara Kurapati 53162365482SMaheswara Kurapati for (int i = MAX31785_MIN_FAN_PAGE; i <= MAX31785_MAX_FAN_PAGE; i++) { 53262365482SMaheswara Kurapati pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE); 53362365482SMaheswara Kurapati } 53462365482SMaheswara Kurapati 53562365482SMaheswara Kurapati for (int i = MAX31785_MIN_TEMP_PAGE; i <= MAX31785_MAX_TEMP_PAGE; i++) { 53662365482SMaheswara Kurapati pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE | PB_HAS_TEMPERATURE); 53762365482SMaheswara Kurapati } 53862365482SMaheswara Kurapati 53962365482SMaheswara Kurapati for (int i = MAX31785_MIN_ADC_VOLTAGE_PAGE; 54062365482SMaheswara Kurapati i <= MAX31785_MAX_ADC_VOLTAGE_PAGE; 54162365482SMaheswara Kurapati i++) { 54262365482SMaheswara Kurapati pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE | PB_HAS_VOUT | 54362365482SMaheswara Kurapati PB_HAS_VOUT_RATING); 54462365482SMaheswara Kurapati } 54562365482SMaheswara Kurapati } 54662365482SMaheswara Kurapati 547*12d1a768SPhilippe Mathieu-Daudé static void max31785_class_init(ObjectClass *klass, const void *data) 54862365482SMaheswara Kurapati { 54962365482SMaheswara Kurapati ResettableClass *rc = RESETTABLE_CLASS(klass); 55062365482SMaheswara Kurapati DeviceClass *dc = DEVICE_CLASS(klass); 55162365482SMaheswara Kurapati PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass); 55262365482SMaheswara Kurapati dc->desc = "Maxim MAX31785 6-Channel Fan Controller"; 55362365482SMaheswara Kurapati dc->vmsd = &vmstate_max31785; 55462365482SMaheswara Kurapati k->write_data = max31785_write_data; 55562365482SMaheswara Kurapati k->receive_byte = max31785_read_byte; 55662365482SMaheswara Kurapati k->device_num_pages = MAX31785_TOTAL_NUM_PAGES; 55762365482SMaheswara Kurapati rc->phases.exit = max31785_exit_reset; 55862365482SMaheswara Kurapati } 55962365482SMaheswara Kurapati 56062365482SMaheswara Kurapati static const TypeInfo max31785_info = { 56162365482SMaheswara Kurapati .name = TYPE_MAX31785, 56262365482SMaheswara Kurapati .parent = TYPE_PMBUS_DEVICE, 56362365482SMaheswara Kurapati .instance_size = sizeof(MAX31785State), 56462365482SMaheswara Kurapati .instance_init = max31785_init, 56562365482SMaheswara Kurapati .class_init = max31785_class_init, 56662365482SMaheswara Kurapati }; 56762365482SMaheswara Kurapati 56862365482SMaheswara Kurapati static void max31785_register_types(void) 56962365482SMaheswara Kurapati { 57062365482SMaheswara Kurapati type_register_static(&max31785_info); 57162365482SMaheswara Kurapati } 57262365482SMaheswara Kurapati 57362365482SMaheswara Kurapati type_init(max31785_register_types) 574