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 "action_environment.hpp" 19 #include "i2c_action.hpp" 20 #include "i2c_interface.hpp" 21 #include "pmbus_utils.hpp" 22 23 #include <cstdint> 24 #include <optional> 25 #include <stdexcept> 26 #include <string> 27 28 namespace phosphor::power::regulators 29 { 30 31 /** 32 * @class PMBusWriteVoutCommandAction 33 * 34 * Writes the value of VOUT_COMMAND to set the output voltage of a PMBus 35 * regulator rail. Communicates with the device directly using the I2C 36 * interface. 37 * 38 * Implements the pmbus_write_vout_command action in the JSON config file. 39 * 40 * The volts value to write can be specified in the constructor. Otherwise, the 41 * volts value will be obtained from the ActionEnvironment. 42 * 43 * The PMBus specification defines four data formats for the value of 44 * VOUT_COMMAND: 45 * - Linear 46 * - VID 47 * - Direct 48 * - IEEE Half-Precision Floating Point 49 * Currently only the linear data format is supported. The volts value is 50 * converted into linear format before being written. 51 * 52 * The linear data format requires an exponent value. The exponent value can be 53 * specified in the constructor. Otherwise the exponent value will be obtained 54 * from the PMBus VOUT_MODE command. Note that some PMBus devices do not 55 * support the VOUT_MODE command. The exponent value for a device is often 56 * found in the device documentation (data sheet). 57 * 58 * If desired, write verification can be performed. The value of VOUT_COMMAND 59 * will be read from the device after it is written to ensure that it contains 60 * the expected value. If VOUT_COMMAND contains an unexpected value, a 61 * WriteVerificationError is thrown. To perform verification, the device must 62 * return all 16 bits of voltage data that were written to VOUT_COMMAND. 63 */ 64 class PMBusWriteVoutCommandAction : public I2CAction 65 { 66 public: 67 // Specify which compiler-generated methods we want 68 PMBusWriteVoutCommandAction() = delete; 69 PMBusWriteVoutCommandAction(const PMBusWriteVoutCommandAction&) = delete; 70 PMBusWriteVoutCommandAction(PMBusWriteVoutCommandAction&&) = delete; 71 PMBusWriteVoutCommandAction& 72 operator=(const PMBusWriteVoutCommandAction&) = delete; 73 PMBusWriteVoutCommandAction& 74 operator=(PMBusWriteVoutCommandAction&&) = delete; 75 virtual ~PMBusWriteVoutCommandAction() = default; 76 77 /** 78 * Constructor. 79 * 80 * Throws an exception if any of the input parameters are invalid. 81 * 82 * @param volts Optional volts value to write to VOUT_COMMAND. 83 * @param format Data format of the volts value written to VOUT_COMMAND. 84 * Currently the only supported format is linear. 85 * @param exponent Optional exponent to use to convert the volts value to 86 * linear data format. 87 * @param isVerified Specifies whether the updated value of VOUT_COMMAND is 88 * verified by reading it from the device. 89 */ PMBusWriteVoutCommandAction(std::optional<double> volts,pmbus_utils::VoutDataFormat format,std::optional<int8_t> exponent,bool isVerified)90 explicit PMBusWriteVoutCommandAction( 91 std::optional<double> volts, pmbus_utils::VoutDataFormat format, 92 std::optional<int8_t> exponent, bool isVerified) : 93 volts{volts}, format{format}, exponent{exponent}, 94 isWriteVerified{isVerified} 95 { 96 // Currently only linear format is supported 97 if (format != pmbus_utils::VoutDataFormat::linear) 98 { 99 throw std::invalid_argument{"Unsupported data format specified"}; 100 } 101 } 102 103 /** 104 * Executes this action. 105 * 106 * Writes a volts value to VOUT_COMMAND using the I2C interface. 107 * 108 * If a volts value was specified in the constructor, that value will be 109 * used. Otherwise the volts value will be obtained from the 110 * ActionEnvironment. 111 * 112 * The data format is specified in the constructor. Currently only the 113 * linear format is supported. 114 * 115 * An exponent value is required to convert the volts value to linear 116 * format. If an exponent value was specified in the constructor, that 117 * value will be used. Otherwise the exponent value will be obtained from 118 * the VOUT_MODE command. 119 * 120 * Write verification will be performed if specified in the constructor. 121 * 122 * The device is obtained from the ActionEnvironment. 123 * 124 * Throws an exception if an error occurs. 125 * 126 * @param environment action execution environment 127 * @return true 128 */ 129 virtual bool execute(ActionEnvironment& environment) override; 130 131 /** 132 * Returns the optional exponent value used to convert the volts value to 133 * linear data format. 134 * 135 * @return optional exponent value 136 */ getExponent() const137 std::optional<int8_t> getExponent() const 138 { 139 return exponent; 140 } 141 142 /** 143 * Returns the data format of the value written to VOUT_COMMAND. 144 * 145 * @return data format 146 */ getFormat() const147 pmbus_utils::VoutDataFormat getFormat() const 148 { 149 return format; 150 } 151 152 /** 153 * Returns the optional volts value to write to VOUT_COMMAND. 154 * 155 * @return optional volts value 156 */ getVolts() const157 std::optional<double> getVolts() const 158 { 159 return volts; 160 } 161 162 /** 163 * Returns whether write verification will be performed when writing to 164 * VOUT_COMMAND. 165 * 166 * @return true if write verification will be performed, false otherwise 167 */ isVerified() const168 bool isVerified() const 169 { 170 return isWriteVerified; 171 } 172 173 /** 174 * Returns a string description of this action. 175 * 176 * @return description of action 177 */ 178 virtual std::string toString() const override; 179 180 private: 181 /** 182 * Gets the exponent value to use to convert the volts value to linear data 183 * format. 184 * 185 * If an exponent value is defined for this action, that value is returned. 186 * Otherwise VOUT_MODE is read from the current device to obtain the 187 * exponent value. 188 * 189 * Throws an exception if an error occurs. 190 * 191 * @param environment action execution environment 192 * @param interface I2C interface to the current device 193 * @return exponent value 194 */ 195 int8_t getExponentValue(ActionEnvironment& environment, 196 i2c::I2CInterface& interface); 197 198 /** 199 * Gets the volts value to write to VOUT_COMMAND. 200 * 201 * If a volts value is defined for this action, that value is returned. 202 * Otherwise the volts value is obtained from the specified 203 * ActionEnvironment. 204 * 205 * Throws an exception if no volts value is defined. 206 * 207 * @param environment action execution environment 208 * @return volts value 209 */ 210 double getVoltsValue(ActionEnvironment& environment); 211 212 /** 213 * Verifies the value written to VOUT_COMMAND. Reads the current value of 214 * VOUT_COMMAND and ensures that it matches the value written. 215 * 216 * Throws an exception if the values do not match or a communication error 217 * occurs. 218 * 219 * @param environment action execution environment 220 * @param interface I2C interface to the current device 221 * @param valueWritten linear format volts value written to VOUT_COMMAND 222 */ 223 void verifyWrite(ActionEnvironment& environment, 224 i2c::I2CInterface& interface, uint16_t valueWritten); 225 226 /** 227 * Optional volts value to write. 228 */ 229 const std::optional<double> volts{}; 230 231 /** 232 * Data format of the volts value written to VOUT_COMMAND. 233 */ 234 const pmbus_utils::VoutDataFormat format{}; 235 236 /** 237 * Optional exponent value to use to convert the volts value to linear data 238 * format. 239 */ 240 const std::optional<int8_t> exponent{}; 241 242 /** 243 * Indicates whether write verification will be performed when writing to 244 * VOUT_COMMAND. 245 */ 246 const bool isWriteVerified{false}; 247 }; 248 249 } // namespace phosphor::power::regulators 250