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 * Sensor Value Type. 64 */ 65 enum class SensorValueType 66 { 67 /** 68 * Output current. 69 */ 70 iout, 71 72 /** 73 * Highest output current. 74 */ 75 iout_peak, 76 77 /** 78 * Lowest output current. 79 */ 80 iout_valley, 81 82 /** 83 * Output power. 84 */ 85 pout, 86 87 /** 88 * Temperature. 89 */ 90 temperature, 91 92 /** 93 * Highest temperature. 94 */ 95 temperature_peak, 96 97 /** 98 * Output voltage. 99 */ 100 vout, 101 102 /** 103 * Highest output voltage. 104 */ 105 vout_peak, 106 107 /** 108 * Lowest output voltage. 109 */ 110 vout_valley 111 }; 112 113 /** 114 * Data formats for output voltage. 115 * 116 * These formats are used for commanding and reading output voltage and related 117 * parameters. 118 */ 119 enum class VoutDataFormat 120 { 121 /** 122 * Linear scale that uses a two byte unsigned binary integer with a scaling 123 * factor. 124 */ 125 linear, 126 127 /** 128 * Format that supports transmitting VID codes. 129 */ 130 vid, 131 132 /** 133 * Direct format that uses an equation and device supplied coefficients. 134 */ 135 direct, 136 137 /** 138 * Half-precision floating point format that follows the IEEE-754 standard 139 * for representing magnitudes in 16 bits. 140 */ 141 ieee 142 }; 143 144 /** 145 * This struct represents one sensor reading from a device. 146 */ 147 struct SensorReading 148 { 149 /** 150 * Sensor value type that was read. 151 */ 152 SensorValueType type; 153 154 /** 155 * Sensor value that was read. 156 */ 157 double value; 158 }; 159 160 /** 161 * Parse the one byte value of the VOUT_MODE command. 162 * 163 * VOUT_MODE contains a 'mode' field that indicates the data format used for 164 * output voltage values. 165 * 166 * VOUT_MODE also contains a 'parameter' field whose value is dependent on the 167 * data format: 168 * - Linear format: value is an exponent 169 * - VID format: value is a VID code 170 * - IEEE and Direct formats: value is not used 171 * 172 * @param voutModeValue one byte value of VOUT_MODE command 173 * @param format data format from the 'mode' field 174 * @param parameter parameter value from the 'parameter' field 175 */ 176 void parseVoutMode(uint8_t voutModeValue, VoutDataFormat& format, 177 int8_t& parameter); 178 179 /** 180 * Converts the specified SensorDataFormat value to a string. 181 * 182 * @param format SensorDataFormat value 183 * @return string corresponding to the enum value 184 */ 185 std::string toString(SensorDataFormat format); 186 187 /** 188 * Converts the specified SensorValueType value to string. 189 * 190 * @param type SensorValueType type 191 * @return string corresponding to the enum value 192 */ 193 std::string toString(SensorValueType type); 194 195 /** 196 * Converts the specified VoutDataFormat value to string. 197 * 198 * @param format VoutDataFormat format 199 * @return string corresponding to the enum value 200 */ 201 std::string toString(VoutDataFormat format); 202 203 /** 204 * Converts a linear data format value to a double value. 205 * 206 * This data format consists of the following: 207 * - Two byte value 208 * - 11-bit two's complement mantissa value stored in the two bytes 209 * - 5-bit two's complement exponent value stored in the two bytes 210 * 211 * @param value linear data format value 212 * @return double value 213 */ 214 inline double convertFromLinear(uint16_t value) 215 { 216 // extract exponent from most significant 5 bits 217 uint8_t exponentField = value >> 11; 218 219 // extract mantissa from least significant 11 bits 220 uint16_t mantissaField = value & 0x7FFu; 221 222 // sign extend exponent 223 if (exponentField > 0x0Fu) 224 { 225 exponentField |= 0xE0u; 226 } 227 228 // sign extend mantissa 229 if (mantissaField > 0x03FFu) 230 { 231 mantissaField |= 0xF800u; 232 } 233 234 int8_t exponent = static_cast<int8_t>(exponentField); 235 int16_t mantissa = static_cast<int16_t>(mantissaField); 236 237 // compute value as mantissa * 2^(exponent) 238 double decimal = mantissa * std::pow(2.0, exponent); 239 return decimal; 240 } 241 242 /** 243 * Converts a linear data format output voltage value to a volts value. 244 * 245 * This data format consists of the following: 246 * - Two byte value 247 * - 16-bit unsigned mantissa value stored in the two bytes 248 * - 5-bit signed exponent value that is not stored in the two bytes 249 * 250 * @param value linear data format output voltage value 251 * @param exponent exponent value obtained from VOUT_MODE or device 252 * documentation 253 * @return normal decimal number 254 */ 255 inline double convertFromVoutLinear(uint16_t value, int8_t exponent) 256 { 257 // compute value as mantissa * 2^(exponent) 258 double decimal = value * std::pow(2.0, exponent); 259 return decimal; 260 } 261 262 /** 263 * Converts a volts value to the linear data format for output voltage. 264 * 265 * This data format consists of the following: 266 * - Two byte value 267 * - 16-bit unsigned mantissa value stored in the two bytes 268 * - 5-bit signed exponent value that is not stored in the two bytes 269 * 270 * The exponent value is typically obtained from the PMBus VOUT_MODE command 271 * or from the hardware device documentation (data sheet). 272 * 273 * Note that this format differs from the linear data format for values 274 * unrelated to output voltage. 275 * 276 * @param volts volts value to convert; must not be negative 277 * @param exponent 5-bit signed exponent used to convert value 278 * @return linear data format value 279 */ 280 inline uint16_t convertToVoutLinear(double volts, int8_t exponent) 281 { 282 // Obtain mantissa using equation 'mantissa = volts / 2^exponent' 283 double mantissa = volts / std::pow(2.0, static_cast<double>(exponent)); 284 285 // Return the mantissa value after converting to a rounded uint16_t 286 return static_cast<uint16_t>(std::lround(mantissa)); 287 } 288 289 } // namespace phosphor::power::regulators::pmbus_utils 290