blob: 438ee465dc996774a909503d94885344c0bd8f06 [file] [log] [blame]
Shawn McCarney6663abf2020-02-29 17:25:48 -06001/**
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>
Bob Kingd6820bb2020-04-28 15:37:02 +080020#include <string>
Shawn McCarney6663abf2020-02-29 17:25:48 -060021
22/**
23 * @namespace pmbus_utils
24 *
25 * Contains utilities for sending PMBus commands over an I2C interface.
26 */
27namespace 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 */
38const uint8_t VOUT_MODE{0x20u};
39const uint8_t VOUT_COMMAND{0x21u};
40
41/**
Bob Kingd6820bb2020-04-28 15:37:02 +080042 * Sensor data format.
43 */
44enum 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 */
65enum 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/**
Shawn McCarney6663abf2020-02-29 17:25:48 -0600114 * Data formats for output voltage.
115 *
116 * These formats are used for commanding and reading output voltage and related
117 * parameters.
118 */
119enum 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 * Parse the one byte value of the VOUT_MODE command.
146 *
147 * VOUT_MODE contains a 'mode' field that indicates the data format used for
148 * output voltage values.
149 *
150 * VOUT_MODE also contains a 'parameter' field whose value is dependent on the
151 * data format:
152 * - Linear format: value is an exponent
153 * - VID format: value is a VID code
154 * - IEEE and Direct formats: value is not used
155 *
156 * @param voutModeValue one byte value of VOUT_MODE command
157 * @param format data format from the 'mode' field
158 * @param parameter parameter value from the 'parameter' field
159 */
160void parseVoutMode(uint8_t voutModeValue, VoutDataFormat& format,
161 int8_t& parameter);
162
163/**
Bob Kingd6820bb2020-04-28 15:37:02 +0800164 * Converts the specified SensorDataFormat value to a string.
165 *
166 * @param format SensorDataFormat value
167 * @return string corresponding to the enum value
168 */
169std::string toString(SensorDataFormat format);
170
171/**
172 * Converts the specified SensorValueType value to string.
173 *
174 * @param type SensorValueType type
175 * @return string corresponding to the enum value
176 */
177std::string toString(SensorValueType type);
178
179/**
180 * Converts the specified VoutDataFormat value to string.
181 *
182 * @param format VoutDataFormat format
183 * @return string corresponding to the enum value
184 */
185std::string toString(VoutDataFormat format);
186
187/**
Bob King19523dd2020-05-08 14:50:36 +0800188 * Converts a linear data format value to a double value.
189 *
190 * This data format consists of the following:
191 * - Two byte value
192 * - 11-bit two's complement mantissa value stored in the two bytes
193 * - 5-bit two's complement exponent value stored in the two bytes
194 *
195 * @param value linear data format value
196 * @return double value
197 */
198inline double convertFromLinear(uint16_t value)
199{
200 // extract exponent from most significant 5 bits
201 uint8_t exponentField = value >> 11;
202
203 // extract mantissa from least significant 11 bits
204 uint16_t mantissaField = value & 0x7FFu;
205
206 // sign extend exponent
207 if (exponentField > 0x0Fu)
208 {
209 exponentField |= 0xE0u;
210 }
211
212 // sign extend mantissa
213 if (mantissaField > 0x03FFu)
214 {
215 mantissaField |= 0xF800u;
216 }
217
218 int8_t exponent = static_cast<int8_t>(exponentField);
219 int16_t mantissa = static_cast<int16_t>(mantissaField);
220
221 // compute value as mantissa * 2^(exponent)
222 double decimal = mantissa * std::pow(2.0, exponent);
223 return decimal;
224}
225
226/**
Bob King8d0b3ce2020-05-12 15:30:08 +0800227 * Converts a linear data format output voltage value to a volts value.
228 *
229 * This data format consists of the following:
230 * - Two byte value
231 * - 16-bit unsigned mantissa value stored in the two bytes
232 * - 5-bit signed exponent value that is not stored in the two bytes
233 *
234 * @param value linear data format output voltage value
235 * @param exponent exponent value obtained from VOUT_MODE or device
236 * documentation
237 * @return normal decimal number
238 */
239inline double convertFromVoutLinear(uint16_t value, int8_t exponent)
240{
241 // compute value as mantissa * 2^(exponent)
242 double decimal = value * std::pow(2.0, exponent);
243 return decimal;
244}
245
246/**
Shawn McCarney6663abf2020-02-29 17:25:48 -0600247 * Converts a volts value to the linear data format for output voltage.
248 *
249 * This data format consists of the following:
250 * - Two byte value
251 * - 16-bit unsigned mantissa value stored in the two bytes
252 * - 5-bit signed exponent value that is not stored in the two bytes
253 *
254 * The exponent value is typically obtained from the PMBus VOUT_MODE command
255 * or from the hardware device documentation (data sheet).
256 *
257 * Note that this format differs from the linear data format for values
258 * unrelated to output voltage.
259 *
260 * @param volts volts value to convert; must not be negative
261 * @param exponent 5-bit signed exponent used to convert value
262 * @return linear data format value
263 */
264inline uint16_t convertToVoutLinear(double volts, int8_t exponent)
265{
266 // Obtain mantissa using equation 'mantissa = volts / 2^exponent'
267 double mantissa = volts / std::pow(2.0, static_cast<double>(exponent));
268
269 // Return the mantissa value after converting to a rounded uint16_t
270 return static_cast<uint16_t>(std::lround(mantissa));
271}
272
273} // namespace phosphor::power::regulators::pmbus_utils