psu-ng: Implement gpio write function

Implement a gpio write function to allow writing to gpios via the
libgpiod bindings. The bindings allow to set the desired gpio value by
passing it to the line request call.

Add the ability to pass flags as defined in gpiod.hpp so that the caller
can specify options such as FLAG_OPEN_DRAIN.

Change-Id: Ia7329a17c46f4f1fda0b66f795f123c8524a1be5
Signed-off-by: Adriana Kobylak <anoo@us.ibm.com>
diff --git a/phosphor-power-supply/test/mock.hpp b/phosphor-power-supply/test/mock.hpp
index d354c9f..a6a384b 100644
--- a/phosphor-power-supply/test/mock.hpp
+++ b/phosphor-power-supply/test/mock.hpp
@@ -54,6 +54,7 @@
 {
   public:
     MOCK_METHOD(int, read, (), (override));
+    MOCK_METHOD(void, write, (int value, std::bitset<32> flags), (override));
     MOCK_METHOD(std::string, getName, (), (const, override));
 };
 
diff --git a/phosphor-power-supply/util.cpp b/phosphor-power-supply/util.cpp
index 41a7109..63719d3 100644
--- a/phosphor-power-supply/util.cpp
+++ b/phosphor-power-supply/util.cpp
@@ -81,6 +81,32 @@
     return value;
 }
 
+void GPIOInterface::write(int value, std::bitset<32> flags)
+{
+    using namespace phosphor::logging;
+
+    if (!line)
+    {
+        log<level::ERR>("Failed line");
+        throw std::runtime_error{std::string{"Failed to find line"}};
+    }
+
+    try
+    {
+        line.request(
+            {__FUNCTION__, gpiod::line_request::DIRECTION_OUTPUT, flags},
+            value);
+
+        line.release();
+    }
+    catch (std::exception& e)
+    {
+        log<level::ERR>("Failed to set GPIO line", entry("MSG=%s", e.what()),
+                        entry("VALUE=%d", value));
+        throw;
+    }
+}
+
 std::unique_ptr<GPIOInterfaceBase> createGPIO(const std::string& namedGpio)
 {
     return GPIOInterface::createGPIO(namedGpio);
diff --git a/phosphor-power-supply/util.hpp b/phosphor-power-supply/util.hpp
index ca0bf3c..40fe5ca 100644
--- a/phosphor-power-supply/util.hpp
+++ b/phosphor-power-supply/util.hpp
@@ -10,6 +10,8 @@
 #include <phosphor-logging/elog.hpp>
 #include <phosphor-logging/log.hpp>
 
+#include <bitset>
+
 namespace phosphor::power::psu
 {
 
@@ -122,6 +124,17 @@
     int read() override;
 
     /**
+     * @brief Attempts to set the state of the GPIO line to the specified value.
+     *
+     * Throws an exception if line not found, request line fails, or set_value
+     * to line fails.
+     *
+     * @param[in] value - The value to set the state of the GPIO line, 1 or 0.
+     * @param[in] flags - Additional line request flags as defined in gpiod.hpp.
+     */
+    void write(int value, std::bitset<32> flags) override;
+
+    /**
      * @brief Returns the name of the GPIO, if not empty.
      */
     std::string getName() const override;
diff --git a/phosphor-power-supply/util_base.hpp b/phosphor-power-supply/util_base.hpp
index ade43ef..b5086f4 100644
--- a/phosphor-power-supply/util_base.hpp
+++ b/phosphor-power-supply/util_base.hpp
@@ -4,6 +4,8 @@
 
 #include <sdbusplus/bus/match.hpp>
 
+#include <bitset>
+
 namespace phosphor::power::psu
 {
 
@@ -43,6 +45,7 @@
     virtual ~GPIOInterfaceBase() = default;
 
     virtual int read() = 0;
+    virtual void write(int value, std::bitset<32> flags) = 0;
     virtual std::string getName() const = 0;
 };