1015e3adeSMatt Spinler #pragma once 2015e3adeSMatt Spinler 3015e3adeSMatt Spinler #include <experimental/filesystem> 4015e3adeSMatt Spinler #include <string> 5015e3adeSMatt Spinler #include <vector> 6015e3adeSMatt Spinler 7015e3adeSMatt Spinler namespace witherspoon 8015e3adeSMatt Spinler { 9015e3adeSMatt Spinler namespace pmbus 10015e3adeSMatt Spinler { 11015e3adeSMatt Spinler 12ff5f339cSBrandon Wyman namespace fs = std::experimental::filesystem; 13ff5f339cSBrandon Wyman 1410295547SBrandon Wyman // The file name Linux uses to capture the STATUS_WORD from pmbus. 15e7e432b4SMatt Spinler constexpr auto STATUS_WORD = "status0"; 1610295547SBrandon Wyman 17253dc9b9SBrandon Wyman // The file name Linux uses to capture the STATUS_INPUT from pmbus. 18253dc9b9SBrandon Wyman constexpr auto STATUS_INPUT = "status0_input"; 19e7e432b4SMatt Spinler 20764c797eSBrandon Wyman // Voltage out status. 21764c797eSBrandon Wyman // Overvoltage fault or warning, Undervoltage fault or warning, maximum or 22764c797eSBrandon Wyman // minimum warning, .... 23e7e432b4SMatt Spinler // Uses Page substitution 24e7e432b4SMatt Spinler constexpr auto STATUS_VOUT = "statusP_vout"; 25e7e432b4SMatt Spinler 26de16d053SMatt Spinler namespace status_vout 27de16d053SMatt Spinler { 28de16d053SMatt Spinler // Mask of bits that are only warnings 29de16d053SMatt Spinler constexpr auto WARNING_MASK = 0x6A; 30de16d053SMatt Spinler } 31de16d053SMatt Spinler 32764c797eSBrandon Wyman // Current output status bits. 33764c797eSBrandon Wyman constexpr auto STATUS_IOUT = "status0_iout"; 34764c797eSBrandon Wyman 35764c797eSBrandon Wyman // Manufacturing specific status bits 36764c797eSBrandon Wyman constexpr auto STATUS_MFR = "status0_mfr"; 37764c797eSBrandon Wyman 3812661f1eSBrandon Wyman // Reports on the status of any fans installed in position 1 and 2. 3912661f1eSBrandon Wyman constexpr auto STATUS_FANS_1_2 = "status0_fans12"; 4012661f1eSBrandon Wyman 4112661f1eSBrandon Wyman // Reports on temperature faults or warnings. Overtemperature fault, 4212661f1eSBrandon Wyman // overtemperature warning, undertemperature warning, undertemperature fault. 4312661f1eSBrandon Wyman constexpr auto STATUS_TEMPERATURE = "status0_temp"; 4412661f1eSBrandon Wyman 45e7e432b4SMatt Spinler namespace status_word 46e7e432b4SMatt Spinler { 47e7e432b4SMatt Spinler constexpr auto VOUT_FAULT = 0x8000; 48764c797eSBrandon Wyman 49764c797eSBrandon Wyman // The IBM CFF power supply driver does map this bit to power1_alarm in the 50764c797eSBrandon Wyman // hwmon space, but since the other bits that need to be checked do not have 51764c797eSBrandon Wyman // a similar mapping, the code will just read STATUS_WORD and use bit masking 52764c797eSBrandon Wyman // to see if the INPUT FAULT OR WARNING bit is on. 53764c797eSBrandon Wyman constexpr auto INPUT_FAULT_WARN = 0x2000; 54764c797eSBrandon Wyman 55764c797eSBrandon Wyman // The bit mask representing the POWER_GOOD Negated bit of the STATUS_WORD. 56764c797eSBrandon Wyman constexpr auto POWER_GOOD_NEGATED = 0x0800; 57764c797eSBrandon Wyman 5812661f1eSBrandon Wyman // The bit mask representing the FAN FAULT or WARNING bit of the STATUS_WORD. 5912661f1eSBrandon Wyman // Bit 2 of the high byte of STATUS_WORD. 6012661f1eSBrandon Wyman constexpr auto FAN_FAULT = 0x0400; 6112661f1eSBrandon Wyman 62764c797eSBrandon Wyman // The bit mask representing the UNITI_IS_OFF bit of the STATUS_WORD. 63764c797eSBrandon Wyman constexpr auto UNIT_IS_OFF = 0x0040; 64764c797eSBrandon Wyman 65ab05c079SBrandon Wyman // Bit 5 of the STATUS_BYTE, or lower byte of STATUS_WORD is used to indicate 66ab05c079SBrandon Wyman // an output overvoltage fault. 67ab05c079SBrandon Wyman constexpr auto VOUT_OV_FAULT = 0x0020; 68ab05c079SBrandon Wyman 69b165c251SBrandon Wyman // The bit mask representing that an output overcurrent fault has occurred. 70b165c251SBrandon Wyman constexpr auto IOUT_OC_FAULT = 0x0010; 71b165c251SBrandon Wyman 72764c797eSBrandon Wyman // The IBM CFF power supply driver does map this bit to in1_alarm, however, 73764c797eSBrandon Wyman // since a number of the other bits are not mapped that way for STATUS_WORD, 74764c797eSBrandon Wyman // this code will just read the entire STATUS_WORD and use bit masking to find 75764c797eSBrandon Wyman // out if that fault is on. 76764c797eSBrandon Wyman constexpr auto VIN_UV_FAULT = 0x0008; 77764c797eSBrandon Wyman 78875b363cSBrandon Wyman // The bit mask representing the TEMPERATURE FAULT or WARNING bit of the 79875b363cSBrandon Wyman // STATUS_WORD. Bit 2 of the low byte (STATUS_BYTE). 80875b363cSBrandon Wyman constexpr auto TEMPERATURE_FAULT_WARN = 0x0004; 81875b363cSBrandon Wyman 82875b363cSBrandon Wyman } 83875b363cSBrandon Wyman 84875b363cSBrandon Wyman namespace status_temperature 85875b363cSBrandon Wyman { 86875b363cSBrandon Wyman // Overtemperature Fault 87875b363cSBrandon Wyman constexpr auto OT_FAULT = 0x80; 88e7e432b4SMatt Spinler } 89e7e432b4SMatt Spinler 90015e3adeSMatt Spinler /** 914dc4678eSMatt Spinler * Where the access should be done 9257868bc5SMatt Spinler */ 9357868bc5SMatt Spinler enum class Type 9457868bc5SMatt Spinler { 954dc4678eSMatt Spinler Base, // base device directory 964dc4678eSMatt Spinler Hwmon, // hwmon directory 974dc4678eSMatt Spinler Debug, // pmbus debug directory 984dc4678eSMatt Spinler DeviceDebug, // device debug directory 994dc4678eSMatt Spinler HwmonDeviceDebug // hwmon device debug directory 10057868bc5SMatt Spinler }; 10157868bc5SMatt Spinler 10257868bc5SMatt Spinler /** 103015e3adeSMatt Spinler * @class PMBus 104015e3adeSMatt Spinler * 105015e3adeSMatt Spinler * This class is an interface to communicating with PMBus devices 106015e3adeSMatt Spinler * by reading and writing sysfs files. 10757868bc5SMatt Spinler * 10857868bc5SMatt Spinler * Based on the Type parameter, the accesses can either be done 10957868bc5SMatt Spinler * in the base device directory (the one passed into the constructor), 11057868bc5SMatt Spinler * or in the hwmon directory for the device. 111015e3adeSMatt Spinler */ 112015e3adeSMatt Spinler class PMBus 113015e3adeSMatt Spinler { 114015e3adeSMatt Spinler public: 115015e3adeSMatt Spinler 116015e3adeSMatt Spinler PMBus() = delete; 117015e3adeSMatt Spinler ~PMBus() = default; 118015e3adeSMatt Spinler PMBus(const PMBus&) = default; 119015e3adeSMatt Spinler PMBus& operator=(const PMBus&) = default; 120015e3adeSMatt Spinler PMBus(PMBus&&) = default; 121015e3adeSMatt Spinler PMBus& operator=(PMBus&&) = default; 122015e3adeSMatt Spinler 123015e3adeSMatt Spinler /** 124015e3adeSMatt Spinler * Constructor 125015e3adeSMatt Spinler * 126015e3adeSMatt Spinler * @param[in] path - path to the sysfs directory 127015e3adeSMatt Spinler */ 128015e3adeSMatt Spinler PMBus(const std::string& path) : 129015e3adeSMatt Spinler basePath(path) 130015e3adeSMatt Spinler { 131ff5f339cSBrandon Wyman findHwmonDir(); 132015e3adeSMatt Spinler } 133015e3adeSMatt Spinler 134015e3adeSMatt Spinler /** 1358f0d953fSMatt Spinler * Constructor 1368f0d953fSMatt Spinler * 1378f0d953fSMatt Spinler * This version is required when DeviceDebug 1388f0d953fSMatt Spinler * access will be used. 1398f0d953fSMatt Spinler * 1408f0d953fSMatt Spinler * @param[in] path - path to the sysfs directory 1418f0d953fSMatt Spinler * @param[in] driverName - the device driver name 1428f0d953fSMatt Spinler * @param[in] instance - chip instance number 1438f0d953fSMatt Spinler */ 1448f0d953fSMatt Spinler PMBus(const std::string& path, 1458f0d953fSMatt Spinler const std::string& driverName, 1468f0d953fSMatt Spinler size_t instance) : 1478f0d953fSMatt Spinler basePath(path), 1488f0d953fSMatt Spinler driverName(driverName), 1498f0d953fSMatt Spinler instance(instance) 1508f0d953fSMatt Spinler { 1518f0d953fSMatt Spinler findHwmonDir(); 1528f0d953fSMatt Spinler } 1538f0d953fSMatt Spinler 1548f0d953fSMatt Spinler /** 155015e3adeSMatt Spinler * Reads a file in sysfs that represents a single bit, 156015e3adeSMatt Spinler * therefore doing a PMBus read. 157015e3adeSMatt Spinler * 158015e3adeSMatt Spinler * @param[in] name - path concatenated to 159015e3adeSMatt Spinler * basePath to read 1608f0d953fSMatt Spinler * @param[in] type - Path type 161015e3adeSMatt Spinler * 162015e3adeSMatt Spinler * @return bool - false if result was 0, else true 163015e3adeSMatt Spinler */ 16457868bc5SMatt Spinler bool readBit(const std::string& name, Type type); 165015e3adeSMatt Spinler 166015e3adeSMatt Spinler /** 167015e3adeSMatt Spinler * Reads a file in sysfs that represents a single bit, 168015e3adeSMatt Spinler * where the page number passed in is substituted 169015e3adeSMatt Spinler * into the name in place of the 'P' character in it. 170015e3adeSMatt Spinler * 171015e3adeSMatt Spinler * @param[in] name - path concatenated to 172015e3adeSMatt Spinler * basePath to read 173015e3adeSMatt Spinler * @param[in] page - page number 1748f0d953fSMatt Spinler * @param[in] type - Path type 175015e3adeSMatt Spinler * 176015e3adeSMatt Spinler * @return bool - false if result was 0, else true 177015e3adeSMatt Spinler */ 178015e3adeSMatt Spinler bool readBitInPage(const std::string& name, 17957868bc5SMatt Spinler size_t page, 18057868bc5SMatt Spinler Type type); 181f855e82aSBrandon Wyman /** 1823b7b38baSBrandon Wyman * Checks if the file for the given name and type exists. 1833b7b38baSBrandon Wyman * 1843b7b38baSBrandon Wyman * @param[in] name - path concatenated to basePath to read 1853b7b38baSBrandon Wyman * @param[in] type - Path type 1863b7b38baSBrandon Wyman * 1873b7b38baSBrandon Wyman * @return bool - True if file exists, false if it does not. 1883b7b38baSBrandon Wyman */ 1893b7b38baSBrandon Wyman bool exists(const std::string& name, Type type); 1903b7b38baSBrandon Wyman 1913b7b38baSBrandon Wyman /** 192f855e82aSBrandon Wyman * Read byte(s) from file in sysfs. 193f855e82aSBrandon Wyman * 194f855e82aSBrandon Wyman * @param[in] name - path concatenated to basePath to read 1958f0d953fSMatt Spinler * @param[in] type - Path type 196f855e82aSBrandon Wyman * 197f855e82aSBrandon Wyman * @return uint64_t - Up to 8 bytes of data read from file. 198f855e82aSBrandon Wyman */ 199f855e82aSBrandon Wyman uint64_t read(const std::string& name, Type type); 200015e3adeSMatt Spinler 201015e3adeSMatt Spinler /** 202fbae7b6cSMatt Spinler * Read a string from file in sysfs. 203fbae7b6cSMatt Spinler * 204fbae7b6cSMatt Spinler * @param[in] name - path concatenated to basePath to read 205fbae7b6cSMatt Spinler * @param[in] type - Path type 206fbae7b6cSMatt Spinler * 207fbae7b6cSMatt Spinler * @return string - The data read from the file. 208fbae7b6cSMatt Spinler */ 209fbae7b6cSMatt Spinler std::string readString(const std::string& name, Type type); 210fbae7b6cSMatt Spinler 211fbae7b6cSMatt Spinler /** 212*fa23e330SMatt Spinler * Read data from a binary file in sysfs. 213*fa23e330SMatt Spinler * 214*fa23e330SMatt Spinler * @param[in] name - path concatenated to basePath to read 215*fa23e330SMatt Spinler * @param[in] type - Path type 216*fa23e330SMatt Spinler * @param[in] length - length of data to read, in bytes 217*fa23e330SMatt Spinler * 218*fa23e330SMatt Spinler * @return vector<uint8_t> - The data read from the file. 219*fa23e330SMatt Spinler */ 220*fa23e330SMatt Spinler std::vector<uint8_t> readBinary(const std::string& name, 221*fa23e330SMatt Spinler Type type, 222*fa23e330SMatt Spinler size_t length); 223*fa23e330SMatt Spinler 224*fa23e330SMatt Spinler /** 225015e3adeSMatt Spinler * Writes an integer value to the file, therefore doing 226015e3adeSMatt Spinler * a PMBus write. 227015e3adeSMatt Spinler * 228015e3adeSMatt Spinler * @param[in] name - path concatenated to 229015e3adeSMatt Spinler * basePath to write 230015e3adeSMatt Spinler * @param[in] value - the value to write 2318f0d953fSMatt Spinler * @param[in] type - Path type 232015e3adeSMatt Spinler */ 23357868bc5SMatt Spinler void write(const std::string& name, int value, Type type); 234015e3adeSMatt Spinler 235015e3adeSMatt Spinler /** 236015e3adeSMatt Spinler * Returns the sysfs base path of this device 237015e3adeSMatt Spinler */ 238015e3adeSMatt Spinler inline const auto& path() const 239015e3adeSMatt Spinler { 240015e3adeSMatt Spinler return basePath; 241015e3adeSMatt Spinler } 242015e3adeSMatt Spinler 243015e3adeSMatt Spinler /** 244015e3adeSMatt Spinler * Replaces the 'P' in the string passed in with 245015e3adeSMatt Spinler * the page number passed in. 246015e3adeSMatt Spinler * 247015e3adeSMatt Spinler * For example: 248015e3adeSMatt Spinler * insertPageNum("inP_enable", 42) 249015e3adeSMatt Spinler * returns "in42_enable" 250015e3adeSMatt Spinler * 251015e3adeSMatt Spinler * @param[in] templateName - the name string, with a 'P' in it 252015e3adeSMatt Spinler * @param[in] page - the page number to insert where the P was 253015e3adeSMatt Spinler * 254015e3adeSMatt Spinler * @return string - the new string with the page number in it 255015e3adeSMatt Spinler */ 256015e3adeSMatt Spinler static std::string insertPageNum(const std::string& templateName, 257015e3adeSMatt Spinler size_t page); 258015e3adeSMatt Spinler 25957868bc5SMatt Spinler /** 26057868bc5SMatt Spinler * Finds the path relative to basePath to the hwmon directory 26157868bc5SMatt Spinler * for the device and stores it in hwmonRelPath. 26257868bc5SMatt Spinler */ 263ff5f339cSBrandon Wyman void findHwmonDir(); 264ff5f339cSBrandon Wyman 265ff5f339cSBrandon Wyman /** 266ff5f339cSBrandon Wyman * Returns the path to use for the passed in type. 267ff5f339cSBrandon Wyman * 2688f0d953fSMatt Spinler * @param[in] type - Path type 269ff5f339cSBrandon Wyman * 2708f0d953fSMatt Spinler * @return fs::path - the full path 271ff5f339cSBrandon Wyman */ 272ff5f339cSBrandon Wyman fs::path getPath(Type type); 27357868bc5SMatt Spinler 274015e3adeSMatt Spinler private: 275015e3adeSMatt Spinler 276015e3adeSMatt Spinler /** 277ba05348fSMatt Spinler * Returns the device name 278ba05348fSMatt Spinler * 279ba05348fSMatt Spinler * This is found in the 'name' file in basePath. 280ba05348fSMatt Spinler * 281ba05348fSMatt Spinler * @return string - the device name 282ba05348fSMatt Spinler */ 283ba05348fSMatt Spinler std::string getDeviceName(); 284ba05348fSMatt Spinler 285ba05348fSMatt Spinler /** 286015e3adeSMatt Spinler * The sysfs device path 287015e3adeSMatt Spinler */ 288ff5f339cSBrandon Wyman fs::path basePath; 289015e3adeSMatt Spinler 29057868bc5SMatt Spinler /** 291ff5f339cSBrandon Wyman * The directory name under the basePath hwmon directory 29257868bc5SMatt Spinler */ 293ff5f339cSBrandon Wyman fs::path hwmonDir; 294ff5f339cSBrandon Wyman 295ff5f339cSBrandon Wyman /** 2968f0d953fSMatt Spinler * The device driver name. Used for finding the device 2978f0d953fSMatt Spinler * debug directory. Not required if that directory 2988f0d953fSMatt Spinler * isn't used. 2998f0d953fSMatt Spinler */ 3008f0d953fSMatt Spinler std::string driverName; 3018f0d953fSMatt Spinler 3028f0d953fSMatt Spinler /** 3038f0d953fSMatt Spinler * The device instance number. 3048f0d953fSMatt Spinler * 3058f0d953fSMatt Spinler * Used in conjuction with the driver name for finding 3068f0d953fSMatt Spinler * the debug directory. Not required if that directory 3078f0d953fSMatt Spinler * isn't used. 3088f0d953fSMatt Spinler */ 3098f0d953fSMatt Spinler size_t instance = 0; 3108f0d953fSMatt Spinler 3118f0d953fSMatt Spinler /** 312ff5f339cSBrandon Wyman * The pmbus debug path with status files 313ff5f339cSBrandon Wyman */ 3148f0d953fSMatt Spinler const fs::path debugPath = "/sys/kernel/debug/"; 31557868bc5SMatt Spinler 316015e3adeSMatt Spinler }; 317015e3adeSMatt Spinler 318015e3adeSMatt Spinler } 319015e3adeSMatt Spinler } 320