1 /** 2 * Copyright © 2020 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include <cmath> 19 #include <cstdint> 20 #include <string> 21 22 /** 23 * @namespace pmbus_utils 24 * 25 * Contains utilities for sending PMBus commands over an I2C interface. 26 */ 27 namespace phosphor::power::regulators::pmbus_utils 28 { 29 30 /* 31 * PMBus command codes. 32 * 33 * The constant names are all uppercase to match the PMBus documentation. 34 * 35 * Only the commands that are currently used by this application are defined. 36 * See the PMBus documentation for all valid command codes. 37 */ 38 const uint8_t VOUT_MODE{0x20u}; 39 const uint8_t VOUT_COMMAND{0x21u}; 40 41 /** 42 * Sensor data format. 43 */ 44 enum class SensorDataFormat 45 { 46 /** 47 * Linear data format used for values not related to voltage output, such 48 * as output current, input voltage, and temperature. Two byte value with 49 * an 11-bit, two's complement mantissa and a 5-bit, two's complement 50 * exponent. 51 */ 52 linear_11, 53 54 /** 55 * Linear data format used for values related to voltage output. Two 56 * byte (16-bit), unsigned integer that is raised to the power of an 57 * exponent. The exponent is not stored within the two bytes. 58 */ 59 linear_16 60 }; 61 62 /** 63 * Data formats for output voltage. 64 * 65 * These formats are used for commanding and reading output voltage and related 66 * parameters. 67 */ 68 enum class VoutDataFormat 69 { 70 /** 71 * Linear scale that uses a two byte unsigned binary integer with a scaling 72 * factor. 73 */ 74 linear, 75 76 /** 77 * Format that supports transmitting VID codes. 78 */ 79 vid, 80 81 /** 82 * Direct format that uses an equation and device supplied coefficients. 83 */ 84 direct, 85 86 /** 87 * Half-precision floating point format that follows the IEEE-754 standard 88 * for representing magnitudes in 16 bits. 89 */ 90 ieee 91 }; 92 93 /** 94 * Parse the one byte value of the VOUT_MODE command. 95 * 96 * VOUT_MODE contains a 'mode' field that indicates the data format used for 97 * output voltage values. 98 * 99 * VOUT_MODE also contains a 'parameter' field whose value is dependent on the 100 * data format: 101 * - Linear format: value is an exponent 102 * - VID format: value is a VID code 103 * - IEEE and Direct formats: value is not used 104 * 105 * @param voutModeValue one byte value of VOUT_MODE command 106 * @param format data format from the 'mode' field 107 * @param parameter parameter value from the 'parameter' field 108 */ 109 void parseVoutMode(uint8_t voutModeValue, VoutDataFormat& format, 110 int8_t& parameter); 111 112 /** 113 * Converts the specified SensorDataFormat value to a string. 114 * 115 * @param format SensorDataFormat value 116 * @return string corresponding to the enum value 117 */ 118 std::string toString(SensorDataFormat format); 119 120 /** 121 * Converts the specified VoutDataFormat value to string. 122 * 123 * @param format VoutDataFormat format 124 * @return string corresponding to the enum value 125 */ 126 std::string toString(VoutDataFormat format); 127 128 /** 129 * Converts a linear data format value to a double value. 130 * 131 * This data format consists of the following: 132 * - Two byte value 133 * - 11-bit two's complement mantissa value stored in the two bytes 134 * - 5-bit two's complement exponent value stored in the two bytes 135 * 136 * @param value linear data format value 137 * @return double value 138 */ 139 inline double convertFromLinear(uint16_t value) 140 { 141 // extract exponent from most significant 5 bits 142 uint8_t exponentField = value >> 11; 143 144 // extract mantissa from least significant 11 bits 145 uint16_t mantissaField = value & 0x7FFu; 146 147 // sign extend exponent 148 if (exponentField > 0x0Fu) 149 { 150 exponentField |= 0xE0u; 151 } 152 153 // sign extend mantissa 154 if (mantissaField > 0x03FFu) 155 { 156 mantissaField |= 0xF800u; 157 } 158 159 int8_t exponent = static_cast<int8_t>(exponentField); 160 int16_t mantissa = static_cast<int16_t>(mantissaField); 161 162 // compute value as mantissa * 2^(exponent) 163 double decimal = mantissa * std::pow(2.0, exponent); 164 return decimal; 165 } 166 167 /** 168 * Converts a linear data format output voltage value to a volts value. 169 * 170 * This data format consists of the following: 171 * - Two byte value 172 * - 16-bit unsigned mantissa value stored in the two bytes 173 * - 5-bit signed exponent value that is not stored in the two bytes 174 * 175 * @param value linear data format output voltage value 176 * @param exponent exponent value obtained from VOUT_MODE or device 177 * documentation 178 * @return normal decimal number 179 */ 180 inline double convertFromVoutLinear(uint16_t value, int8_t exponent) 181 { 182 // compute value as mantissa * 2^(exponent) 183 double decimal = value * std::pow(2.0, exponent); 184 return decimal; 185 } 186 187 /** 188 * Converts a volts value to the linear data format for output voltage. 189 * 190 * This data format consists of the following: 191 * - Two byte value 192 * - 16-bit unsigned mantissa value stored in the two bytes 193 * - 5-bit signed exponent value that is not stored in the two bytes 194 * 195 * The exponent value is typically obtained from the PMBus VOUT_MODE command 196 * or from the hardware device documentation (data sheet). 197 * 198 * Note that this format differs from the linear data format for values 199 * unrelated to output voltage. 200 * 201 * @param volts volts value to convert; must not be negative 202 * @param exponent 5-bit signed exponent used to convert value 203 * @return linear data format value 204 */ 205 inline uint16_t convertToVoutLinear(double volts, int8_t exponent) 206 { 207 // Obtain mantissa using equation 'mantissa = volts / 2^exponent' 208 double mantissa = volts / std::pow(2.0, static_cast<double>(exponent)); 209 210 // Return the mantissa value after converting to a rounded uint16_t 211 return static_cast<uint16_t>(std::lround(mantissa)); 212 } 213 214 } // namespace phosphor::power::regulators::pmbus_utils 215