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  * 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  */
160 void parseVoutMode(uint8_t voutModeValue, VoutDataFormat& format,
161                    int8_t& parameter);
162 
163 /**
164  * Converts the specified SensorDataFormat value to a string.
165  *
166  * @param format SensorDataFormat value
167  * @return string corresponding to the enum value
168  */
169 std::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  */
177 std::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  */
185 std::string toString(VoutDataFormat format);
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