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