blob: 94e4ef1773dfe194738e82b58dd648ef768c95f6 [file] [log] [blame]
/**
* Copyright © 2020 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cmath>
#include <cstdint>
#include <string>
/**
* @namespace pmbus_utils
*
* Contains utilities for sending PMBus commands over an I2C interface.
*/
namespace phosphor::power::regulators::pmbus_utils
{
/*
* PMBus command codes.
*
* The constant names are all uppercase to match the PMBus documentation.
*
* Only the commands that are currently used by this application are defined.
* See the PMBus documentation for all valid command codes.
*/
const uint8_t VOUT_MODE{0x20u};
const uint8_t VOUT_COMMAND{0x21u};
/**
* Sensor data format.
*/
enum class SensorDataFormat
{
/**
* Linear data format used for values not related to voltage output, such
* as output current, input voltage, and temperature. Two byte value with
* an 11-bit, two's complement mantissa and a 5-bit, two's complement
* exponent.
*/
linear_11,
/**
* Linear data format used for values related to voltage output. Two
* byte (16-bit), unsigned integer that is raised to the power of an
* exponent. The exponent is not stored within the two bytes.
*/
linear_16
};
/**
* Data formats for output voltage.
*
* These formats are used for commanding and reading output voltage and related
* parameters.
*/
enum class VoutDataFormat
{
/**
* Linear scale that uses a two byte unsigned binary integer with a scaling
* factor.
*/
linear,
/**
* Format that supports transmitting VID codes.
*/
vid,
/**
* Direct format that uses an equation and device supplied coefficients.
*/
direct,
/**
* Half-precision floating point format that follows the IEEE-754 standard
* for representing magnitudes in 16 bits.
*/
ieee
};
/**
* Parse the one byte value of the VOUT_MODE command.
*
* VOUT_MODE contains a 'mode' field that indicates the data format used for
* output voltage values.
*
* VOUT_MODE also contains a 'parameter' field whose value is dependent on the
* data format:
* - Linear format: value is an exponent
* - VID format: value is a VID code
* - IEEE and Direct formats: value is not used
*
* @param voutModeValue one byte value of VOUT_MODE command
* @param format data format from the 'mode' field
* @param parameter parameter value from the 'parameter' field
*/
void parseVoutMode(uint8_t voutModeValue, VoutDataFormat& format,
int8_t& parameter);
/**
* Converts the specified SensorDataFormat value to a string.
*
* @param format SensorDataFormat value
* @return string corresponding to the enum value
*/
std::string toString(SensorDataFormat format);
/**
* Converts the specified VoutDataFormat value to string.
*
* @param format VoutDataFormat format
* @return string corresponding to the enum value
*/
std::string toString(VoutDataFormat format);
/**
* Converts a linear data format value to a double value.
*
* This data format consists of the following:
* - Two byte value
* - 11-bit two's complement mantissa value stored in the two bytes
* - 5-bit two's complement exponent value stored in the two bytes
*
* @param value linear data format value
* @return double value
*/
inline double convertFromLinear(uint16_t value)
{
// extract exponent from most significant 5 bits
uint8_t exponentField = value >> 11;
// extract mantissa from least significant 11 bits
uint16_t mantissaField = value & 0x7FFu;
// sign extend exponent
if (exponentField > 0x0Fu)
{
exponentField |= 0xE0u;
}
// sign extend mantissa
if (mantissaField > 0x03FFu)
{
mantissaField |= 0xF800u;
}
int8_t exponent = static_cast<int8_t>(exponentField);
int16_t mantissa = static_cast<int16_t>(mantissaField);
// compute value as mantissa * 2^(exponent)
double decimal = mantissa * std::pow(2.0, exponent);
return decimal;
}
/**
* Converts a linear data format output voltage value to a volts value.
*
* This data format consists of the following:
* - Two byte value
* - 16-bit unsigned mantissa value stored in the two bytes
* - 5-bit signed exponent value that is not stored in the two bytes
*
* @param value linear data format output voltage value
* @param exponent exponent value obtained from VOUT_MODE or device
* documentation
* @return normal decimal number
*/
inline double convertFromVoutLinear(uint16_t value, int8_t exponent)
{
// compute value as mantissa * 2^(exponent)
double decimal = value * std::pow(2.0, exponent);
return decimal;
}
/**
* Converts a volts value to the linear data format for output voltage.
*
* This data format consists of the following:
* - Two byte value
* - 16-bit unsigned mantissa value stored in the two bytes
* - 5-bit signed exponent value that is not stored in the two bytes
*
* The exponent value is typically obtained from the PMBus VOUT_MODE command
* or from the hardware device documentation (data sheet).
*
* Note that this format differs from the linear data format for values
* unrelated to output voltage.
*
* @param volts volts value to convert; must not be negative
* @param exponent 5-bit signed exponent used to convert value
* @return linear data format value
*/
inline uint16_t convertToVoutLinear(double volts, int8_t exponent)
{
// Obtain mantissa using equation 'mantissa = volts / 2^exponent'
double mantissa = volts / std::pow(2.0, static_cast<double>(exponent));
// Return the mantissa value after converting to a rounded uint16_t
return static_cast<uint16_t>(std::lround(mantissa));
}
} // namespace phosphor::power::regulators::pmbus_utils