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 */ 90 explicit PMBusWriteVoutCommandAction(std::optional<double> volts, 91 pmbus_utils::VoutDataFormat format, 92 std::optional<int8_t> exponent, 93 bool isVerified) : 94 volts{volts}, 95 format{format}, exponent{exponent}, isWriteVerified{isVerified} 96 { 97 // Currently only linear format is supported 98 if (format != pmbus_utils::VoutDataFormat::linear) 99 { 100 throw std::invalid_argument{"Unsupported data format specified"}; 101 } 102 } 103 104 /** 105 * Executes this action. 106 * 107 * Writes a volts value to VOUT_COMMAND using the I2C interface. 108 * 109 * If a volts value was specified in the constructor, that value will be 110 * used. Otherwise the volts value will be obtained from the 111 * ActionEnvironment. 112 * 113 * The data format is specified in the constructor. Currently only the 114 * linear format is supported. 115 * 116 * An exponent value is required to convert the volts value to linear 117 * format. If an exponent value was specified in the constructor, that 118 * value will be used. Otherwise the exponent value will be obtained from 119 * the VOUT_MODE command. 120 * 121 * Write verification will be performed if specified in the constructor. 122 * 123 * The device is obtained from the ActionEnvironment. 124 * 125 * Throws an exception if an error occurs. 126 * 127 * @param environment action execution environment 128 * @return true 129 */ 130 virtual bool execute(ActionEnvironment& environment) override; 131 132 /** 133 * Returns the optional exponent value used to convert the volts value to 134 * linear data format. 135 * 136 * @return optional exponent value 137 */ 138 std::optional<int8_t> getExponent() const 139 { 140 return exponent; 141 } 142 143 /** 144 * Returns the data format of the value written to VOUT_COMMAND. 145 * 146 * @return data format 147 */ 148 pmbus_utils::VoutDataFormat getFormat() const 149 { 150 return format; 151 } 152 153 /** 154 * Returns the optional volts value to write to VOUT_COMMAND. 155 * 156 * @return optional volts value 157 */ 158 std::optional<double> getVolts() const 159 { 160 return volts; 161 } 162 163 /** 164 * Returns whether write verification will be performed when writing to 165 * VOUT_COMMAND. 166 * 167 * @return true if write verification will be performed, false otherwise 168 */ 169 bool isVerified() const 170 { 171 return isWriteVerified; 172 } 173 174 /** 175 * Returns a string description of this action. 176 * 177 * @return description of action 178 */ 179 virtual std::string toString() const override; 180 181 private: 182 /** 183 * Gets the exponent value to use to convert the volts value to linear data 184 * format. 185 * 186 * If an exponent value is defined for this action, that value is returned. 187 * Otherwise VOUT_MODE is read from the current device to obtain the 188 * exponent value. 189 * 190 * Throws an exception if an error occurs. 191 * 192 * @param environment action execution environment 193 * @param interface I2C interface to the current device 194 * @return exponent value 195 */ 196 int8_t getExponentValue(ActionEnvironment& environment, 197 i2c::I2CInterface& interface); 198 199 /** 200 * Gets the volts value to write to VOUT_COMMAND. 201 * 202 * If a volts value is defined for this action, that value is returned. 203 * Otherwise the volts value is obtained from the specified 204 * ActionEnvironment. 205 * 206 * Throws an exception if no volts value is defined. 207 * 208 * @param environment action execution environment 209 * @return volts value 210 */ 211 double getVoltsValue(ActionEnvironment& environment); 212 213 /** 214 * Verifies the value written to VOUT_COMMAND. Reads the current value of 215 * VOUT_COMMAND and ensures that it matches the value written. 216 * 217 * Throws an exception if the values do not match or a communication error 218 * occurs. 219 * 220 * @param environment action execution environment 221 * @param interface I2C interface to the current device 222 * @param valueWritten linear format volts value written to VOUT_COMMAND 223 */ 224 void verifyWrite(ActionEnvironment& environment, 225 i2c::I2CInterface& interface, uint16_t valueWritten); 226 227 /** 228 * Optional volts value to write. 229 */ 230 const std::optional<double> volts{}; 231 232 /** 233 * Data format of the volts value written to VOUT_COMMAND. 234 */ 235 const pmbus_utils::VoutDataFormat format{}; 236 237 /** 238 * Optional exponent value to use to convert the volts value to linear data 239 * format. 240 */ 241 const std::optional<int8_t> exponent{}; 242 243 /** 244 * Indicates whether write verification will be performed when writing to 245 * VOUT_COMMAND. 246 */ 247 const bool isWriteVerified{false}; 248 }; 249 250 } // namespace phosphor::power::regulators 251