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