1 /** 2 * Copyright © 2024 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 "pmbus.hpp" 19 #include "rail.hpp" 20 #include "services.hpp" 21 #include "standard_device.hpp" 22 23 #include <stddef.h> // for size_t 24 25 #include <cstdint> 26 #include <map> 27 #include <memory> 28 #include <optional> 29 #include <string> 30 #include <utility> 31 #include <vector> 32 33 namespace phosphor::power::sequencer 34 { 35 36 /** 37 * @class PMBusDriverDevice 38 * 39 * StandardDevice sub-class for power sequencer devices that are bound to a 40 * PMBus device driver. 41 */ 42 class PMBusDriverDevice : public StandardDevice 43 { 44 public: 45 // Specify which compiler-generated methods we want 46 PMBusDriverDevice() = delete; 47 PMBusDriverDevice(const PMBusDriverDevice&) = delete; 48 PMBusDriverDevice(PMBusDriverDevice&&) = delete; 49 PMBusDriverDevice& operator=(const PMBusDriverDevice&) = delete; 50 PMBusDriverDevice& operator=(PMBusDriverDevice&&) = delete; 51 virtual ~PMBusDriverDevice() = default; 52 53 /** 54 * Constructor. 55 * 56 * @param name Device name 57 * @param rails Voltage rails that are enabled and monitored by this device 58 * @param services System services like hardware presence and the journal 59 * @param bus I2C bus for the device 60 * @param address I2C address for the device 61 * @param driverName Device driver name 62 * @param instance Chip instance number 63 */ PMBusDriverDevice(const std::string & name,std::vector<std::unique_ptr<Rail>> rails,Services & services,uint8_t bus,uint16_t address,const std::string & driverName="",size_t instance=0)64 explicit PMBusDriverDevice( 65 const std::string& name, std::vector<std::unique_ptr<Rail>> rails, 66 Services& services, uint8_t bus, uint16_t address, 67 const std::string& driverName = "", size_t instance = 0) : 68 StandardDevice(name, std::move(rails)), bus{bus}, address{address}, 69 driverName{driverName}, instance{instance} 70 { 71 pmbusInterface = 72 services.createPMBus(bus, address, driverName, instance); 73 } 74 75 /** 76 * Returns the I2C bus for the device. 77 * 78 * @return I2C bus 79 */ getBus() const80 uint8_t getBus() const 81 { 82 return bus; 83 } 84 85 /** 86 * Returns the I2C address for the device. 87 * 88 * @return I2C address 89 */ getAddress() const90 uint16_t getAddress() const 91 { 92 return address; 93 } 94 95 /** 96 * Returns the device driver name. 97 * 98 * @return driver name 99 */ getDriverName() const100 const std::string& getDriverName() const 101 { 102 return driverName; 103 } 104 105 /** 106 * Returns the chip instance number. 107 * 108 * @return chip instance 109 */ getInstance() const110 size_t getInstance() const 111 { 112 return instance; 113 } 114 115 /** 116 * Returns interface to the PMBus information that is provided by the device 117 * driver in sysfs. 118 * 119 * @return PMBus interface object 120 */ getPMBusInterface()121 pmbus::PMBusBase& getPMBusInterface() 122 { 123 return *pmbusInterface; 124 } 125 126 /** @copydoc PowerSequencerDevice::getGPIOValues() */ 127 virtual std::vector<int> getGPIOValues(Services& services) override; 128 129 /** @copydoc PowerSequencerDevice::getStatusWord() */ 130 virtual uint16_t getStatusWord(uint8_t page) override; 131 132 /** @copydoc PowerSequencerDevice::getStatusVout() */ 133 virtual uint8_t getStatusVout(uint8_t page) override; 134 135 /** @copydoc PowerSequencerDevice::getReadVout() */ 136 virtual double getReadVout(uint8_t page) override; 137 138 /** @copydoc PowerSequencerDevice::getVoutUVFaultLimit() */ 139 virtual double getVoutUVFaultLimit(uint8_t page) override; 140 141 /** 142 * Returns map from PMBus PAGE numbers to sysfs hwmon file numbers. 143 * 144 * Throws an exception if an error occurs trying to build the map. 145 * 146 * @return page to file number map 147 */ getPageToFileNumberMap()148 const std::map<uint8_t, unsigned int>& getPageToFileNumberMap() 149 { 150 if (pageToFileNumber.empty()) 151 { 152 buildPageToFileNumberMap(); 153 } 154 return pageToFileNumber; 155 } 156 157 /** 158 * Returns the hwmon file number that corresponds to the specified PMBus 159 * PAGE number. 160 * 161 * Throws an exception if a file number was not found for the specified PAGE 162 * number. 163 * 164 * @param page PMBus PAGE number 165 * @return hwmon file number 166 */ 167 unsigned int getFileNumber(uint8_t page); 168 169 protected: 170 /** @copydoc StandardDevice::prepareForPgoodFaultDetection() */ prepareForPgoodFaultDetection(Services & services)171 virtual void prepareForPgoodFaultDetection(Services& services) override 172 { 173 // Rebuild PMBus PAGE to hwmon file number map 174 buildPageToFileNumberMap(); 175 176 // Call parent class method to do any actions defined there 177 StandardDevice::prepareForPgoodFaultDetection(services); 178 } 179 180 /** 181 * Build mapping from PMBus PAGE numbers to the hwmon file numbers in 182 * sysfs. 183 * 184 * hwmon file names have the format: 185 * <type><number>_<item> 186 * 187 * The <number> is not the PMBus PAGE number. The PMBus PAGE is determined 188 * by reading the contents of the <type><number>_label file. 189 * 190 * If the map is not empty, it is cleared and rebuilt. This is necessary 191 * over time because power devices may have been added or removed. 192 * 193 * Throws an exception if an error occurs trying to build the map. 194 */ 195 virtual void buildPageToFileNumberMap(); 196 197 /** 198 * Returns whether the specified sysfs hwmon file is a voltage label file. 199 * 200 * If it is a label file, the hwmon file number is obtained from the file 201 * name and returned. 202 * 203 * @param fileName file within the sysfs hwmon directory 204 * @param fileNumber the hwmon file number is stored in this output 205 * parameter if this is a label file 206 * @return true if specified file is a voltage label file, false otherwise 207 */ 208 virtual bool isLabelFile(const std::string& fileName, 209 unsigned int& fileNumber); 210 211 /** 212 * Reads the specified voltage label file to obtain the associated PMBus 213 * PAGE number. 214 * 215 * The returned optional variable will have no value if the PMBus PAGE 216 * number could not be obtained due to an error. 217 * 218 * @param fileName voltage label file within the sysfs hwmon directory 219 * @return PMBus page number 220 */ 221 virtual std::optional<uint8_t> 222 readPageFromLabelFile(const std::string& fileName); 223 224 /** 225 * I2C bus for the device. 226 */ 227 uint8_t bus; 228 229 /** 230 * I2C address for the device. 231 */ 232 uint16_t address; 233 234 /** 235 * Device driver name. 236 */ 237 std::string driverName; 238 239 /** 240 * Chip instance number. 241 */ 242 size_t instance; 243 244 /** 245 * Interface to the PMBus information that is provided by the device driver 246 * in sysfs. 247 */ 248 std::unique_ptr<pmbus::PMBusBase> pmbusInterface; 249 250 /** 251 * Map from PMBus PAGE numbers to sysfs hwmon file numbers. 252 */ 253 std::map<uint8_t, unsigned int> pageToFileNumber; 254 }; 255 256 } // namespace phosphor::power::sequencer 257