1015e3adeSMatt Spinler /**
2015e3adeSMatt Spinler * Copyright © 2017 IBM Corporation
3015e3adeSMatt Spinler *
4015e3adeSMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License");
5015e3adeSMatt Spinler * you may not use this file except in compliance with the License.
6015e3adeSMatt Spinler * You may obtain a copy of the License at
7015e3adeSMatt Spinler *
8015e3adeSMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0
9015e3adeSMatt Spinler *
10015e3adeSMatt Spinler * Unless required by applicable law or agreed to in writing, software
11015e3adeSMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS,
12015e3adeSMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13015e3adeSMatt Spinler * See the License for the specific language governing permissions and
14015e3adeSMatt Spinler * limitations under the License.
15015e3adeSMatt Spinler */
16f0f02b9aSMatt Spinler #include "pmbus.hpp"
17f0f02b9aSMatt Spinler
18015e3adeSMatt Spinler #include <phosphor-logging/elog-errors.hpp>
19f0f02b9aSMatt Spinler #include <phosphor-logging/elog.hpp>
20ceacf941SMatt Spinler #include <xyz/openbmc_project/Common/Device/error.hpp>
21f0f02b9aSMatt Spinler #include <xyz/openbmc_project/Common/error.hpp>
22015e3adeSMatt Spinler
23d1bc4cecSBrandon Wyman #include <filesystem>
24d1bc4cecSBrandon Wyman #include <fstream>
25d1bc4cecSBrandon Wyman
26ab093328SLei YU namespace phosphor
27015e3adeSMatt Spinler {
28015e3adeSMatt Spinler namespace pmbus
29015e3adeSMatt Spinler {
30015e3adeSMatt Spinler
31015e3adeSMatt Spinler using namespace phosphor::logging;
32015e3adeSMatt Spinler using namespace sdbusplus::xyz::openbmc_project::Common::Error;
33ceacf941SMatt Spinler using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
349c7897ceSBrandon Wyman namespace fs = std::filesystem;
35015e3adeSMatt Spinler
36fa23e330SMatt Spinler /**
37fa23e330SMatt Spinler * @brief Helper to close a file handle
38fa23e330SMatt Spinler */
39fa23e330SMatt Spinler struct FileCloser
40fa23e330SMatt Spinler {
operator ()phosphor::pmbus::FileCloser41fa23e330SMatt Spinler void operator()(FILE* fp) const
42fa23e330SMatt Spinler {
43fa23e330SMatt Spinler fclose(fp);
44fa23e330SMatt Spinler }
45fa23e330SMatt Spinler };
46fa23e330SMatt Spinler
insertPageNum(const std::string & templateName,size_t page)47f0f02b9aSMatt Spinler std::string PMBus::insertPageNum(const std::string& templateName, size_t page)
48015e3adeSMatt Spinler {
49015e3adeSMatt Spinler auto name = templateName;
50015e3adeSMatt Spinler
51015e3adeSMatt Spinler // insert the page where the P was
52015e3adeSMatt Spinler auto pos = name.find('P');
53015e3adeSMatt Spinler if (pos != std::string::npos)
54015e3adeSMatt Spinler {
55015e3adeSMatt Spinler name.replace(pos, 1, std::to_string(page));
56015e3adeSMatt Spinler }
57015e3adeSMatt Spinler
58015e3adeSMatt Spinler return name;
59015e3adeSMatt Spinler }
60015e3adeSMatt Spinler
getPath(Type type)61ff5f339cSBrandon Wyman fs::path PMBus::getPath(Type type)
62ff5f339cSBrandon Wyman {
63ff5f339cSBrandon Wyman switch (type)
64ff5f339cSBrandon Wyman {
65ff5f339cSBrandon Wyman default:
66ff5f339cSBrandon Wyman /* fall through */
67ff5f339cSBrandon Wyman case Type::Base:
68ff5f339cSBrandon Wyman return basePath;
69ff5f339cSBrandon Wyman break;
70ff5f339cSBrandon Wyman case Type::Hwmon:
71ff5f339cSBrandon Wyman return basePath / "hwmon" / hwmonDir;
72ff5f339cSBrandon Wyman break;
73ff5f339cSBrandon Wyman case Type::Debug:
748f0d953fSMatt Spinler return debugPath / "pmbus" / hwmonDir;
758f0d953fSMatt Spinler break;
768f0d953fSMatt Spinler case Type::DeviceDebug:
774dc4678eSMatt Spinler {
788f0d953fSMatt Spinler auto dir = driverName + "." + std::to_string(instance);
798f0d953fSMatt Spinler return debugPath / dir;
80ff5f339cSBrandon Wyman break;
81ff5f339cSBrandon Wyman }
824dc4678eSMatt Spinler case Type::HwmonDeviceDebug:
834dc4678eSMatt Spinler return debugPath / "pmbus" / hwmonDir / getDeviceName();
844dc4678eSMatt Spinler break;
854dc4678eSMatt Spinler }
86ff5f339cSBrandon Wyman }
87ff5f339cSBrandon Wyman
getDeviceName()88ba05348fSMatt Spinler std::string PMBus::getDeviceName()
89ba05348fSMatt Spinler {
90ba05348fSMatt Spinler std::string name;
91ba05348fSMatt Spinler std::ifstream file;
92ba05348fSMatt Spinler auto path = basePath / "name";
93ba05348fSMatt Spinler
94f0f02b9aSMatt Spinler file.exceptions(std::ifstream::failbit | std::ifstream::badbit |
95ba05348fSMatt Spinler std::ifstream::eofbit);
96ba05348fSMatt Spinler try
97ba05348fSMatt Spinler {
98ba05348fSMatt Spinler file.open(path);
99ba05348fSMatt Spinler file >> name;
100ba05348fSMatt Spinler }
101c1d4de5eSPatrick Williams catch (const std::exception& e)
102ba05348fSMatt Spinler {
1036a3fd2c2SJay Meyer log<level::ERR>((std::string("Unable to read PMBus device name "
1046a3fd2c2SJay Meyer "PATH=") +
1056a3fd2c2SJay Meyer path.string())
1066a3fd2c2SJay Meyer .c_str());
107ba05348fSMatt Spinler }
108ba05348fSMatt Spinler
109ba05348fSMatt Spinler return name;
110ba05348fSMatt Spinler }
111ba05348fSMatt Spinler
readBitInPage(const std::string & name,size_t page,Type type)112f0f02b9aSMatt Spinler bool PMBus::readBitInPage(const std::string& name, size_t page, Type type)
113015e3adeSMatt Spinler {
114015e3adeSMatt Spinler auto pagedBit = insertPageNum(name, page);
11557868bc5SMatt Spinler return readBit(pagedBit, type);
116015e3adeSMatt Spinler }
117015e3adeSMatt Spinler
readBit(const std::string & name,Type type)11857868bc5SMatt Spinler bool PMBus::readBit(const std::string& name, Type type)
119015e3adeSMatt Spinler {
120015e3adeSMatt Spinler unsigned long int value = 0;
121015e3adeSMatt Spinler std::ifstream file;
122ff5f339cSBrandon Wyman fs::path path = getPath(type);
12357868bc5SMatt Spinler
124015e3adeSMatt Spinler path /= name;
125015e3adeSMatt Spinler
126f0f02b9aSMatt Spinler file.exceptions(std::ifstream::failbit | std::ifstream::badbit |
127015e3adeSMatt Spinler std::ifstream::eofbit);
128015e3adeSMatt Spinler
129015e3adeSMatt Spinler try
130015e3adeSMatt Spinler {
131757ad6a9SJayanth Othayoth char* err = nullptr;
132015e3adeSMatt Spinler std::string val{1, '\0'};
133015e3adeSMatt Spinler
134015e3adeSMatt Spinler file.open(path);
135015e3adeSMatt Spinler file.read(&val[0], 1);
136015e3adeSMatt Spinler
137015e3adeSMatt Spinler value = strtoul(val.c_str(), &err, 10);
138015e3adeSMatt Spinler
139015e3adeSMatt Spinler if (*err)
140015e3adeSMatt Spinler {
1416a3fd2c2SJay Meyer log<level::ERR>((std::string("Invalid character in sysfs file"
1426a3fd2c2SJay Meyer " FILE=") +
1436a3fd2c2SJay Meyer path.string() + std::string(" CONTENTS=") + val)
1446a3fd2c2SJay Meyer .c_str());
145015e3adeSMatt Spinler
146015e3adeSMatt Spinler // Catch below and handle as a read failure
147015e3adeSMatt Spinler elog<InternalFailure>();
148015e3adeSMatt Spinler }
149015e3adeSMatt Spinler }
150c1d4de5eSPatrick Williams catch (const std::exception& e)
151015e3adeSMatt Spinler {
152015e3adeSMatt Spinler auto rc = errno;
153015e3adeSMatt Spinler
154f5402197SPatrick Williams log<level::ERR>(
155f5402197SPatrick Williams (std::string("Failed to read sysfs file "
1566a3fd2c2SJay Meyer "errno=") +
157f5402197SPatrick Williams std::to_string(rc) + std::string(" FILENAME=") + path.string())
1586a3fd2c2SJay Meyer .c_str());
159015e3adeSMatt Spinler
160ceacf941SMatt Spinler using metadata = xyz::openbmc_project::Common::Device::ReadFailure;
161ceacf941SMatt Spinler
162f0f02b9aSMatt Spinler elog<ReadFailure>(
163f0f02b9aSMatt Spinler metadata::CALLOUT_ERRNO(rc),
164f0f02b9aSMatt Spinler metadata::CALLOUT_DEVICE_PATH(fs::canonical(basePath).c_str()));
165015e3adeSMatt Spinler }
166015e3adeSMatt Spinler
167015e3adeSMatt Spinler return value != 0;
168015e3adeSMatt Spinler }
169015e3adeSMatt Spinler
exists(const std::string & name,Type type)1703b7b38baSBrandon Wyman bool PMBus::exists(const std::string& name, Type type)
1713b7b38baSBrandon Wyman {
1723b7b38baSBrandon Wyman auto path = getPath(type);
1733b7b38baSBrandon Wyman path /= name;
1743b7b38baSBrandon Wyman return fs::exists(path);
1753b7b38baSBrandon Wyman }
1763b7b38baSBrandon Wyman
read(const std::string & name,Type type,bool errTrace)17732453e9bSBrandon Wyman uint64_t PMBus::read(const std::string& name, Type type, bool errTrace)
178f855e82aSBrandon Wyman {
179f855e82aSBrandon Wyman uint64_t data = 0;
180f855e82aSBrandon Wyman std::ifstream file;
181f855e82aSBrandon Wyman auto path = getPath(type);
182f855e82aSBrandon Wyman path /= name;
183f855e82aSBrandon Wyman
184f0f02b9aSMatt Spinler file.exceptions(std::ifstream::failbit | std::ifstream::badbit |
185f855e82aSBrandon Wyman std::ifstream::eofbit);
186f855e82aSBrandon Wyman
187f855e82aSBrandon Wyman try
188f855e82aSBrandon Wyman {
189f855e82aSBrandon Wyman file.open(path);
190f855e82aSBrandon Wyman file >> std::hex >> data;
191f855e82aSBrandon Wyman }
192c1d4de5eSPatrick Williams catch (const std::exception& e)
193f855e82aSBrandon Wyman {
194f855e82aSBrandon Wyman auto rc = errno;
19532453e9bSBrandon Wyman
19632453e9bSBrandon Wyman if (errTrace)
19732453e9bSBrandon Wyman {
1986a3fd2c2SJay Meyer log<level::ERR>((std::string("Failed to read sysfs file "
1996a3fd2c2SJay Meyer "errno=") +
2006a3fd2c2SJay Meyer std::to_string(rc) + " FILENAME=" + path.string())
2016a3fd2c2SJay Meyer .c_str());
202f855e82aSBrandon Wyman
203ceacf941SMatt Spinler using metadata = xyz::openbmc_project::Common::Device::ReadFailure;
204f855e82aSBrandon Wyman
205f0f02b9aSMatt Spinler elog<ReadFailure>(
206f0f02b9aSMatt Spinler metadata::CALLOUT_ERRNO(rc),
207f0f02b9aSMatt Spinler metadata::CALLOUT_DEVICE_PATH(fs::canonical(basePath).c_str()));
208f855e82aSBrandon Wyman }
20932453e9bSBrandon Wyman else
21032453e9bSBrandon Wyman {
21132453e9bSBrandon Wyman throw ReadFailure();
21232453e9bSBrandon Wyman }
21332453e9bSBrandon Wyman }
214f855e82aSBrandon Wyman
215f855e82aSBrandon Wyman return data;
216f855e82aSBrandon Wyman }
217f855e82aSBrandon Wyman
readString(const std::string & name,Type type)218fbae7b6cSMatt Spinler std::string PMBus::readString(const std::string& name, Type type)
219fbae7b6cSMatt Spinler {
220fbae7b6cSMatt Spinler std::string data;
221fbae7b6cSMatt Spinler std::ifstream file;
222fbae7b6cSMatt Spinler auto path = getPath(type);
223fbae7b6cSMatt Spinler path /= name;
224fbae7b6cSMatt Spinler
225f0f02b9aSMatt Spinler file.exceptions(std::ifstream::failbit | std::ifstream::badbit |
226fbae7b6cSMatt Spinler std::ifstream::eofbit);
227fbae7b6cSMatt Spinler
228fbae7b6cSMatt Spinler try
229fbae7b6cSMatt Spinler {
230fbae7b6cSMatt Spinler file.open(path);
231fbae7b6cSMatt Spinler file >> data;
232fbae7b6cSMatt Spinler }
233c1d4de5eSPatrick Williams catch (const std::exception& e)
234fbae7b6cSMatt Spinler {
235fbae7b6cSMatt Spinler auto rc = errno;
2366a3fd2c2SJay Meyer log<level::ERR>((std::string("Failed to read sysfs file "
2376a3fd2c2SJay Meyer "errno=") +
2386a3fd2c2SJay Meyer std::to_string(rc) + " FILENAME=" + path.string())
2396a3fd2c2SJay Meyer .c_str());
240fbae7b6cSMatt Spinler
241fbae7b6cSMatt Spinler using metadata = xyz::openbmc_project::Common::Device::ReadFailure;
242fbae7b6cSMatt Spinler
243f0f02b9aSMatt Spinler elog<ReadFailure>(
244f0f02b9aSMatt Spinler metadata::CALLOUT_ERRNO(rc),
245f0f02b9aSMatt Spinler metadata::CALLOUT_DEVICE_PATH(fs::canonical(basePath).c_str()));
246fbae7b6cSMatt Spinler }
247fbae7b6cSMatt Spinler
248fbae7b6cSMatt Spinler return data;
249fbae7b6cSMatt Spinler }
250fbae7b6cSMatt Spinler
readBinary(const std::string & name,Type type,size_t length)251f0f02b9aSMatt Spinler std::vector<uint8_t> PMBus::readBinary(const std::string& name, Type type,
252fa23e330SMatt Spinler size_t length)
253fa23e330SMatt Spinler {
254fa23e330SMatt Spinler auto path = getPath(type) / name;
255fa23e330SMatt Spinler
256fa23e330SMatt Spinler // Use C style IO because it's easier to handle telling the difference
257fa23e330SMatt Spinler // between hitting EOF or getting an actual error.
258fa23e330SMatt Spinler std::unique_ptr<FILE, FileCloser> file{fopen(path.c_str(), "rb")};
259fa23e330SMatt Spinler
260fa23e330SMatt Spinler if (file)
261fa23e330SMatt Spinler {
262fa23e330SMatt Spinler std::vector<uint8_t> data(length, 0);
263fa23e330SMatt Spinler
264f5402197SPatrick Williams auto bytes =
265f5402197SPatrick Williams fread(data.data(), sizeof(decltype(data[0])), length, file.get());
266fa23e330SMatt Spinler
267fa23e330SMatt Spinler if (bytes != length)
268fa23e330SMatt Spinler {
269fa23e330SMatt Spinler // If hit EOF, just return the amount of data that was read.
270fa23e330SMatt Spinler if (feof(file.get()))
271fa23e330SMatt Spinler {
272fa23e330SMatt Spinler data.erase(data.begin() + bytes, data.end());
273fa23e330SMatt Spinler }
274fa23e330SMatt Spinler else if (ferror(file.get()))
275fa23e330SMatt Spinler {
276fa23e330SMatt Spinler auto rc = errno;
277f5402197SPatrick Williams log<level::ERR>(
278f5402197SPatrick Williams (std::string("Failed to read sysfs file "
2796a3fd2c2SJay Meyer "errno=") +
280f5402197SPatrick Williams std::to_string(rc) + " FILENAME=" + path.string())
2816a3fd2c2SJay Meyer .c_str());
282f0f02b9aSMatt Spinler using metadata =
283f0f02b9aSMatt Spinler xyz::openbmc_project::Common::Device::ReadFailure;
284fa23e330SMatt Spinler
285fa23e330SMatt Spinler elog<ReadFailure>(metadata::CALLOUT_ERRNO(rc),
286fa23e330SMatt Spinler metadata::CALLOUT_DEVICE_PATH(
287fa23e330SMatt Spinler fs::canonical(basePath).c_str()));
288fa23e330SMatt Spinler }
289fa23e330SMatt Spinler }
290fa23e330SMatt Spinler return data;
291fa23e330SMatt Spinler }
292fa23e330SMatt Spinler
293fa23e330SMatt Spinler return std::vector<uint8_t>{};
294fa23e330SMatt Spinler }
295fa23e330SMatt Spinler
write(const std::string & name,int value,Type type)29657868bc5SMatt Spinler void PMBus::write(const std::string& name, int value, Type type)
297015e3adeSMatt Spinler {
298015e3adeSMatt Spinler std::ofstream file;
299ff5f339cSBrandon Wyman fs::path path = getPath(type);
30057868bc5SMatt Spinler
301015e3adeSMatt Spinler path /= name;
302015e3adeSMatt Spinler
303f0f02b9aSMatt Spinler file.exceptions(std::ofstream::failbit | std::ofstream::badbit |
304015e3adeSMatt Spinler std::ofstream::eofbit);
305015e3adeSMatt Spinler
306015e3adeSMatt Spinler try
307015e3adeSMatt Spinler {
308015e3adeSMatt Spinler file.open(path);
309015e3adeSMatt Spinler file << value;
310015e3adeSMatt Spinler }
311015e3adeSMatt Spinler catch (const std::exception& e)
312015e3adeSMatt Spinler {
313015e3adeSMatt Spinler auto rc = errno;
3146a3fd2c2SJay Meyer log<level::ERR>((std::string("Failed to write sysfs file "
3156a3fd2c2SJay Meyer "errno=") +
3166a3fd2c2SJay Meyer std::to_string(rc) + " FILENAME=" + path.string())
3176a3fd2c2SJay Meyer .c_str());
318015e3adeSMatt Spinler
319ceacf941SMatt Spinler using metadata = xyz::openbmc_project::Common::Device::WriteFailure;
320ceacf941SMatt Spinler
321f0f02b9aSMatt Spinler elog<WriteFailure>(
322f0f02b9aSMatt Spinler metadata::CALLOUT_ERRNO(rc),
323f0f02b9aSMatt Spinler metadata::CALLOUT_DEVICE_PATH(fs::canonical(basePath).c_str()));
324015e3adeSMatt Spinler }
325015e3adeSMatt Spinler }
326015e3adeSMatt Spinler
writeBinary(const std::string & name,std::vector<uint8_t> data,Type type)32759a35793SBrandon Wyman void PMBus::writeBinary(const std::string& name, std::vector<uint8_t> data,
32859a35793SBrandon Wyman Type type)
32959a35793SBrandon Wyman {
33059a35793SBrandon Wyman std::ofstream file;
33159a35793SBrandon Wyman fs::path path = getPath(type);
33259a35793SBrandon Wyman
33359a35793SBrandon Wyman path /= name;
33459a35793SBrandon Wyman
33559a35793SBrandon Wyman file.exceptions(std::ofstream::failbit | std::ofstream::badbit |
33659a35793SBrandon Wyman std::ofstream::eofbit);
33759a35793SBrandon Wyman
33859a35793SBrandon Wyman try
33959a35793SBrandon Wyman {
34059a35793SBrandon Wyman // I need to specify binary mode when I construct the ofstream
34159a35793SBrandon Wyman file.open(path, std::ios::out | std::ios_base::binary);
3426a3fd2c2SJay Meyer log<level::DEBUG>(std::string("Write data to sysfs file "
3436a3fd2c2SJay Meyer "FILENAME=" +
3446a3fd2c2SJay Meyer path.string())
3456a3fd2c2SJay Meyer .c_str());
34659a35793SBrandon Wyman file.write(reinterpret_cast<const char*>(&data[0]), data.size());
34759a35793SBrandon Wyman }
34859a35793SBrandon Wyman catch (const std::exception& e)
34959a35793SBrandon Wyman {
35059a35793SBrandon Wyman auto rc = errno;
3516a3fd2c2SJay Meyer log<level::ERR>(
3526a3fd2c2SJay Meyer (std::string("Failed to write binary data to sysfs file "
3536a3fd2c2SJay Meyer "errno=") +
3546a3fd2c2SJay Meyer std::to_string(rc) + " FILENAME=" + path.string())
3556a3fd2c2SJay Meyer .c_str());
35659a35793SBrandon Wyman
35759a35793SBrandon Wyman using metadata = xyz::openbmc_project::Common::Device::WriteFailure;
35859a35793SBrandon Wyman
35959a35793SBrandon Wyman elog<WriteFailure>(
36059a35793SBrandon Wyman metadata::CALLOUT_ERRNO(rc),
36159a35793SBrandon Wyman metadata::CALLOUT_DEVICE_PATH(fs::canonical(basePath).c_str()));
36259a35793SBrandon Wyman }
36359a35793SBrandon Wyman }
36459a35793SBrandon Wyman
findHwmonDir()365ff5f339cSBrandon Wyman void PMBus::findHwmonDir()
36657868bc5SMatt Spinler {
36757868bc5SMatt Spinler fs::path path{basePath};
36857868bc5SMatt Spinler path /= "hwmon";
36957868bc5SMatt Spinler
370aad73e92SBrandon Wyman // Make sure the directory exists, otherwise for things that can be
371aad73e92SBrandon Wyman // dynamically present or not present an exception will be thrown if the
372aad73e92SBrandon Wyman // hwmon directory is not there, resulting in a program termination.
373aad73e92SBrandon Wyman if (fs::is_directory(path))
374aad73e92SBrandon Wyman {
37557868bc5SMatt Spinler // look for <basePath>/hwmon/hwmonN/
37657868bc5SMatt Spinler for (auto& f : fs::directory_iterator(path))
37757868bc5SMatt Spinler {
37857868bc5SMatt Spinler if ((f.path().filename().string().find("hwmon") !=
37957868bc5SMatt Spinler std::string::npos) &&
38057868bc5SMatt Spinler (fs::is_directory(f.path())))
38157868bc5SMatt Spinler {
382ff5f339cSBrandon Wyman hwmonDir = f.path().filename();
38357868bc5SMatt Spinler break;
38457868bc5SMatt Spinler }
38557868bc5SMatt Spinler }
386aad73e92SBrandon Wyman }
38757868bc5SMatt Spinler
38857868bc5SMatt Spinler // Don't really want to crash here, just log it
38957868bc5SMatt Spinler // and let accesses fail later
390ff5f339cSBrandon Wyman if (hwmonDir.empty())
39157868bc5SMatt Spinler {
3926a3fd2c2SJay Meyer log<level::INFO>(std::string("Unable to find hwmon directory "
3936a3fd2c2SJay Meyer "in device base path"
3946a3fd2c2SJay Meyer " DEVICE_PATH=" +
3956a3fd2c2SJay Meyer basePath.string())
3966a3fd2c2SJay Meyer .c_str());
39757868bc5SMatt Spinler }
39857868bc5SMatt Spinler }
39957868bc5SMatt Spinler
createPMBus(std::uint8_t bus,const std::string & address)400*92261f88SPatrick Williams std::unique_ptr<PMBusBase> PMBus::createPMBus(std::uint8_t bus,
401*92261f88SPatrick Williams const std::string& address)
4028d195771SBrandon Wyman {
403f5402197SPatrick Williams const std::string physpath = {
404f5402197SPatrick Williams "/sys/bus/i2c/devices/" + std::to_string(bus) + "-" + address};
4058d195771SBrandon Wyman auto interface = std::make_unique<PMBus>(physpath);
4068d195771SBrandon Wyman
4078d195771SBrandon Wyman return interface;
4088d195771SBrandon Wyman }
4098d195771SBrandon Wyman
createPMBus(std::uint8_t bus,const std::string & address)4108d195771SBrandon Wyman std::unique_ptr<PMBusBase> createPMBus(std::uint8_t bus,
4118d195771SBrandon Wyman const std::string& address)
4128d195771SBrandon Wyman {
4138d195771SBrandon Wyman return PMBus::createPMBus(bus, address);
4148d195771SBrandon Wyman }
4158d195771SBrandon Wyman
416f0f02b9aSMatt Spinler } // namespace pmbus
417ab093328SLei YU } // namespace phosphor
418