pseq: Add GPIOs to power control application

Add power control GPIOs for power on / off control and chassis power
good monitoring. Use libgpiod and make neccessary meson changes.

Signed-off-by: Jim Wright <jlwright@us.ibm.com>
Change-Id: I4f44552e855547fea466a98cb71acdb315aa26f5
diff --git a/phosphor-power-sequencer/src/power_control.cpp b/phosphor-power-sequencer/src/power_control.cpp
index 931142d..2680409 100644
--- a/phosphor-power-sequencer/src/power_control.cpp
+++ b/phosphor-power-sequencer/src/power_control.cpp
@@ -20,19 +20,22 @@
 
 #include <fmt/format.h>
 
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/elog.hpp>
 #include <phosphor-logging/log.hpp>
-#include <sdbusplus/bus.hpp>
-#include <sdeventplus/event.hpp>
-#include <sdeventplus/utility/timer.hpp>
+#include <xyz/openbmc_project/Common/error.hpp>
 
-#include <chrono>
 #include <exception>
+#include <string>
 
 using namespace phosphor::logging;
 
 namespace phosphor::power::sequencer
 {
 
+const std::string powerControlLineName = "power-chassis-control";
+const std::string pgoodLineName = "power-chassis-good";
+
 PowerControl::PowerControl(sdbusplus::bus::bus& bus,
                            const sdeventplus::Event& event) :
     PowerObject{bus, POWER_OBJ_PATH, true},
@@ -41,6 +44,7 @@
 {
     // Obtain dbus service name
     bus.request_name(POWER_IFACE);
+    setUpGpio();
 }
 
 int PowerControl::getPgood() const
@@ -59,7 +63,37 @@
 }
 
 void PowerControl::pollPgood()
-{}
+{
+    if (inStateTransition)
+    {
+        const auto now = std::chrono::steady_clock::now();
+        if (now > pgoodTimeoutTime)
+        {
+            log<level::ERR>("ERROR PowerControl: Pgood poll timeout");
+            inStateTransition = false;
+            return;
+        }
+    }
+
+    int pgoodState = pgoodLine.get_value();
+    if (pgoodState != pgood)
+    {
+        pgood = pgoodState;
+        if (pgoodState == 0)
+        {
+            emitPowerLostSignal();
+        }
+        else
+        {
+            emitPowerGoodSignal();
+        }
+        emitPropertyChangedSignal("pgood");
+    }
+    if (pgoodState == state)
+    {
+        inStateTransition = false;
+    }
+}
 
 void PowerControl::setPgoodTimeout(int t)
 {
@@ -80,8 +114,46 @@
     }
 
     log<level::INFO>(fmt::format("setState: {}", s).c_str());
+    powerControlLine.request(
+        {"phosphor-power-control", gpiod::line_request::DIRECTION_OUTPUT, 0});
+    powerControlLine.set_value(s);
+    powerControlLine.release();
+
+    pgoodTimeoutTime = std::chrono::steady_clock::now() + timeout;
+    inStateTransition = true;
     state = s;
     emitPropertyChangedSignal("state");
 }
 
+void PowerControl::setUpGpio()
+{
+    pgoodLine = gpiod::find_line(pgoodLineName);
+    if (!pgoodLine)
+    {
+        std::string errorString =
+            fmt::format("GPIO line name not found: {}", pgoodLineName);
+        log<level::ERR>(errorString.c_str());
+        report<
+            sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
+        throw std::runtime_error(errorString);
+    }
+    powerControlLine = gpiod::find_line(powerControlLineName);
+    if (!powerControlLine)
+    {
+        std::string errorString =
+            fmt::format("GPIO line name not found: {}", powerControlLineName);
+        log<level::ERR>(errorString.c_str());
+        report<
+            sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
+        throw std::runtime_error(errorString);
+    }
+
+    pgoodLine.request(
+        {"phosphor-power-control", gpiod::line_request::DIRECTION_INPUT, 0});
+    int pgoodState = pgoodLine.get_value();
+    pgood = pgoodState;
+    state = pgoodState;
+    log<level::INFO>(fmt::format("Pgood state: {}", pgoodState).c_str());
+}
+
 } // namespace phosphor::power::sequencer