1*62365482SMaheswara Kurapati // SPDX-License-Identifier: GPL-2.0-or-later 2*62365482SMaheswara Kurapati /* 3*62365482SMaheswara Kurapati * Maxim MAX31785 PMBus 6-Channel Fan Controller 4*62365482SMaheswara Kurapati * 5*62365482SMaheswara Kurapati * Datasheet: 6*62365482SMaheswara Kurapati * https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf 7*62365482SMaheswara Kurapati * 8*62365482SMaheswara Kurapati * Copyright(c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 9*62365482SMaheswara Kurapati */ 10*62365482SMaheswara Kurapati 11*62365482SMaheswara Kurapati #include "qemu/osdep.h" 12*62365482SMaheswara Kurapati #include "hw/i2c/pmbus_device.h" 13*62365482SMaheswara Kurapati #include "hw/irq.h" 14*62365482SMaheswara Kurapati #include "migration/vmstate.h" 15*62365482SMaheswara Kurapati #include "qapi/error.h" 16*62365482SMaheswara Kurapati #include "qapi/visitor.h" 17*62365482SMaheswara Kurapati #include "qemu/log.h" 18*62365482SMaheswara Kurapati #include "qemu/module.h" 19*62365482SMaheswara Kurapati 20*62365482SMaheswara Kurapati #define TYPE_MAX31785 "max31785" 21*62365482SMaheswara Kurapati #define MAX31785(obj) OBJECT_CHECK(MAX31785State, (obj), TYPE_MAX31785) 22*62365482SMaheswara Kurapati 23*62365482SMaheswara Kurapati /* MAX31785 mfr specific PMBus commands */ 24*62365482SMaheswara Kurapati #define MAX31785_MFR_MODE 0xD1 25*62365482SMaheswara Kurapati #define MAX31785_MFR_PSEN_CONFIG 0xD2 26*62365482SMaheswara Kurapati #define MAX31785_MFR_VOUT_PEAK 0xD4 27*62365482SMaheswara Kurapati #define MAX31785_MFR_TEMPERATURE_PEAK 0xD6 28*62365482SMaheswara Kurapati #define MAX31785_MFR_VOUT_MIN 0xD7 29*62365482SMaheswara Kurapati #define MAX31785_MFR_FAULT_RESPONSE 0xD9 30*62365482SMaheswara Kurapati #define MAX31785_MFR_NV_FAULT_LOG 0xDC 31*62365482SMaheswara Kurapati #define MAX31785_MFR_TIME_COUNT 0xDD 32*62365482SMaheswara Kurapati #define MAX31785_MFR_TEMP_SENSOR_CONFIG 0xF0 33*62365482SMaheswara Kurapati #define MAX31785_MFR_FAN_CONFIG 0xF1 34*62365482SMaheswara Kurapati #define MAX31785_MFR_FAN_LUT 0xF2 35*62365482SMaheswara Kurapati #define MAX31785_MFR_READ_FAN_PWM 0xF3 36*62365482SMaheswara Kurapati #define MAX31785_MFR_FAN_FAULT_LIMIT 0xF5 37*62365482SMaheswara Kurapati #define MAX31785_MFR_FAN_WARN_LIMIT 0xF6 38*62365482SMaheswara Kurapati #define MAX31785_MFR_FAN_RUN_TIME 0xF7 39*62365482SMaheswara Kurapati #define MAX31785_MFR_FAN_PWM_AVG 0xF8 40*62365482SMaheswara Kurapati #define MAX31785_MFR_FAN_PWM2RPM 0xF9 41*62365482SMaheswara Kurapati 42*62365482SMaheswara Kurapati /* defaults as per the data sheet */ 43*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_CAPABILITY 0x10 44*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_VOUT_MODE 0x40 45*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_VOUT_SCALE_MONITOR 0x7FFF 46*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_FAN_COMMAND_1 0x7FFF 47*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_OV_FAULT_LIMIT 0x7FFF 48*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_OV_WARN_LIMIT 0x7FFF 49*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_OT_FAULT_LIMIT 0x7FFF 50*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_OT_WARN_LIMIT 0x7FFF 51*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_PMBUS_REVISION 0x11 52*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_MFR_ID 0x4D 53*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_MFR_MODEL 0x53 54*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_MFR_REVISION 0x3030 55*62365482SMaheswara Kurapati #define MAX31785A_DEFAULT_MFR_REVISION 0x3040 56*62365482SMaheswara Kurapati #define MAX31785B_DEFAULT_MFR_REVISION 0x3061 57*62365482SMaheswara Kurapati #define MAX31785B_DEFAULT_MFR_TEMPERATURE_PEAK 0x8000 58*62365482SMaheswara Kurapati #define MAX31785B_DEFAULT_MFR_VOUT_MIN 0x7FFF 59*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_TEXT 0x3130313031303130 60*62365482SMaheswara Kurapati 61*62365482SMaheswara Kurapati /* MAX31785 pages */ 62*62365482SMaheswara Kurapati #define MAX31785_TOTAL_NUM_PAGES 23 63*62365482SMaheswara Kurapati #define MAX31785_FAN_PAGES 6 64*62365482SMaheswara Kurapati #define MAX31785_MIN_FAN_PAGE 0 65*62365482SMaheswara Kurapati #define MAX31785_MAX_FAN_PAGE 5 66*62365482SMaheswara Kurapati #define MAX31785_MIN_TEMP_PAGE 6 67*62365482SMaheswara Kurapati #define MAX31785_MAX_TEMP_PAGE 16 68*62365482SMaheswara Kurapati #define MAX31785_MIN_ADC_VOLTAGE_PAGE 17 69*62365482SMaheswara Kurapati #define MAX31785_MAX_ADC_VOLTAGE_PAGE 22 70*62365482SMaheswara Kurapati 71*62365482SMaheswara Kurapati /* FAN_CONFIG_1_2 */ 72*62365482SMaheswara Kurapati #define MAX31785_MFR_FAN_CONFIG 0xF1 73*62365482SMaheswara Kurapati #define MAX31785_FAN_CONFIG_ENABLE BIT(7) 74*62365482SMaheswara Kurapati #define MAX31785_FAN_CONFIG_RPM_PWM BIT(6) 75*62365482SMaheswara Kurapati #define MAX31785_FAN_CONFIG_PULSE(pulse) (pulse << 4) 76*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_FAN_CONFIG_1_2(pulse) \ 77*62365482SMaheswara Kurapati (MAX31785_FAN_CONFIG_ENABLE | MAX31785_FAN_CONFIG_PULSE(pulse)) 78*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_MFR_FAN_CONFIG 0x0000 79*62365482SMaheswara Kurapati 80*62365482SMaheswara Kurapati /* fan speed in RPM */ 81*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_FAN_SPEED 0x7fff 82*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_FAN_STATUS 0x00 83*62365482SMaheswara Kurapati 84*62365482SMaheswara Kurapati #define MAX31785_DEFAULT_FAN_MAX_PWM 0x2710 85*62365482SMaheswara Kurapati 86*62365482SMaheswara Kurapati /* 87*62365482SMaheswara Kurapati * MAX31785State: 88*62365482SMaheswara Kurapati * @code: The command code received 89*62365482SMaheswara Kurapati * @page: Each page corresponds to a device monitored by the Max 31785 90*62365482SMaheswara Kurapati * The page register determines the available commands depending on device 91*62365482SMaheswara Kurapati * _____________________________________________________________________________ 92*62365482SMaheswara Kurapati * | 0 | Fan Connected to PWM0 | 93*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 94*62365482SMaheswara Kurapati * | 1 | Fan Connected to PWM1 | 95*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 96*62365482SMaheswara Kurapati * | 2 | Fan Connected to PWM2 | 97*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 98*62365482SMaheswara Kurapati * | 3 | Fan Connected to PWM3 | 99*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 100*62365482SMaheswara Kurapati * | 4 | Fan Connected to PWM4 | 101*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 102*62365482SMaheswara Kurapati * | 5 | Fan Connected to PWM5 | 103*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 104*62365482SMaheswara Kurapati * | 6 | Remote Thermal Diode Connected to ADC 0 | 105*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 106*62365482SMaheswara Kurapati * | 7 | Remote Thermal Diode Connected to ADC 1 | 107*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 108*62365482SMaheswara Kurapati * | 8 | Remote Thermal Diode Connected to ADC 2 | 109*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 110*62365482SMaheswara Kurapati * | 9 | Remote Thermal Diode Connected to ADC 3 | 111*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 112*62365482SMaheswara Kurapati * | 10 | Remote Thermal Diode Connected to ADC 4 | 113*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 114*62365482SMaheswara Kurapati * | 11 | Remote Thermal Diode Connected to ADC 5 | 115*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 116*62365482SMaheswara Kurapati * | 12 | Internal Temperature Sensor | 117*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 118*62365482SMaheswara Kurapati * | 13 | Remote I2C Temperature Sensor with Address 0 | 119*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 120*62365482SMaheswara Kurapati * | 14 | Remote I2C Temperature Sensor with Address 1 | 121*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 122*62365482SMaheswara Kurapati * | 15 | Remote I2C Temperature Sensor with Address 2 | 123*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 124*62365482SMaheswara Kurapati * | 16 | Remote I2C Temperature Sensor with Address 3 | 125*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 126*62365482SMaheswara Kurapati * | 17 | Remote I2C Temperature Sensor with Address 4 | 127*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 128*62365482SMaheswara Kurapati * | 17 | Remote Voltage Connected to ADC0 | 129*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 130*62365482SMaheswara Kurapati * | 18 | Remote Voltage Connected to ADC1 | 131*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 132*62365482SMaheswara Kurapati * | 19 | Remote Voltage Connected to ADC2 | 133*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 134*62365482SMaheswara Kurapati * | 20 | Remote Voltage Connected to ADC3 | 135*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 136*62365482SMaheswara Kurapati * | 21 | Remote Voltage Connected to ADC4 | 137*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 138*62365482SMaheswara Kurapati * | 22 | Remote Voltage Connected to ADC5 | 139*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 140*62365482SMaheswara Kurapati * |23-254 | Reserved | 141*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 142*62365482SMaheswara Kurapati * | 255 | Applies to all pages | 143*62365482SMaheswara Kurapati * |_______|___________________________________________________________________| 144*62365482SMaheswara Kurapati */ 145*62365482SMaheswara Kurapati 146*62365482SMaheswara Kurapati /* Place holder to save the max31785 mfr specific registers */ 147*62365482SMaheswara Kurapati typedef struct MAX31785State { 148*62365482SMaheswara Kurapati PMBusDevice parent; 149*62365482SMaheswara Kurapati uint16_t mfr_mode[MAX31785_TOTAL_NUM_PAGES]; 150*62365482SMaheswara Kurapati uint16_t vout_peak[MAX31785_TOTAL_NUM_PAGES]; 151*62365482SMaheswara Kurapati uint16_t temperature_peak[MAX31785_TOTAL_NUM_PAGES]; 152*62365482SMaheswara Kurapati uint16_t vout_min[MAX31785_TOTAL_NUM_PAGES]; 153*62365482SMaheswara Kurapati uint8_t fault_response[MAX31785_TOTAL_NUM_PAGES]; 154*62365482SMaheswara Kurapati uint32_t time_count[MAX31785_TOTAL_NUM_PAGES]; 155*62365482SMaheswara Kurapati uint16_t temp_sensor_config[MAX31785_TOTAL_NUM_PAGES]; 156*62365482SMaheswara Kurapati uint16_t fan_config[MAX31785_TOTAL_NUM_PAGES]; 157*62365482SMaheswara Kurapati uint16_t read_fan_pwm[MAX31785_TOTAL_NUM_PAGES]; 158*62365482SMaheswara Kurapati uint16_t fan_fault_limit[MAX31785_TOTAL_NUM_PAGES]; 159*62365482SMaheswara Kurapati uint16_t fan_warn_limit[MAX31785_TOTAL_NUM_PAGES]; 160*62365482SMaheswara Kurapati uint16_t fan_run_time[MAX31785_TOTAL_NUM_PAGES]; 161*62365482SMaheswara Kurapati uint16_t fan_pwm_avg[MAX31785_TOTAL_NUM_PAGES]; 162*62365482SMaheswara Kurapati uint64_t fan_pwm2rpm[MAX31785_TOTAL_NUM_PAGES]; 163*62365482SMaheswara Kurapati uint64_t mfr_location; 164*62365482SMaheswara Kurapati uint64_t mfr_date; 165*62365482SMaheswara Kurapati uint64_t mfr_serial; 166*62365482SMaheswara Kurapati uint16_t mfr_revision; 167*62365482SMaheswara Kurapati } MAX31785State; 168*62365482SMaheswara Kurapati 169*62365482SMaheswara Kurapati static uint8_t max31785_read_byte(PMBusDevice *pmdev) 170*62365482SMaheswara Kurapati { 171*62365482SMaheswara Kurapati MAX31785State *s = MAX31785(pmdev); 172*62365482SMaheswara Kurapati switch (pmdev->code) { 173*62365482SMaheswara Kurapati 174*62365482SMaheswara Kurapati case PMBUS_FAN_CONFIG_1_2: 175*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 176*62365482SMaheswara Kurapati pmbus_send8(pmdev, pmdev->pages[pmdev->page].fan_config_1_2); 177*62365482SMaheswara Kurapati } 178*62365482SMaheswara Kurapati break; 179*62365482SMaheswara Kurapati 180*62365482SMaheswara Kurapati case PMBUS_FAN_COMMAND_1: 181*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 182*62365482SMaheswara Kurapati pmbus_send16(pmdev, pmdev->pages[pmdev->page].fan_command_1); 183*62365482SMaheswara Kurapati } 184*62365482SMaheswara Kurapati break; 185*62365482SMaheswara Kurapati 186*62365482SMaheswara Kurapati case PMBUS_READ_FAN_SPEED_1: 187*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 188*62365482SMaheswara Kurapati pmbus_send16(pmdev, pmdev->pages[pmdev->page].read_fan_speed_1); 189*62365482SMaheswara Kurapati } 190*62365482SMaheswara Kurapati break; 191*62365482SMaheswara Kurapati 192*62365482SMaheswara Kurapati case PMBUS_STATUS_FANS_1_2: 193*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 194*62365482SMaheswara Kurapati pmbus_send16(pmdev, pmdev->pages[pmdev->page].status_fans_1_2); 195*62365482SMaheswara Kurapati } 196*62365482SMaheswara Kurapati break; 197*62365482SMaheswara Kurapati 198*62365482SMaheswara Kurapati case PMBUS_MFR_REVISION: 199*62365482SMaheswara Kurapati pmbus_send16(pmdev, MAX31785_DEFAULT_MFR_REVISION); 200*62365482SMaheswara Kurapati break; 201*62365482SMaheswara Kurapati 202*62365482SMaheswara Kurapati case PMBUS_MFR_ID: 203*62365482SMaheswara Kurapati pmbus_send8(pmdev, 0x4d); /* Maxim */ 204*62365482SMaheswara Kurapati break; 205*62365482SMaheswara Kurapati 206*62365482SMaheswara Kurapati case PMBUS_MFR_MODEL: 207*62365482SMaheswara Kurapati pmbus_send8(pmdev, 0x53); 208*62365482SMaheswara Kurapati break; 209*62365482SMaheswara Kurapati 210*62365482SMaheswara Kurapati case PMBUS_MFR_LOCATION: 211*62365482SMaheswara Kurapati pmbus_send64(pmdev, s->mfr_location); 212*62365482SMaheswara Kurapati break; 213*62365482SMaheswara Kurapati 214*62365482SMaheswara Kurapati case PMBUS_MFR_DATE: 215*62365482SMaheswara Kurapati pmbus_send64(pmdev, s->mfr_date); 216*62365482SMaheswara Kurapati break; 217*62365482SMaheswara Kurapati 218*62365482SMaheswara Kurapati case PMBUS_MFR_SERIAL: 219*62365482SMaheswara Kurapati pmbus_send64(pmdev, s->mfr_serial); 220*62365482SMaheswara Kurapati break; 221*62365482SMaheswara Kurapati 222*62365482SMaheswara Kurapati case MAX31785_MFR_MODE: 223*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->mfr_mode[pmdev->page]); 224*62365482SMaheswara Kurapati break; 225*62365482SMaheswara Kurapati 226*62365482SMaheswara Kurapati case MAX31785_MFR_VOUT_PEAK: 227*62365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && 228*62365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { 229*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->vout_peak[pmdev->page]); 230*62365482SMaheswara Kurapati } 231*62365482SMaheswara Kurapati break; 232*62365482SMaheswara Kurapati 233*62365482SMaheswara Kurapati case MAX31785_MFR_TEMPERATURE_PEAK: 234*62365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) && 235*62365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_TEMP_PAGE)) { 236*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->temperature_peak[pmdev->page]); 237*62365482SMaheswara Kurapati } 238*62365482SMaheswara Kurapati break; 239*62365482SMaheswara Kurapati 240*62365482SMaheswara Kurapati case MAX31785_MFR_VOUT_MIN: 241*62365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && 242*62365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { 243*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->vout_min[pmdev->page]); 244*62365482SMaheswara Kurapati } 245*62365482SMaheswara Kurapati break; 246*62365482SMaheswara Kurapati 247*62365482SMaheswara Kurapati case MAX31785_MFR_FAULT_RESPONSE: 248*62365482SMaheswara Kurapati pmbus_send8(pmdev, s->fault_response[pmdev->page]); 249*62365482SMaheswara Kurapati break; 250*62365482SMaheswara Kurapati 251*62365482SMaheswara Kurapati case MAX31785_MFR_TIME_COUNT: /* R/W 32 */ 252*62365482SMaheswara Kurapati pmbus_send32(pmdev, s->time_count[pmdev->page]); 253*62365482SMaheswara Kurapati break; 254*62365482SMaheswara Kurapati 255*62365482SMaheswara Kurapati case MAX31785_MFR_TEMP_SENSOR_CONFIG: /* R/W 16 */ 256*62365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) && 257*62365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_TEMP_PAGE)) { 258*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->temp_sensor_config[pmdev->page]); 259*62365482SMaheswara Kurapati } 260*62365482SMaheswara Kurapati break; 261*62365482SMaheswara Kurapati 262*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_CONFIG: /* R/W 16 */ 263*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 264*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->fan_config[pmdev->page]); 265*62365482SMaheswara Kurapati } 266*62365482SMaheswara Kurapati break; 267*62365482SMaheswara Kurapati 268*62365482SMaheswara Kurapati case MAX31785_MFR_READ_FAN_PWM: /* R/W 16 */ 269*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 270*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->read_fan_pwm[pmdev->page]); 271*62365482SMaheswara Kurapati } 272*62365482SMaheswara Kurapati break; 273*62365482SMaheswara Kurapati 274*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_FAULT_LIMIT: /* R/W 16 */ 275*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 276*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->fan_fault_limit[pmdev->page]); 277*62365482SMaheswara Kurapati } 278*62365482SMaheswara Kurapati break; 279*62365482SMaheswara Kurapati 280*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_WARN_LIMIT: /* R/W 16 */ 281*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 282*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->fan_warn_limit[pmdev->page]); 283*62365482SMaheswara Kurapati } 284*62365482SMaheswara Kurapati break; 285*62365482SMaheswara Kurapati 286*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_RUN_TIME: /* R/W 16 */ 287*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 288*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->fan_run_time[pmdev->page]); 289*62365482SMaheswara Kurapati } 290*62365482SMaheswara Kurapati break; 291*62365482SMaheswara Kurapati 292*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_PWM_AVG: /* R/W 16 */ 293*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 294*62365482SMaheswara Kurapati pmbus_send16(pmdev, s->fan_pwm_avg[pmdev->page]); 295*62365482SMaheswara Kurapati } 296*62365482SMaheswara Kurapati break; 297*62365482SMaheswara Kurapati 298*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_PWM2RPM: /* R/W 64 */ 299*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 300*62365482SMaheswara Kurapati pmbus_send64(pmdev, s->fan_pwm2rpm[pmdev->page]); 301*62365482SMaheswara Kurapati } 302*62365482SMaheswara Kurapati break; 303*62365482SMaheswara Kurapati 304*62365482SMaheswara Kurapati default: 305*62365482SMaheswara Kurapati qemu_log_mask(LOG_GUEST_ERROR, 306*62365482SMaheswara Kurapati "%s: reading from unsupported register: 0x%02x\n", 307*62365482SMaheswara Kurapati __func__, pmdev->code); 308*62365482SMaheswara Kurapati break; 309*62365482SMaheswara Kurapati } 310*62365482SMaheswara Kurapati 311*62365482SMaheswara Kurapati return 0xFF; 312*62365482SMaheswara Kurapati } 313*62365482SMaheswara Kurapati 314*62365482SMaheswara Kurapati static int max31785_write_data(PMBusDevice *pmdev, const uint8_t *buf, 315*62365482SMaheswara Kurapati uint8_t len) 316*62365482SMaheswara Kurapati { 317*62365482SMaheswara Kurapati MAX31785State *s = MAX31785(pmdev); 318*62365482SMaheswara Kurapati if (len == 0) { 319*62365482SMaheswara Kurapati qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__); 320*62365482SMaheswara Kurapati return -1; 321*62365482SMaheswara Kurapati } 322*62365482SMaheswara Kurapati 323*62365482SMaheswara Kurapati pmdev->code = buf[0]; /* PMBus command code */ 324*62365482SMaheswara Kurapati 325*62365482SMaheswara Kurapati if (len == 1) { 326*62365482SMaheswara Kurapati return 0; 327*62365482SMaheswara Kurapati } 328*62365482SMaheswara Kurapati 329*62365482SMaheswara Kurapati /* Exclude command code from buffer */ 330*62365482SMaheswara Kurapati buf++; 331*62365482SMaheswara Kurapati len--; 332*62365482SMaheswara Kurapati 333*62365482SMaheswara Kurapati switch (pmdev->code) { 334*62365482SMaheswara Kurapati 335*62365482SMaheswara Kurapati case PMBUS_FAN_CONFIG_1_2: 336*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 337*62365482SMaheswara Kurapati pmdev->pages[pmdev->page].fan_config_1_2 = pmbus_receive8(pmdev); 338*62365482SMaheswara Kurapati } 339*62365482SMaheswara Kurapati break; 340*62365482SMaheswara Kurapati 341*62365482SMaheswara Kurapati case PMBUS_FAN_COMMAND_1: 342*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 343*62365482SMaheswara Kurapati pmdev->pages[pmdev->page].fan_command_1 = pmbus_receive16(pmdev); 344*62365482SMaheswara Kurapati pmdev->pages[pmdev->page].read_fan_speed_1 = 345*62365482SMaheswara Kurapati ((MAX31785_DEFAULT_FAN_SPEED / MAX31785_DEFAULT_FAN_MAX_PWM) * 346*62365482SMaheswara Kurapati pmdev->pages[pmdev->page].fan_command_1); 347*62365482SMaheswara Kurapati } 348*62365482SMaheswara Kurapati break; 349*62365482SMaheswara Kurapati 350*62365482SMaheswara Kurapati case PMBUS_MFR_LOCATION: /* R/W 64 */ 351*62365482SMaheswara Kurapati s->mfr_location = pmbus_receive64(pmdev); 352*62365482SMaheswara Kurapati break; 353*62365482SMaheswara Kurapati 354*62365482SMaheswara Kurapati case PMBUS_MFR_DATE: /* R/W 64 */ 355*62365482SMaheswara Kurapati s->mfr_date = pmbus_receive64(pmdev); 356*62365482SMaheswara Kurapati break; 357*62365482SMaheswara Kurapati 358*62365482SMaheswara Kurapati case PMBUS_MFR_SERIAL: /* R/W 64 */ 359*62365482SMaheswara Kurapati s->mfr_serial = pmbus_receive64(pmdev); 360*62365482SMaheswara Kurapati break; 361*62365482SMaheswara Kurapati 362*62365482SMaheswara Kurapati case MAX31785_MFR_MODE: /* R/W word */ 363*62365482SMaheswara Kurapati s->mfr_mode[pmdev->page] = pmbus_receive16(pmdev); 364*62365482SMaheswara Kurapati break; 365*62365482SMaheswara Kurapati 366*62365482SMaheswara Kurapati case MAX31785_MFR_VOUT_PEAK: /* R/W word */ 367*62365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && 368*62365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { 369*62365482SMaheswara Kurapati s->vout_peak[pmdev->page] = pmbus_receive16(pmdev); 370*62365482SMaheswara Kurapati } 371*62365482SMaheswara Kurapati break; 372*62365482SMaheswara Kurapati 373*62365482SMaheswara Kurapati case MAX31785_MFR_TEMPERATURE_PEAK: /* R/W word */ 374*62365482SMaheswara Kurapati if ((pmdev->page >= 6) && (pmdev->page <= 16)) { 375*62365482SMaheswara Kurapati s->temperature_peak[pmdev->page] = pmbus_receive16(pmdev); 376*62365482SMaheswara Kurapati } 377*62365482SMaheswara Kurapati break; 378*62365482SMaheswara Kurapati 379*62365482SMaheswara Kurapati case MAX31785_MFR_VOUT_MIN: /* R/W word */ 380*62365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_ADC_VOLTAGE_PAGE) && 381*62365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_ADC_VOLTAGE_PAGE)) { 382*62365482SMaheswara Kurapati s->vout_min[pmdev->page] = pmbus_receive16(pmdev); 383*62365482SMaheswara Kurapati } 384*62365482SMaheswara Kurapati break; 385*62365482SMaheswara Kurapati 386*62365482SMaheswara Kurapati case MAX31785_MFR_FAULT_RESPONSE: /* R/W 8 */ 387*62365482SMaheswara Kurapati s->fault_response[pmdev->page] = pmbus_receive8(pmdev); 388*62365482SMaheswara Kurapati break; 389*62365482SMaheswara Kurapati 390*62365482SMaheswara Kurapati case MAX31785_MFR_TIME_COUNT: /* R/W 32 */ 391*62365482SMaheswara Kurapati s->time_count[pmdev->page] = pmbus_receive32(pmdev); 392*62365482SMaheswara Kurapati break; 393*62365482SMaheswara Kurapati 394*62365482SMaheswara Kurapati case MAX31785_MFR_TEMP_SENSOR_CONFIG: /* R/W 16 */ 395*62365482SMaheswara Kurapati if ((pmdev->page >= MAX31785_MIN_TEMP_PAGE) && 396*62365482SMaheswara Kurapati (pmdev->page <= MAX31785_MAX_TEMP_PAGE)) { 397*62365482SMaheswara Kurapati s->temp_sensor_config[pmdev->page] = pmbus_receive16(pmdev); 398*62365482SMaheswara Kurapati } 399*62365482SMaheswara Kurapati break; 400*62365482SMaheswara Kurapati 401*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_CONFIG: /* R/W 16 */ 402*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 403*62365482SMaheswara Kurapati s->fan_config[pmdev->page] = pmbus_receive16(pmdev); 404*62365482SMaheswara Kurapati } 405*62365482SMaheswara Kurapati break; 406*62365482SMaheswara Kurapati 407*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_FAULT_LIMIT: /* R/W 16 */ 408*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 409*62365482SMaheswara Kurapati s->fan_fault_limit[pmdev->page] = pmbus_receive16(pmdev); 410*62365482SMaheswara Kurapati } 411*62365482SMaheswara Kurapati break; 412*62365482SMaheswara Kurapati 413*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_WARN_LIMIT: /* R/W 16 */ 414*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 415*62365482SMaheswara Kurapati s->fan_warn_limit[pmdev->page] = pmbus_receive16(pmdev); 416*62365482SMaheswara Kurapati } 417*62365482SMaheswara Kurapati break; 418*62365482SMaheswara Kurapati 419*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_RUN_TIME: /* R/W 16 */ 420*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 421*62365482SMaheswara Kurapati s->fan_run_time[pmdev->page] = pmbus_receive16(pmdev); 422*62365482SMaheswara Kurapati } 423*62365482SMaheswara Kurapati break; 424*62365482SMaheswara Kurapati 425*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_PWM_AVG: /* R/W 16 */ 426*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 427*62365482SMaheswara Kurapati s->fan_pwm_avg[pmdev->page] = pmbus_receive16(pmdev); 428*62365482SMaheswara Kurapati } 429*62365482SMaheswara Kurapati break; 430*62365482SMaheswara Kurapati 431*62365482SMaheswara Kurapati case MAX31785_MFR_FAN_PWM2RPM: /* R/W 64 */ 432*62365482SMaheswara Kurapati if (pmdev->page <= MAX31785_MAX_FAN_PAGE) { 433*62365482SMaheswara Kurapati s->fan_pwm2rpm[pmdev->page] = pmbus_receive64(pmdev); 434*62365482SMaheswara Kurapati } 435*62365482SMaheswara Kurapati break; 436*62365482SMaheswara Kurapati 437*62365482SMaheswara Kurapati default: 438*62365482SMaheswara Kurapati qemu_log_mask(LOG_GUEST_ERROR, 439*62365482SMaheswara Kurapati "%s: writing to unsupported register: 0x%02x\n", 440*62365482SMaheswara Kurapati __func__, pmdev->code); 441*62365482SMaheswara Kurapati break; 442*62365482SMaheswara Kurapati } 443*62365482SMaheswara Kurapati 444*62365482SMaheswara Kurapati return 0; 445*62365482SMaheswara Kurapati } 446*62365482SMaheswara Kurapati 447*62365482SMaheswara Kurapati static void max31785_exit_reset(Object *obj) 448*62365482SMaheswara Kurapati { 449*62365482SMaheswara Kurapati PMBusDevice *pmdev = PMBUS_DEVICE(obj); 450*62365482SMaheswara Kurapati MAX31785State *s = MAX31785(obj); 451*62365482SMaheswara Kurapati 452*62365482SMaheswara Kurapati pmdev->capability = MAX31785_DEFAULT_CAPABILITY; 453*62365482SMaheswara Kurapati 454*62365482SMaheswara Kurapati for (int i = MAX31785_MIN_FAN_PAGE; i <= MAX31785_MAX_FAN_PAGE; i++) { 455*62365482SMaheswara Kurapati pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE; 456*62365482SMaheswara Kurapati pmdev->pages[i].fan_command_1 = MAX31785_DEFAULT_FAN_COMMAND_1; 457*62365482SMaheswara Kurapati pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION; 458*62365482SMaheswara Kurapati pmdev->pages[i].fan_config_1_2 = MAX31785_DEFAULT_FAN_CONFIG_1_2(0); 459*62365482SMaheswara Kurapati pmdev->pages[i].read_fan_speed_1 = MAX31785_DEFAULT_FAN_SPEED; 460*62365482SMaheswara Kurapati pmdev->pages[i].status_fans_1_2 = MAX31785_DEFAULT_FAN_STATUS; 461*62365482SMaheswara Kurapati } 462*62365482SMaheswara Kurapati 463*62365482SMaheswara Kurapati for (int i = MAX31785_MIN_TEMP_PAGE; i <= MAX31785_MAX_TEMP_PAGE; i++) { 464*62365482SMaheswara Kurapati pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE; 465*62365482SMaheswara Kurapati pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION; 466*62365482SMaheswara Kurapati pmdev->pages[i].ot_fault_limit = MAX31785_DEFAULT_OT_FAULT_LIMIT; 467*62365482SMaheswara Kurapati pmdev->pages[i].ot_warn_limit = MAX31785_DEFAULT_OT_WARN_LIMIT; 468*62365482SMaheswara Kurapati } 469*62365482SMaheswara Kurapati 470*62365482SMaheswara Kurapati for (int i = MAX31785_MIN_ADC_VOLTAGE_PAGE; 471*62365482SMaheswara Kurapati i <= MAX31785_MAX_ADC_VOLTAGE_PAGE; 472*62365482SMaheswara Kurapati i++) { 473*62365482SMaheswara Kurapati pmdev->pages[i].vout_mode = MAX31785_DEFAULT_VOUT_MODE; 474*62365482SMaheswara Kurapati pmdev->pages[i].revision = MAX31785_DEFAULT_PMBUS_REVISION; 475*62365482SMaheswara Kurapati pmdev->pages[i].vout_scale_monitor = 476*62365482SMaheswara Kurapati MAX31785_DEFAULT_VOUT_SCALE_MONITOR; 477*62365482SMaheswara Kurapati pmdev->pages[i].vout_ov_fault_limit = MAX31785_DEFAULT_OV_FAULT_LIMIT; 478*62365482SMaheswara Kurapati pmdev->pages[i].vout_ov_warn_limit = MAX31785_DEFAULT_OV_WARN_LIMIT; 479*62365482SMaheswara Kurapati } 480*62365482SMaheswara Kurapati 481*62365482SMaheswara Kurapati s->mfr_location = MAX31785_DEFAULT_TEXT; 482*62365482SMaheswara Kurapati s->mfr_date = MAX31785_DEFAULT_TEXT; 483*62365482SMaheswara Kurapati s->mfr_serial = MAX31785_DEFAULT_TEXT; 484*62365482SMaheswara Kurapati } 485*62365482SMaheswara Kurapati 486*62365482SMaheswara Kurapati static const VMStateDescription vmstate_max31785 = { 487*62365482SMaheswara Kurapati .name = TYPE_MAX31785, 488*62365482SMaheswara Kurapati .version_id = 0, 489*62365482SMaheswara Kurapati .minimum_version_id = 0, 490*62365482SMaheswara Kurapati .fields = (VMStateField[]){ 491*62365482SMaheswara Kurapati VMSTATE_PMBUS_DEVICE(parent, MAX31785State), 492*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(mfr_mode, MAX31785State, 493*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 494*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(vout_peak, MAX31785State, 495*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 496*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(temperature_peak, MAX31785State, 497*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 498*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(vout_min, MAX31785State, 499*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 500*62365482SMaheswara Kurapati VMSTATE_UINT8_ARRAY(fault_response, MAX31785State, 501*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 502*62365482SMaheswara Kurapati VMSTATE_UINT32_ARRAY(time_count, MAX31785State, 503*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 504*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(temp_sensor_config, MAX31785State, 505*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 506*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(fan_config, MAX31785State, 507*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 508*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(read_fan_pwm, MAX31785State, 509*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 510*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(fan_fault_limit, MAX31785State, 511*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 512*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(fan_warn_limit, MAX31785State, 513*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 514*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(fan_run_time, MAX31785State, 515*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 516*62365482SMaheswara Kurapati VMSTATE_UINT16_ARRAY(fan_pwm_avg, MAX31785State, 517*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 518*62365482SMaheswara Kurapati VMSTATE_UINT64_ARRAY(fan_pwm2rpm, MAX31785State, 519*62365482SMaheswara Kurapati MAX31785_TOTAL_NUM_PAGES), 520*62365482SMaheswara Kurapati VMSTATE_UINT64(mfr_location, MAX31785State), 521*62365482SMaheswara Kurapati VMSTATE_UINT64(mfr_date, MAX31785State), 522*62365482SMaheswara Kurapati VMSTATE_UINT64(mfr_serial, MAX31785State), 523*62365482SMaheswara Kurapati VMSTATE_END_OF_LIST() 524*62365482SMaheswara Kurapati } 525*62365482SMaheswara Kurapati }; 526*62365482SMaheswara Kurapati 527*62365482SMaheswara Kurapati static void max31785_init(Object *obj) 528*62365482SMaheswara Kurapati { 529*62365482SMaheswara Kurapati PMBusDevice *pmdev = PMBUS_DEVICE(obj); 530*62365482SMaheswara Kurapati 531*62365482SMaheswara Kurapati for (int i = MAX31785_MIN_FAN_PAGE; i <= MAX31785_MAX_FAN_PAGE; i++) { 532*62365482SMaheswara Kurapati pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE); 533*62365482SMaheswara Kurapati } 534*62365482SMaheswara Kurapati 535*62365482SMaheswara Kurapati for (int i = MAX31785_MIN_TEMP_PAGE; i <= MAX31785_MAX_TEMP_PAGE; i++) { 536*62365482SMaheswara Kurapati pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE | PB_HAS_TEMPERATURE); 537*62365482SMaheswara Kurapati } 538*62365482SMaheswara Kurapati 539*62365482SMaheswara Kurapati for (int i = MAX31785_MIN_ADC_VOLTAGE_PAGE; 540*62365482SMaheswara Kurapati i <= MAX31785_MAX_ADC_VOLTAGE_PAGE; 541*62365482SMaheswara Kurapati i++) { 542*62365482SMaheswara Kurapati pmbus_page_config(pmdev, i, PB_HAS_VOUT_MODE | PB_HAS_VOUT | 543*62365482SMaheswara Kurapati PB_HAS_VOUT_RATING); 544*62365482SMaheswara Kurapati } 545*62365482SMaheswara Kurapati } 546*62365482SMaheswara Kurapati 547*62365482SMaheswara Kurapati static void max31785_class_init(ObjectClass *klass, void *data) 548*62365482SMaheswara Kurapati { 549*62365482SMaheswara Kurapati ResettableClass *rc = RESETTABLE_CLASS(klass); 550*62365482SMaheswara Kurapati DeviceClass *dc = DEVICE_CLASS(klass); 551*62365482SMaheswara Kurapati PMBusDeviceClass *k = PMBUS_DEVICE_CLASS(klass); 552*62365482SMaheswara Kurapati dc->desc = "Maxim MAX31785 6-Channel Fan Controller"; 553*62365482SMaheswara Kurapati dc->vmsd = &vmstate_max31785; 554*62365482SMaheswara Kurapati k->write_data = max31785_write_data; 555*62365482SMaheswara Kurapati k->receive_byte = max31785_read_byte; 556*62365482SMaheswara Kurapati k->device_num_pages = MAX31785_TOTAL_NUM_PAGES; 557*62365482SMaheswara Kurapati rc->phases.exit = max31785_exit_reset; 558*62365482SMaheswara Kurapati } 559*62365482SMaheswara Kurapati 560*62365482SMaheswara Kurapati static const TypeInfo max31785_info = { 561*62365482SMaheswara Kurapati .name = TYPE_MAX31785, 562*62365482SMaheswara Kurapati .parent = TYPE_PMBUS_DEVICE, 563*62365482SMaheswara Kurapati .instance_size = sizeof(MAX31785State), 564*62365482SMaheswara Kurapati .instance_init = max31785_init, 565*62365482SMaheswara Kurapati .class_init = max31785_class_init, 566*62365482SMaheswara Kurapati }; 567*62365482SMaheswara Kurapati 568*62365482SMaheswara Kurapati static void max31785_register_types(void) 569*62365482SMaheswara Kurapati { 570*62365482SMaheswara Kurapati type_register_static(&max31785_info); 571*62365482SMaheswara Kurapati } 572*62365482SMaheswara Kurapati 573*62365482SMaheswara Kurapati type_init(max31785_register_types) 574