1 #pragma once
2 
3 #include <experimental/filesystem>
4 #include <string>
5 #include <vector>
6 
7 namespace witherspoon
8 {
9 namespace pmbus
10 {
11 
12 namespace fs = std::experimental::filesystem;
13 
14 // The file name Linux uses to capture the STATUS_WORD from pmbus.
15 constexpr auto STATUS_WORD = "status0";
16 
17 // The file name Linux uses to capture the STATUS_INPUT from pmbus.
18 constexpr auto STATUS_INPUT = "status0_input";
19 
20 // Voltage out status.
21 // Overvoltage fault or warning, Undervoltage fault or warning, maximum or
22 // minimum warning, ....
23 // Uses Page substitution
24 constexpr auto STATUS_VOUT = "statusP_vout";
25 
26 // Current output status bits.
27 constexpr auto STATUS_IOUT = "status0_iout";
28 
29 // Manufacturing specific status bits
30 constexpr auto STATUS_MFR = "status0_mfr";
31 
32 namespace status_word
33 {
34 constexpr auto VOUT_FAULT = 0x8000;
35 
36 // The IBM CFF power supply driver does map this bit to power1_alarm in the
37 // hwmon space, but since the other bits that need to be checked do not have
38 // a similar mapping, the code will just read STATUS_WORD and use bit masking
39 // to see if the INPUT FAULT OR WARNING bit is on.
40 constexpr auto INPUT_FAULT_WARN = 0x2000;
41 
42 // The bit mask representing the POWER_GOOD Negated bit of the STATUS_WORD.
43 constexpr auto POWER_GOOD_NEGATED = 0x0800;
44 
45 // The bit mask representing the UNITI_IS_OFF bit of the STATUS_WORD.
46 constexpr auto UNIT_IS_OFF = 0x0040;
47 
48 // The IBM CFF power supply driver does map this bit to in1_alarm, however,
49 // since a number of the other bits are not mapped that way for STATUS_WORD,
50 // this code will just read the entire STATUS_WORD and use bit masking to find
51 // out if that fault is on.
52 constexpr auto VIN_UV_FAULT = 0x0008;
53 
54 }
55 
56 /**
57  * If the access should be done in the base
58  * device directory, the hwmon directory, the
59  * pmbus debug directory, or the device debug
60  * directory.
61  */
62 enum class Type
63 {
64     Base,
65     Hwmon,
66     Debug,
67     DeviceDebug
68 };
69 
70 /**
71  * @class PMBus
72  *
73  * This class is an interface to communicating with PMBus devices
74  * by reading and writing sysfs files.
75  *
76  * Based on the Type parameter, the accesses can either be done
77  * in the base device directory (the one passed into the constructor),
78  * or in the hwmon directory for the device.
79  */
80 class PMBus
81 {
82     public:
83 
84         PMBus() = delete;
85         ~PMBus() = default;
86         PMBus(const PMBus&) = default;
87         PMBus& operator=(const PMBus&) = default;
88         PMBus(PMBus&&) = default;
89         PMBus& operator=(PMBus&&) = default;
90 
91         /**
92          * Constructor
93          *
94          * @param[in] path - path to the sysfs directory
95          */
96         PMBus(const std::string& path) :
97             basePath(path)
98         {
99             findHwmonDir();
100         }
101 
102         /**
103          * Constructor
104          *
105          * This version is required when DeviceDebug
106          * access will be used.
107          *
108          * @param[in] path - path to the sysfs directory
109          * @param[in] driverName - the device driver name
110          * @param[in] instance - chip instance number
111          */
112         PMBus(const std::string& path,
113               const std::string& driverName,
114               size_t instance) :
115             basePath(path),
116             driverName(driverName),
117             instance(instance)
118         {
119             findHwmonDir();
120         }
121 
122         /**
123          * Reads a file in sysfs that represents a single bit,
124          * therefore doing a PMBus read.
125          *
126          * @param[in] name - path concatenated to
127          *                   basePath to read
128          * @param[in] type - Path type
129          *
130          * @return bool - false if result was 0, else true
131          */
132         bool readBit(const std::string& name, Type type);
133 
134         /**
135          * Reads a file in sysfs that represents a single bit,
136          * where the page number passed in is substituted
137          * into the name in place of the 'P' character in it.
138          *
139          * @param[in] name - path concatenated to
140          *                   basePath to read
141          * @param[in] page - page number
142          * @param[in] type - Path type
143          *
144          * @return bool - false if result was 0, else true
145          */
146         bool readBitInPage(const std::string& name,
147                            size_t page,
148                            Type type);
149         /**
150          * Read byte(s) from file in sysfs.
151          *
152          * @param[in] name   - path concatenated to basePath to read
153          * @param[in] type   - Path type
154          *
155          * @return uint64_t - Up to 8 bytes of data read from file.
156          */
157         uint64_t read(const std::string& name, Type type);
158 
159         /**
160          * Writes an integer value to the file, therefore doing
161          * a PMBus write.
162          *
163          * @param[in] name - path concatenated to
164          *                   basePath to write
165          * @param[in] value - the value to write
166          * @param[in] type - Path type
167          */
168         void write(const std::string& name, int value, Type type);
169 
170         /**
171          * Returns the sysfs base path of this device
172          */
173         inline const auto& path() const
174         {
175             return basePath;
176         }
177 
178         /**
179          * Replaces the 'P' in the string passed in with
180          * the page number passed in.
181          *
182          * For example:
183          *   insertPageNum("inP_enable", 42)
184          *   returns "in42_enable"
185          *
186          * @param[in] templateName - the name string, with a 'P' in it
187          * @param[in] page - the page number to insert where the P was
188          *
189          * @return string - the new string with the page number in it
190          */
191         static std::string insertPageNum(const std::string& templateName,
192                                          size_t page);
193 
194         /**
195          * Finds the path relative to basePath to the hwmon directory
196          * for the device and stores it in hwmonRelPath.
197          */
198         void findHwmonDir();
199 
200         /**
201          * Returns the path to use for the passed in type.
202          *
203          * @param[in] type - Path type
204          *
205          * @return fs::path - the full path
206          */
207         fs::path getPath(Type type);
208 
209     private:
210 
211         /**
212          * The sysfs device path
213          */
214         fs::path basePath;
215 
216         /**
217          * The directory name under the basePath hwmon directory
218          */
219         fs::path hwmonDir;
220 
221         /**
222          * The device driver name.  Used for finding the device
223          * debug directory.  Not required if that directory
224          * isn't used.
225          */
226         std::string driverName;
227 
228         /**
229          * The device instance number.
230          *
231          * Used in conjuction with the driver name for finding
232          * the debug directory.  Not required if that directory
233          * isn't used.
234          */
235         size_t instance = 0;
236 
237         /**
238          * The pmbus debug path with status files
239          */
240         const fs::path debugPath = "/sys/kernel/debug/";
241 
242 };
243 
244 }
245 }
246