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(const std::string& name, 65 std::vector<std::unique_ptr<Rail>> rails, 66 Services& services, uint8_t bus, 67 uint16_t address, 68 const std::string& driverName = "", 69 size_t instance = 0) : 70 StandardDevice(name, std::move(rails)), 71 bus{bus}, address{address}, driverName{driverName}, instance{instance} 72 { 73 pmbusInterface = services.createPMBus(bus, address, driverName, 74 instance); 75 } 76 77 /** 78 * Returns the I2C bus for the device. 79 * 80 * @return I2C bus 81 */ getBus() const82 uint8_t getBus() const 83 { 84 return bus; 85 } 86 87 /** 88 * Returns the I2C address for the device. 89 * 90 * @return I2C address 91 */ getAddress() const92 uint16_t getAddress() const 93 { 94 return address; 95 } 96 97 /** 98 * Returns the device driver name. 99 * 100 * @return driver name 101 */ getDriverName() const102 const std::string& getDriverName() const 103 { 104 return driverName; 105 } 106 107 /** 108 * Returns the chip instance number. 109 * 110 * @return chip instance 111 */ getInstance() const112 size_t getInstance() const 113 { 114 return instance; 115 } 116 117 /** 118 * Returns interface to the PMBus information that is provided by the device 119 * driver in sysfs. 120 * 121 * @return PMBus interface object 122 */ getPMBusInterface()123 pmbus::PMBusBase& getPMBusInterface() 124 { 125 return *pmbusInterface; 126 } 127 128 /** @copydoc PowerSequencerDevice::getGPIOValues() */ 129 virtual std::vector<int> getGPIOValues(Services& services) override; 130 131 /** @copydoc PowerSequencerDevice::getStatusWord() */ 132 virtual uint16_t getStatusWord(uint8_t page) override; 133 134 /** @copydoc PowerSequencerDevice::getStatusVout() */ 135 virtual uint8_t getStatusVout(uint8_t page) override; 136 137 /** @copydoc PowerSequencerDevice::getReadVout() */ 138 virtual double getReadVout(uint8_t page) override; 139 140 /** @copydoc PowerSequencerDevice::getVoutUVFaultLimit() */ 141 virtual double getVoutUVFaultLimit(uint8_t page) override; 142 143 /** 144 * Returns map from PMBus PAGE numbers to sysfs hwmon file numbers. 145 * 146 * Throws an exception if an error occurs trying to build the map. 147 * 148 * @return page to file number map 149 */ getPageToFileNumberMap()150 const std::map<uint8_t, unsigned int>& getPageToFileNumberMap() 151 { 152 if (pageToFileNumber.empty()) 153 { 154 buildPageToFileNumberMap(); 155 } 156 return pageToFileNumber; 157 } 158 159 /** 160 * Returns the hwmon file number that corresponds to the specified PMBus 161 * PAGE number. 162 * 163 * Throws an exception if a file number was not found for the specified PAGE 164 * number. 165 * 166 * @param page PMBus PAGE number 167 * @return hwmon file number 168 */ 169 unsigned int getFileNumber(uint8_t page); 170 171 protected: 172 /** @copydoc StandardDevice::prepareForPgoodFaultDetection() */ prepareForPgoodFaultDetection(Services & services)173 virtual void prepareForPgoodFaultDetection(Services& services) override 174 { 175 // Rebuild PMBus PAGE to hwmon file number map 176 buildPageToFileNumberMap(); 177 178 // Call parent class method to do any actions defined there 179 StandardDevice::prepareForPgoodFaultDetection(services); 180 } 181 182 /** 183 * Build mapping from PMBus PAGE numbers to the hwmon file numbers in 184 * sysfs. 185 * 186 * hwmon file names have the format: 187 * <type><number>_<item> 188 * 189 * The <number> is not the PMBus PAGE number. The PMBus PAGE is determined 190 * by reading the contents of the <type><number>_label file. 191 * 192 * If the map is not empty, it is cleared and rebuilt. This is necessary 193 * over time because power devices may have been added or removed. 194 * 195 * Throws an exception if an error occurs trying to build the map. 196 */ 197 virtual void buildPageToFileNumberMap(); 198 199 /** 200 * Returns whether the specified sysfs hwmon file is a voltage label file. 201 * 202 * If it is a label file, the hwmon file number is obtained from the file 203 * name and returned. 204 * 205 * @param fileName file within the sysfs hwmon directory 206 * @param fileNumber the hwmon file number is stored in this output 207 * parameter if this is a label file 208 * @return true if specified file is a voltage label file, false otherwise 209 */ 210 virtual bool isLabelFile(const std::string& fileName, 211 unsigned int& fileNumber); 212 213 /** 214 * Reads the specified voltage label file to obtain the associated PMBus 215 * PAGE number. 216 * 217 * The returned optional variable will have no value if the PMBus PAGE 218 * number could not be obtained due to an error. 219 * 220 * @param fileName voltage label file within the sysfs hwmon directory 221 * @return PMBus page number 222 */ 223 virtual std::optional<uint8_t> 224 readPageFromLabelFile(const std::string& fileName); 225 226 /** 227 * I2C bus for the device. 228 */ 229 uint8_t bus; 230 231 /** 232 * I2C address for the device. 233 */ 234 uint16_t address; 235 236 /** 237 * Device driver name. 238 */ 239 std::string driverName; 240 241 /** 242 * Chip instance number. 243 */ 244 size_t instance; 245 246 /** 247 * Interface to the PMBus information that is provided by the device driver 248 * in sysfs. 249 */ 250 std::unique_ptr<pmbus::PMBusBase> pmbusInterface; 251 252 /** 253 * Map from PMBus PAGE numbers to sysfs hwmon file numbers. 254 */ 255 std::map<uint8_t, unsigned int> pageToFileNumber; 256 }; 257 258 } // namespace phosphor::power::sequencer 259