xref: /openbmc/phosphor-power/phosphor-power-sequencer/src/power_control.cpp (revision f54021972b91be5058b50e9046bb0dd5a3b22a80)
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