blob: 4d4b047c9697b7834030b4f16f76b204d93a6871 [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/**
Bob Kingb1ab1cf2020-05-18 18:26:26 +0800145 * This struct represents one sensor reading from a device.
146 */
147struct 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/**
Shawn McCarney6663abf2020-02-29 17:25:48 -0600161 * 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 */
176void parseVoutMode(uint8_t voutModeValue, VoutDataFormat& format,
177 int8_t& parameter);
178
179/**
Bob Kingd6820bb2020-04-28 15:37:02 +0800180 * Converts the specified SensorDataFormat value to a string.
181 *
182 * @param format SensorDataFormat value
183 * @return string corresponding to the enum value
184 */
185std::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 */
193std::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 */
201std::string toString(VoutDataFormat format);
202
203/**
Bob King19523dd2020-05-08 14:50:36 +0800204 * 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 */
214inline 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/**
Bob King8d0b3ce2020-05-12 15:30:08 +0800243 * 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 */
255inline 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/**
Shawn McCarney6663abf2020-02-29 17:25:48 -0600263 * 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 */
280inline 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