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 */
convertFromLinear(uint16_t value)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 */
convertFromVoutLinear(uint16_t value,int8_t exponent)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 */
convertToVoutLinear(double volts,int8_t exponent)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