110eb00f6SJim Wright /**
210eb00f6SJim Wright * Copyright © 2021 IBM Corporation
310eb00f6SJim Wright *
410eb00f6SJim Wright * Licensed under the Apache License, Version 2.0 (the "License");
510eb00f6SJim Wright * you may not use this file except in compliance with the License.
610eb00f6SJim Wright * You may obtain a copy of the License at
710eb00f6SJim Wright *
810eb00f6SJim Wright * http://www.apache.org/licenses/LICENSE-2.0
910eb00f6SJim Wright *
1010eb00f6SJim Wright * Unless required by applicable law or agreed to in writing, software
1110eb00f6SJim Wright * distributed under the License is distributed on an "AS IS" BASIS,
1210eb00f6SJim Wright * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1310eb00f6SJim Wright * See the License for the specific language governing permissions and
1410eb00f6SJim Wright * limitations under the License.
1510eb00f6SJim Wright */
1610eb00f6SJim Wright
17539b608fSJim Wright #include "power_control.hpp"
18539b608fSJim Wright
191f8b1103SShawn McCarney #include "config_file_parser.hpp"
201f8b1103SShawn McCarney #include "format_utils.hpp"
21539b608fSJim Wright #include "types.hpp"
221f8b1103SShawn McCarney #include "ucd90160_device.hpp"
231f8b1103SShawn McCarney #include "ucd90320_device.hpp"
241f8b1103SShawn McCarney #include "utility.hpp"
25539b608fSJim Wright
26539b608fSJim Wright #include <exception>
271f8b1103SShawn McCarney #include <format>
281f8b1103SShawn McCarney #include <functional>
291f8b1103SShawn McCarney #include <map>
301f8b1103SShawn McCarney #include <span>
311f8b1103SShawn McCarney #include <stdexcept>
321f8b1103SShawn McCarney #include <thread>
331f8b1103SShawn McCarney #include <utility>
34539b608fSJim Wright
35539b608fSJim Wright namespace phosphor::power::sequencer
3610eb00f6SJim Wright {
37539b608fSJim Wright
381f8b1103SShawn McCarney const std::string powerOnTimeoutError =
391f8b1103SShawn McCarney "xyz.openbmc_project.Power.Error.PowerOnTimeout";
401f8b1103SShawn McCarney
411f8b1103SShawn McCarney const std::string powerOffTimeoutError =
421f8b1103SShawn McCarney "xyz.openbmc_project.Power.Error.PowerOffTimeout";
431f8b1103SShawn McCarney
441f8b1103SShawn McCarney const std::string shutdownError = "xyz.openbmc_project.Power.Error.Shutdown";
457a5dd99bSJim Wright
PowerControl(sdbusplus::bus_t & bus,const sdeventplus::Event & event)467354ce62SPatrick Williams PowerControl::PowerControl(sdbusplus::bus_t& bus,
47539b608fSJim Wright const sdeventplus::Event& event) :
48*f5402197SPatrick Williams PowerObject{bus, POWER_OBJ_PATH, PowerObject::action::defer_emit}, bus{bus},
49*f5402197SPatrick Williams services{bus},
501b639538SJim Wright pgoodWaitTimer{event, std::bind(&PowerControl::onFailureCallback, this)},
51b4ad95ddSJim Wright powerOnAllowedTime{std::chrono::steady_clock::now() + minimumColdStartTime},
52ccea2d2bSJim Wright timer{event, std::bind(&PowerControl::pollPgood, this), pollInterval}
53ccea2d2bSJim Wright {
54ccea2d2bSJim Wright // Obtain dbus service name
55ccea2d2bSJim Wright bus.request_name(POWER_IFACE);
56ccea2d2bSJim Wright
571f8b1103SShawn McCarney compatSysTypesFinder = std::make_unique<util::CompatibleSystemTypesFinder>(
581f8b1103SShawn McCarney bus, std::bind_front(&PowerControl::compatibleSystemTypesFound, this));
591f8b1103SShawn McCarney
601f8b1103SShawn McCarney deviceFinder = std::make_unique<DeviceFinder>(
611f8b1103SShawn McCarney bus, std::bind_front(&PowerControl::deviceFound, this));
621f8b1103SShawn McCarney
637a5dd99bSJim Wright setUpGpio();
6410eb00f6SJim Wright }
65539b608fSJim Wright
getPgood() const6622318a32SJim Wright int PowerControl::getPgood() const
6722318a32SJim Wright {
6822318a32SJim Wright return pgood;
6922318a32SJim Wright }
7022318a32SJim Wright
getPgoodTimeout() const7122318a32SJim Wright int PowerControl::getPgoodTimeout() const
7222318a32SJim Wright {
7322318a32SJim Wright return timeout.count();
7422318a32SJim Wright }
7522318a32SJim Wright
getState() const7622318a32SJim Wright int PowerControl::getState() const
7722318a32SJim Wright {
7822318a32SJim Wright return state;
7922318a32SJim Wright }
8022318a32SJim Wright
onFailureCallback()811b639538SJim Wright void PowerControl::onFailureCallback()
821b639538SJim Wright {
831f8b1103SShawn McCarney services.logInfoMsg("After onFailure wait");
841b639538SJim Wright
851b639538SJim Wright onFailure(false);
861b639538SJim Wright
871b639538SJim Wright // Power good has failed, call for chassis hard power off
881b639538SJim Wright auto method = bus.new_method_call(util::SYSTEMD_SERVICE, util::SYSTEMD_ROOT,
891b639538SJim Wright util::SYSTEMD_INTERFACE, "StartUnit");
901b639538SJim Wright method.append(util::POWEROFF_TARGET);
911b639538SJim Wright method.append("replace");
921b639538SJim Wright bus.call_noreply(method);
931b639538SJim Wright }
941b639538SJim Wright
onFailure(bool wasTimeOut)951f8b1103SShawn McCarney void PowerControl::onFailure(bool wasTimeOut)
961b639538SJim Wright {
971f8b1103SShawn McCarney std::string error;
981f8b1103SShawn McCarney std::map<std::string, std::string> additionalData{};
991f8b1103SShawn McCarney
1001f8b1103SShawn McCarney // Check if pgood fault occurred on rail monitored by power sequencer device
1011f8b1103SShawn McCarney if (device)
1021f8b1103SShawn McCarney {
1031f8b1103SShawn McCarney try
1041f8b1103SShawn McCarney {
1051f8b1103SShawn McCarney error = device->findPgoodFault(services, powerSupplyError,
1061f8b1103SShawn McCarney additionalData);
1071f8b1103SShawn McCarney }
1081f8b1103SShawn McCarney catch (const std::exception& e)
1091f8b1103SShawn McCarney {
1101f8b1103SShawn McCarney services.logErrorMsg(e.what());
1111f8b1103SShawn McCarney additionalData.emplace("ERROR", e.what());
1121f8b1103SShawn McCarney }
1131f8b1103SShawn McCarney }
1141f8b1103SShawn McCarney
1151f8b1103SShawn McCarney // If fault was not isolated to a voltage rail, select a more generic error
1161f8b1103SShawn McCarney if (error.empty())
1171f8b1103SShawn McCarney {
1181f8b1103SShawn McCarney if (!powerSupplyError.empty())
1191f8b1103SShawn McCarney {
1201f8b1103SShawn McCarney error = powerSupplyError;
1211f8b1103SShawn McCarney }
1221f8b1103SShawn McCarney else if (wasTimeOut)
1231f8b1103SShawn McCarney {
1241f8b1103SShawn McCarney error = powerOnTimeoutError;
1251f8b1103SShawn McCarney }
1261f8b1103SShawn McCarney else
1271f8b1103SShawn McCarney {
1281f8b1103SShawn McCarney error = shutdownError;
1291f8b1103SShawn McCarney }
1301f8b1103SShawn McCarney }
1311f8b1103SShawn McCarney
1321f8b1103SShawn McCarney services.logError(error, Entry::Level::Critical, additionalData);
1331f8b1103SShawn McCarney
1341f8b1103SShawn McCarney if (!wasTimeOut)
1351f8b1103SShawn McCarney {
1361f8b1103SShawn McCarney services.createBMCDump();
1371f8b1103SShawn McCarney }
1381b639538SJim Wright }
1391b639538SJim Wright
pollPgood()140539b608fSJim Wright void PowerControl::pollPgood()
1417a5dd99bSJim Wright {
1427a5dd99bSJim Wright if (inStateTransition)
1437a5dd99bSJim Wright {
1449d7d95c7SJim Wright // In transition between power on and off, check for timeout
1457a5dd99bSJim Wright const auto now = std::chrono::steady_clock::now();
1467a5dd99bSJim Wright if (now > pgoodTimeoutTime)
1477a5dd99bSJim Wright {
1481f8b1103SShawn McCarney services.logErrorMsg(std::format(
1491f8b1103SShawn McCarney "Power state transition timeout, state: {}", state));
1507a5dd99bSJim Wright inStateTransition = false;
1514e25df5eSJim Wright
152930458c2SJim Wright if (state)
1534e25df5eSJim Wright {
154930458c2SJim Wright // Time out powering on
1551b639538SJim Wright onFailure(true);
1564e25df5eSJim Wright }
157930458c2SJim Wright else
1584e25df5eSJim Wright {
159930458c2SJim Wright // Time out powering off
160930458c2SJim Wright std::map<std::string, std::string> additionalData{};
1611f8b1103SShawn McCarney services.logError(powerOffTimeoutError, Entry::Level::Critical,
162930458c2SJim Wright additionalData);
1634e25df5eSJim Wright }
1644e25df5eSJim Wright
16548752626SJim Wright failureFound = true;
1667a5dd99bSJim Wright return;
1677a5dd99bSJim Wright }
1687a5dd99bSJim Wright }
1697a5dd99bSJim Wright
1707a5dd99bSJim Wright int pgoodState = pgoodLine.get_value();
1717a5dd99bSJim Wright if (pgoodState != pgood)
1727a5dd99bSJim Wright {
1739d7d95c7SJim Wright // Power good has changed since last read
1747a5dd99bSJim Wright pgood = pgoodState;
1757a5dd99bSJim Wright if (pgoodState == 0)
1767a5dd99bSJim Wright {
1777a5dd99bSJim Wright emitPowerLostSignal();
1787a5dd99bSJim Wright }
1797a5dd99bSJim Wright else
1807a5dd99bSJim Wright {
1817a5dd99bSJim Wright emitPowerGoodSignal();
18248752626SJim Wright // Clear any errors on the transition to power on
183abd64b94SJim Wright powerSupplyError.clear();
18448752626SJim Wright failureFound = false;
1857a5dd99bSJim Wright }
1867a5dd99bSJim Wright emitPropertyChangedSignal("pgood");
1877a5dd99bSJim Wright }
1887a5dd99bSJim Wright if (pgoodState == state)
1897a5dd99bSJim Wright {
1909d7d95c7SJim Wright // Power good matches requested state
1917a5dd99bSJim Wright inStateTransition = false;
1927a5dd99bSJim Wright }
19348752626SJim Wright else if (!inStateTransition && (pgoodState == 0) && !failureFound)
1949d7d95c7SJim Wright {
1959d7d95c7SJim Wright // Not in power off state, not changing state, and power good is off
1961f8b1103SShawn McCarney services.logErrorMsg("Chassis pgood failure");
1971b639538SJim Wright pgoodWaitTimer.restartOnce(std::chrono::seconds(7));
19848752626SJim Wright failureFound = true;
1999d7d95c7SJim Wright }
2007a5dd99bSJim Wright }
201539b608fSJim Wright
setPgoodTimeout(int t)20222318a32SJim Wright void PowerControl::setPgoodTimeout(int t)
20322318a32SJim Wright {
20422318a32SJim Wright if (timeout.count() != t)
20522318a32SJim Wright {
20622318a32SJim Wright timeout = std::chrono::seconds(t);
20722318a32SJim Wright emitPropertyChangedSignal("pgood_timeout");
20822318a32SJim Wright }
20922318a32SJim Wright }
21022318a32SJim Wright
setPowerSupplyError(const std::string & error)211ccea2d2bSJim Wright void PowerControl::setPowerSupplyError(const std::string& error)
212ccea2d2bSJim Wright {
213ccea2d2bSJim Wright powerSupplyError = error;
214ccea2d2bSJim Wright }
215ccea2d2bSJim Wright
setState(int s)21622318a32SJim Wright void PowerControl::setState(int s)
21722318a32SJim Wright {
21822318a32SJim Wright if (state == s)
21922318a32SJim Wright {
2201f8b1103SShawn McCarney services.logInfoMsg(
2211f8b1103SShawn McCarney std::format("Power already at requested state: {}", state));
22222318a32SJim Wright return;
22322318a32SJim Wright }
224209690b5SJim Wright if (s == 0)
225209690b5SJim Wright {
226209690b5SJim Wright // Wait for two seconds when powering down. This is to allow host and
227209690b5SJim Wright // other BMC applications time to complete power off processing
228209690b5SJim Wright std::this_thread::sleep_for(std::chrono::seconds(2));
229209690b5SJim Wright }
230b4ad95ddSJim Wright else
231b4ad95ddSJim Wright {
232b4ad95ddSJim Wright // If minimum power off time has not passed, wait
233b4ad95ddSJim Wright if (powerOnAllowedTime > std::chrono::steady_clock::now())
234b4ad95ddSJim Wright {
2351f8b1103SShawn McCarney services.logInfoMsg(std::format(
236b4ad95ddSJim Wright "Waiting {} seconds until power on allowed",
237b4ad95ddSJim Wright std::chrono::duration_cast<std::chrono::seconds>(
238b4ad95ddSJim Wright powerOnAllowedTime - std::chrono::steady_clock::now())
2391f8b1103SShawn McCarney .count()));
240b4ad95ddSJim Wright }
241b4ad95ddSJim Wright std::this_thread::sleep_until(powerOnAllowedTime);
242b4ad95ddSJim Wright }
24322318a32SJim Wright
2441f8b1103SShawn McCarney services.logInfoMsg(std::format("setState: {}", s));
2451f8b1103SShawn McCarney services.logInfoMsg(std::format("Powering chassis {}", (s ? "on" : "off")));
2467a5dd99bSJim Wright powerControlLine.request(
2477a5dd99bSJim Wright {"phosphor-power-control", gpiod::line_request::DIRECTION_OUTPUT, 0});
2487a5dd99bSJim Wright powerControlLine.set_value(s);
2497a5dd99bSJim Wright powerControlLine.release();
2507a5dd99bSJim Wright
251b4ad95ddSJim Wright if (s == 0)
252b4ad95ddSJim Wright {
253b4ad95ddSJim Wright // Set a minimum amount of time to wait before next power on
254*f5402197SPatrick Williams powerOnAllowedTime =
255*f5402197SPatrick Williams std::chrono::steady_clock::now() + minimumPowerOffTime;
256b4ad95ddSJim Wright }
257b4ad95ddSJim Wright
2587a5dd99bSJim Wright pgoodTimeoutTime = std::chrono::steady_clock::now() + timeout;
2597a5dd99bSJim Wright inStateTransition = true;
26022318a32SJim Wright state = s;
26122318a32SJim Wright emitPropertyChangedSignal("state");
26222318a32SJim Wright }
26322318a32SJim Wright
compatibleSystemTypesFound(const std::vector<std::string> & types)2641f8b1103SShawn McCarney void PowerControl::compatibleSystemTypesFound(
2651f8b1103SShawn McCarney const std::vector<std::string>& types)
2662d99bf7dSJim Wright {
2671f8b1103SShawn McCarney // If we don't already have compatible system types
2681f8b1103SShawn McCarney if (compatibleSystemTypes.empty())
2692d99bf7dSJim Wright {
2701f8b1103SShawn McCarney std::string typesStr = format_utils::toString(std::span{types});
2711f8b1103SShawn McCarney services.logInfoMsg(
2721f8b1103SShawn McCarney std::format("Compatible system types found: {}", typesStr));
2732d99bf7dSJim Wright
2741f8b1103SShawn McCarney // Store compatible system types
2751f8b1103SShawn McCarney compatibleSystemTypes = types;
2762d99bf7dSJim Wright
2771f8b1103SShawn McCarney // Load config file and create device object if possible
2781f8b1103SShawn McCarney loadConfigFileAndCreateDevice();
2792d99bf7dSJim Wright }
2802d99bf7dSJim Wright }
2811f8b1103SShawn McCarney
deviceFound(const DeviceProperties & properties)2821f8b1103SShawn McCarney void PowerControl::deviceFound(const DeviceProperties& properties)
2832d99bf7dSJim Wright {
2841f8b1103SShawn McCarney // If we don't already have device properties
2851f8b1103SShawn McCarney if (!deviceProperties)
2861f8b1103SShawn McCarney {
2871f8b1103SShawn McCarney services.logInfoMsg(std::format(
2881f8b1103SShawn McCarney "Power sequencer device found: type={}, name={}, bus={:d}, address={:#02x}",
2891f8b1103SShawn McCarney properties.type, properties.name, properties.bus,
2901f8b1103SShawn McCarney properties.address));
2911f8b1103SShawn McCarney
2921f8b1103SShawn McCarney // Store device properties
2931f8b1103SShawn McCarney deviceProperties = properties;
2941f8b1103SShawn McCarney
2951f8b1103SShawn McCarney // Load config file and create device object if possible
2961f8b1103SShawn McCarney loadConfigFileAndCreateDevice();
2972d99bf7dSJim Wright }
2982d99bf7dSJim Wright }
2992d99bf7dSJim Wright
setUpGpio()3007a5dd99bSJim Wright void PowerControl::setUpGpio()
3017a5dd99bSJim Wright {
3022d99bf7dSJim Wright const std::string powerControlLineName = "power-chassis-control";
3032d99bf7dSJim Wright const std::string pgoodLineName = "power-chassis-good";
3042d99bf7dSJim Wright
3057a5dd99bSJim Wright pgoodLine = gpiod::find_line(pgoodLineName);
3067a5dd99bSJim Wright if (!pgoodLine)
3077a5dd99bSJim Wright {
308209690b5SJim Wright std::string errorString{"GPIO line name not found: " + pgoodLineName};
3091f8b1103SShawn McCarney services.logErrorMsg(errorString);
3107a5dd99bSJim Wright throw std::runtime_error(errorString);
3117a5dd99bSJim Wright }
3127a5dd99bSJim Wright powerControlLine = gpiod::find_line(powerControlLineName);
3137a5dd99bSJim Wright if (!powerControlLine)
3147a5dd99bSJim Wright {
315*f5402197SPatrick Williams std::string errorString{
316*f5402197SPatrick Williams "GPIO line name not found: " + powerControlLineName};
3171f8b1103SShawn McCarney services.logErrorMsg(errorString);
3187a5dd99bSJim Wright throw std::runtime_error(errorString);
3197a5dd99bSJim Wright }
3207a5dd99bSJim Wright
3217a5dd99bSJim Wright pgoodLine.request(
3227a5dd99bSJim Wright {"phosphor-power-control", gpiod::line_request::DIRECTION_INPUT, 0});
3237a5dd99bSJim Wright int pgoodState = pgoodLine.get_value();
3247a5dd99bSJim Wright pgood = pgoodState;
3257a5dd99bSJim Wright state = pgoodState;
3261f8b1103SShawn McCarney services.logInfoMsg(std::format("Pgood state: {}", pgoodState));
3271f8b1103SShawn McCarney }
3281f8b1103SShawn McCarney
loadConfigFileAndCreateDevice()3291f8b1103SShawn McCarney void PowerControl::loadConfigFileAndCreateDevice()
3301f8b1103SShawn McCarney {
3311f8b1103SShawn McCarney // If compatible system types and device properties have been found
3321f8b1103SShawn McCarney if (!compatibleSystemTypes.empty() && deviceProperties)
3331f8b1103SShawn McCarney {
3341f8b1103SShawn McCarney // Find the JSON configuration file
3351f8b1103SShawn McCarney std::filesystem::path configFile = findConfigFile();
3361f8b1103SShawn McCarney if (!configFile.empty())
3371f8b1103SShawn McCarney {
3381f8b1103SShawn McCarney // Parse the JSON configuration file
3391f8b1103SShawn McCarney std::vector<std::unique_ptr<Rail>> rails;
3401f8b1103SShawn McCarney if (parseConfigFile(configFile, rails))
3411f8b1103SShawn McCarney {
3421f8b1103SShawn McCarney // Create the power sequencer device object
3431f8b1103SShawn McCarney createDevice(std::move(rails));
3441f8b1103SShawn McCarney }
3451f8b1103SShawn McCarney }
3461f8b1103SShawn McCarney }
3471f8b1103SShawn McCarney }
3481f8b1103SShawn McCarney
findConfigFile()3491f8b1103SShawn McCarney std::filesystem::path PowerControl::findConfigFile()
3501f8b1103SShawn McCarney {
3511f8b1103SShawn McCarney // Find config file for current system based on compatible system types
3521f8b1103SShawn McCarney std::filesystem::path configFile;
3531f8b1103SShawn McCarney if (!compatibleSystemTypes.empty())
3541f8b1103SShawn McCarney {
3551f8b1103SShawn McCarney try
3561f8b1103SShawn McCarney {
3571f8b1103SShawn McCarney configFile = config_file_parser::find(compatibleSystemTypes);
3581f8b1103SShawn McCarney if (!configFile.empty())
3591f8b1103SShawn McCarney {
3601f8b1103SShawn McCarney services.logInfoMsg(std::format(
3611f8b1103SShawn McCarney "JSON configuration file found: {}", configFile.string()));
3621f8b1103SShawn McCarney }
3631f8b1103SShawn McCarney }
3641f8b1103SShawn McCarney catch (const std::exception& e)
3651f8b1103SShawn McCarney {
3661f8b1103SShawn McCarney services.logErrorMsg(std::format(
3671f8b1103SShawn McCarney "Unable to find JSON configuration file: {}", e.what()));
3681f8b1103SShawn McCarney }
3691f8b1103SShawn McCarney }
3701f8b1103SShawn McCarney return configFile;
3711f8b1103SShawn McCarney }
3721f8b1103SShawn McCarney
parseConfigFile(const std::filesystem::path & configFile,std::vector<std::unique_ptr<Rail>> & rails)3731f8b1103SShawn McCarney bool PowerControl::parseConfigFile(const std::filesystem::path& configFile,
3741f8b1103SShawn McCarney std::vector<std::unique_ptr<Rail>>& rails)
3751f8b1103SShawn McCarney {
3761f8b1103SShawn McCarney // Parse JSON configuration file
3771f8b1103SShawn McCarney bool wasParsed{false};
3781f8b1103SShawn McCarney try
3791f8b1103SShawn McCarney {
3801f8b1103SShawn McCarney rails = config_file_parser::parse(configFile);
3811f8b1103SShawn McCarney wasParsed = true;
3821f8b1103SShawn McCarney }
3831f8b1103SShawn McCarney catch (const std::exception& e)
3841f8b1103SShawn McCarney {
3851f8b1103SShawn McCarney services.logErrorMsg(std::format(
3861f8b1103SShawn McCarney "Unable to parse JSON configuration file: {}", e.what()));
3871f8b1103SShawn McCarney }
3881f8b1103SShawn McCarney return wasParsed;
3891f8b1103SShawn McCarney }
3901f8b1103SShawn McCarney
createDevice(std::vector<std::unique_ptr<Rail>> rails)3911f8b1103SShawn McCarney void PowerControl::createDevice(std::vector<std::unique_ptr<Rail>> rails)
3921f8b1103SShawn McCarney {
3931f8b1103SShawn McCarney // Create power sequencer device based on device properties
3941f8b1103SShawn McCarney if (deviceProperties)
3951f8b1103SShawn McCarney {
3961f8b1103SShawn McCarney try
3971f8b1103SShawn McCarney {
3981f8b1103SShawn McCarney if (deviceProperties->type == UCD90160Device::deviceName)
3991f8b1103SShawn McCarney {
4001f8b1103SShawn McCarney device = std::make_unique<UCD90160Device>(
4011f8b1103SShawn McCarney std::move(rails), services, deviceProperties->bus,
4021f8b1103SShawn McCarney deviceProperties->address);
4031f8b1103SShawn McCarney }
4041f8b1103SShawn McCarney else if (deviceProperties->type == UCD90320Device::deviceName)
4051f8b1103SShawn McCarney {
4061f8b1103SShawn McCarney device = std::make_unique<UCD90320Device>(
4071f8b1103SShawn McCarney std::move(rails), services, deviceProperties->bus,
4081f8b1103SShawn McCarney deviceProperties->address);
4091f8b1103SShawn McCarney }
4101f8b1103SShawn McCarney else
4111f8b1103SShawn McCarney {
4121f8b1103SShawn McCarney throw std::runtime_error{std::format(
4131f8b1103SShawn McCarney "Unsupported device type: {}", deviceProperties->type)};
4141f8b1103SShawn McCarney }
4151f8b1103SShawn McCarney services.logInfoMsg(std::format(
4161f8b1103SShawn McCarney "Power sequencer device created: {}", device->getName()));
4171f8b1103SShawn McCarney }
4181f8b1103SShawn McCarney catch (const std::exception& e)
4191f8b1103SShawn McCarney {
4201f8b1103SShawn McCarney services.logErrorMsg(
4211f8b1103SShawn McCarney std::format("Unable to create device object: {}", e.what()));
4221f8b1103SShawn McCarney }
4231f8b1103SShawn McCarney }
4247a5dd99bSJim Wright }
4257a5dd99bSJim Wright
426539b608fSJim Wright } // namespace phosphor::power::sequencer
427