in hw/i2c/pmbus_device.c [246:954]
static uint8_t pmbus_receive_byte(SMBusDevice *smd)
{
PMBusDevice *pmdev = PMBUS_DEVICE(smd);
PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev);
uint8_t ret = 0xFF;
uint8_t index = pmdev->page;
if (pmdev->out_buf_len != 0) {
ret = pmbus_out_buf_pop(pmdev);
return ret;
}
switch (pmdev->code) {
case PMBUS_PAGE:
pmbus_send8(pmdev, pmdev->page);
break;
case PMBUS_OPERATION: /* R/W byte */
pmbus_send8(pmdev, pmdev->pages[index].operation);
break;
case PMBUS_ON_OFF_CONFIG: /* R/W byte */
pmbus_send8(pmdev, pmdev->pages[index].on_off_config);
break;
case PMBUS_PHASE: /* R/W byte */
pmbus_send8(pmdev, pmdev->pages[index].phase);
break;
case PMBUS_WRITE_PROTECT: /* R/W byte */
pmbus_send8(pmdev, pmdev->pages[index].write_protect);
break;
case PMBUS_CAPABILITY:
pmbus_send8(pmdev, pmdev->capability);
break;
case PMBUS_VOUT_MODE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MODE) {
pmbus_send8(pmdev, pmdev->pages[index].vout_mode);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_COMMAND: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_command);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_TRIM: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_trim);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_CAL_OFFSET: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_cal_offset);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_MAX: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_max);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_MARGIN_HIGH: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) {
pmbus_send16(pmdev, pmdev->pages[index].vout_margin_high);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_MARGIN_LOW: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) {
pmbus_send16(pmdev, pmdev->pages[index].vout_margin_low);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_TRANSITION_RATE: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_transition_rate);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_DROOP: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_droop);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_SCALE_LOOP: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_scale_loop);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_SCALE_MONITOR: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_scale_monitor);
} else {
goto passthough;
}
break;
/* TODO: implement coefficients support */
case PMBUS_POUT_MAX: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
pmbus_send16(pmdev, pmdev->pages[index].pout_max);
} else {
goto passthough;
}
break;
case PMBUS_VIN_ON: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
pmbus_send16(pmdev, pmdev->pages[index].vin_on);
} else {
goto passthough;
}
break;
case PMBUS_VIN_OFF: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
pmbus_send16(pmdev, pmdev->pages[index].vin_off);
} else {
goto passthough;
}
break;
case PMBUS_IOUT_CAL_GAIN: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT_GAIN) {
pmbus_send16(pmdev, pmdev->pages[index].iout_cal_gain);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_OV_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_ov_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_OV_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send8(pmdev, pmdev->pages[index].vout_ov_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_OV_WARN_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_ov_warn_limit);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_UV_WARN_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_uv_warn_limit);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_UV_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].vout_uv_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_VOUT_UV_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send8(pmdev, pmdev->pages[index].vout_uv_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_IOUT_OC_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
pmbus_send16(pmdev, pmdev->pages[index].iout_oc_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_IOUT_OC_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
pmbus_send8(pmdev, pmdev->pages[index].iout_oc_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_IOUT_OC_LV_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
pmbus_send16(pmdev, pmdev->pages[index].iout_oc_lv_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_IOUT_OC_LV_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
pmbus_send8(pmdev, pmdev->pages[index].iout_oc_lv_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_IOUT_OC_WARN_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
pmbus_send16(pmdev, pmdev->pages[index].iout_oc_warn_limit);
} else {
goto passthough;
}
break;
case PMBUS_IOUT_UC_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
pmbus_send16(pmdev, pmdev->pages[index].iout_uc_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_IOUT_UC_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
pmbus_send8(pmdev, pmdev->pages[index].iout_uc_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_OT_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
pmbus_send16(pmdev, pmdev->pages[index].ot_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_OT_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
pmbus_send8(pmdev, pmdev->pages[index].ot_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_OT_WARN_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
pmbus_send16(pmdev, pmdev->pages[index].ot_warn_limit);
} else {
goto passthough;
}
break;
case PMBUS_UT_WARN_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
pmbus_send16(pmdev, pmdev->pages[index].ut_warn_limit);
} else {
goto passthough;
}
break;
case PMBUS_UT_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
pmbus_send16(pmdev, pmdev->pages[index].ut_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_UT_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
pmbus_send8(pmdev, pmdev->pages[index].ut_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_VIN_OV_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
pmbus_send16(pmdev, pmdev->pages[index].vin_ov_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_VIN_OV_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
pmbus_send8(pmdev, pmdev->pages[index].vin_ov_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_VIN_OV_WARN_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
pmbus_send16(pmdev, pmdev->pages[index].vin_ov_warn_limit);
} else {
goto passthough;
}
break;
case PMBUS_VIN_UV_WARN_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
pmbus_send16(pmdev, pmdev->pages[index].vin_uv_warn_limit);
} else {
goto passthough;
}
break;
case PMBUS_VIN_UV_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
pmbus_send16(pmdev, pmdev->pages[index].vin_uv_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_VIN_UV_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
pmbus_send8(pmdev, pmdev->pages[index].vin_uv_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_IIN_OC_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
pmbus_send16(pmdev, pmdev->pages[index].iin_oc_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_IIN_OC_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
pmbus_send8(pmdev, pmdev->pages[index].iin_oc_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_IIN_OC_WARN_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
pmbus_send16(pmdev, pmdev->pages[index].iin_oc_warn_limit);
} else {
goto passthough;
}
break;
case PMBUS_POUT_OP_FAULT_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
pmbus_send16(pmdev, pmdev->pages[index].pout_op_fault_limit);
} else {
goto passthough;
}
break;
case PMBUS_POUT_OP_FAULT_RESPONSE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
pmbus_send8(pmdev, pmdev->pages[index].pout_op_fault_response);
} else {
goto passthough;
}
break;
case PMBUS_POUT_OP_WARN_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
pmbus_send16(pmdev, pmdev->pages[index].pout_op_warn_limit);
} else {
goto passthough;
}
break;
case PMBUS_PIN_OP_WARN_LIMIT: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_PIN) {
pmbus_send16(pmdev, pmdev->pages[index].pin_op_warn_limit);
} else {
goto passthough;
}
break;
case PMBUS_STATUS_BYTE: /* R/W byte */
pmbus_send8(pmdev, pmdev->pages[index].status_word & 0xFF);
break;
case PMBUS_STATUS_WORD: /* R/W word */
pmbus_send16(pmdev, pmdev->pages[index].status_word);
break;
case PMBUS_STATUS_VOUT: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send8(pmdev, pmdev->pages[index].status_vout);
} else {
goto passthough;
}
break;
case PMBUS_STATUS_IOUT: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
pmbus_send8(pmdev, pmdev->pages[index].status_iout);
} else {
goto passthough;
}
break;
case PMBUS_STATUS_INPUT: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_VIN ||
pmdev->pages[index].page_flags & PB_HAS_IIN ||
pmdev->pages[index].page_flags & PB_HAS_PIN) {
pmbus_send8(pmdev, pmdev->pages[index].status_input);
} else {
goto passthough;
}
break;
case PMBUS_STATUS_TEMPERATURE: /* R/W byte */
if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
pmbus_send8(pmdev, pmdev->pages[index].status_temperature);
} else {
goto passthough;
}
break;
case PMBUS_STATUS_CML: /* R/W byte */
pmbus_send8(pmdev, pmdev->pages[index].status_cml);
break;
case PMBUS_STATUS_OTHER: /* R/W byte */
pmbus_send8(pmdev, pmdev->pages[index].status_other);
break;
case PMBUS_READ_EIN: /* Read-Only block 5 bytes */
if (pmdev->pages[index].page_flags & PB_HAS_EIN) {
pmbus_send(pmdev, pmdev->pages[index].read_ein, 5);
} else {
goto passthough;
}
break;
case PMBUS_READ_EOUT: /* Read-Only block 5 bytes */
if (pmdev->pages[index].page_flags & PB_HAS_EOUT) {
pmbus_send(pmdev, pmdev->pages[index].read_eout, 5);
} else {
goto passthough;
}
break;
case PMBUS_READ_VIN: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_VIN) {
pmbus_send16(pmdev, pmdev->pages[index].read_vin);
} else {
goto passthough;
}
break;
case PMBUS_READ_IIN: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_IIN) {
pmbus_send16(pmdev, pmdev->pages[index].read_iin);
} else {
goto passthough;
}
break;
case PMBUS_READ_VOUT: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT) {
pmbus_send16(pmdev, pmdev->pages[index].read_vout);
} else {
goto passthough;
}
break;
case PMBUS_READ_IOUT: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT) {
pmbus_send16(pmdev, pmdev->pages[index].read_iout);
} else {
goto passthough;
}
break;
case PMBUS_READ_TEMPERATURE_1: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) {
pmbus_send16(pmdev, pmdev->pages[index].read_temperature_1);
} else {
goto passthough;
}
break;
case PMBUS_READ_TEMPERATURE_2: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_TEMP2) {
pmbus_send16(pmdev, pmdev->pages[index].read_temperature_2);
} else {
goto passthough;
}
break;
case PMBUS_READ_TEMPERATURE_3: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_TEMP3) {
pmbus_send16(pmdev, pmdev->pages[index].read_temperature_3);
} else {
goto passthough;
}
break;
case PMBUS_READ_POUT: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_POUT) {
pmbus_send16(pmdev, pmdev->pages[index].read_pout);
} else {
goto passthough;
}
break;
case PMBUS_READ_PIN: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_PIN) {
pmbus_send16(pmdev, pmdev->pages[index].read_pin);
} else {
goto passthough;
}
break;
case PMBUS_REVISION: /* Read-Only byte */
pmbus_send8(pmdev, pmdev->pages[index].revision);
break;
case PMBUS_MFR_ID: /* R/W block */
if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
pmbus_send_string(pmdev, pmdev->pages[index].mfr_id);
} else {
goto passthough;
}
break;
case PMBUS_MFR_MODEL: /* R/W block */
if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
pmbus_send_string(pmdev, pmdev->pages[index].mfr_model);
} else {
goto passthough;
}
break;
case PMBUS_MFR_REVISION: /* R/W block */
if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
pmbus_send_string(pmdev, pmdev->pages[index].mfr_revision);
} else {
goto passthough;
}
break;
case PMBUS_MFR_LOCATION: /* R/W block */
if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) {
pmbus_send_string(pmdev, pmdev->pages[index].mfr_location);
} else {
goto passthough;
}
break;
case PMBUS_MFR_VIN_MIN: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_VIN_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_vin_min);
} else {
goto passthough;
}
break;
case PMBUS_MFR_VIN_MAX: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_VIN_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_vin_max);
} else {
goto passthough;
}
break;
case PMBUS_MFR_IIN_MAX: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_IIN_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_iin_max);
} else {
goto passthough;
}
break;
case PMBUS_MFR_PIN_MAX: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_PIN_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_pin_max);
} else {
goto passthough;
}
break;
case PMBUS_MFR_VOUT_MIN: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_vout_min);
} else {
goto passthough;
}
break;
case PMBUS_MFR_VOUT_MAX: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_vout_max);
} else {
goto passthough;
}
break;
case PMBUS_MFR_IOUT_MAX: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_IOUT_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_iout_max);
} else {
goto passthough;
}
break;
case PMBUS_MFR_POUT_MAX: /* Read-Only word */
if (pmdev->pages[index].page_flags & PB_HAS_POUT_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_pout_max);
} else {
goto passthough;
}
break;
case PMBUS_MFR_MAX_TEMP_1: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_1);
} else {
goto passthough;
}
break;
case PMBUS_MFR_MAX_TEMP_2: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_2);
} else {
goto passthough;
}
break;
case PMBUS_MFR_MAX_TEMP_3: /* R/W word */
if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) {
pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_3);
} else {
goto passthough;
}
break;
case PMBUS_CLEAR_FAULTS: /* Send Byte */
case PMBUS_PAGE_PLUS_WRITE: /* Block Write-only */
case PMBUS_STORE_DEFAULT_ALL: /* Send Byte */
case PMBUS_RESTORE_DEFAULT_ALL: /* Send Byte */
case PMBUS_STORE_DEFAULT_CODE: /* Write-only Byte */
case PMBUS_RESTORE_DEFAULT_CODE: /* Write-only Byte */
case PMBUS_STORE_USER_ALL: /* Send Byte */
case PMBUS_RESTORE_USER_ALL: /* Send Byte */
case PMBUS_STORE_USER_CODE: /* Write-only Byte */
case PMBUS_RESTORE_USER_CODE: /* Write-only Byte */
case PMBUS_QUERY: /* Write-Only */
qemu_log_mask(LOG_GUEST_ERROR,
"%s: reading from write only register 0x%02x\n",
__func__, pmdev->code);
break;
passthough:
default:
/* Pass through read request if not handled */
if (pmdc->receive_byte) {
ret = pmdc->receive_byte(pmdev);
}
break;
}
if (pmdev->out_buf_len != 0) {
ret = pmbus_out_buf_pop(pmdev);
return ret;
}
return ret;
}