Write pwmX_enable for fans that have a fanX_target

For fans that have a fanX_target hwmon sysfs attribute,
write the pwmX_enable on startup to put that fan into
RPM mode, which is safe to do because this application
requires that the target is written in RPMs.  The write
will only occur if the  pwm_enable file exists.

In the future, if fans with a target need to run in pwm
mode, this code will need to be updated to convert between
RPM and pwm anyway and the pwm_enable value can then
be different based on that.

Resolves openbmc/openbmc#1584

Change-Id: I4f6f3ac8d6651314367aaf5c51ac176220f1fba6
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/fan_speed.cpp b/fan_speed.cpp
index 74bbea3..df6618c 100644
--- a/fan_speed.cpp
+++ b/fan_speed.cpp
@@ -1,6 +1,7 @@
 #include "fan_speed.hpp"
 #include "hwmon.hpp"
 #include "sysfs.hpp"
+#include <experimental/filesystem>
 
 namespace hwmon
 {
@@ -23,4 +24,28 @@
     return FanSpeedObject::target(value);
 }
 
+
+void FanSpeed::enable()
+{
+    namespace fs = std::experimental::filesystem;
+
+    auto path = sysfsRoot + "/" + instance;
+    auto fullPath = make_sysfs_path(path,
+                                    type::pwm,
+                                    id,
+                                    entry::enable);
+
+    if (fs::exists(fullPath))
+    {
+        //This class always uses RPM mode
+        writeSysfsWithCallout(enable::rpmMode,
+                              sysfsRoot,
+                              instance,
+                              type::pwm,
+                              id,
+                              entry::enable);
+    }
+}
+
+
 } // namespace hwmon
diff --git a/fan_speed.hpp b/fan_speed.hpp
index 7c7da3a..eb9882c 100644
--- a/fan_speed.hpp
+++ b/fan_speed.hpp
@@ -45,6 +45,11 @@
          */
         uint64_t target(uint64_t value) override;
 
+        /**
+         * @brief Writes the pwm_enable sysfs entry.
+         */
+        void enable();
+
     private:
         /** @brief hwmon class root */
         std::string sysfsRoot;
diff --git a/hwmon.hpp b/hwmon.hpp
index 6ae1885..cc24266 100644
--- a/hwmon.hpp
+++ b/hwmon.hpp
@@ -9,10 +9,17 @@
 static constexpr auto cinput = "input";
 static constexpr auto clabel = "label";
 static constexpr auto ctarget = "target";
+static constexpr auto cenable = "enable";
 
 static const std::string input = cinput;
 static const std::string label = clabel;
 static const std::string target = ctarget;
+static const std::string enable = cenable;
+}
+
+namespace enable
+{
+static const auto rpmMode = 2;
 }
 
 namespace type
@@ -23,6 +30,8 @@
 static constexpr auto ccurr = "current";
 static constexpr auto cenergy = "energy";
 static constexpr auto cpower = "power";
+static constexpr auto cpwm = "pwm";
+
 
 static const std::string fan = cfan;
 static const std::string temp = ctemp;
@@ -30,6 +39,7 @@
 static const std::string curr = ccurr;
 static const std::string energy = cenergy;
 static const std::string power = cpower;
+static const std::string pwm = cpwm;
 }
 }
 
diff --git a/mainloop.cpp b/mainloop.cpp
index 34970b1..9714d0f 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -242,7 +242,13 @@
         addThreshold<CriticalObject>(i.first, sensorValue, info);
         //TODO openbmc/openbmc#1347
         //     Handle application restarts to set/refresh fan speed values
-        addTarget<hwmon::FanSpeed>(i.first, _hwmonRoot, _instance, info);
+        auto target = addTarget<hwmon::FanSpeed>(
+                i.first, _hwmonRoot, _instance, info);
+
+        if (target)
+        {
+            target->enable();
+        }
 
         // All the interfaces have been created.  Go ahead
         // and emit InterfacesAdded.
diff --git a/targets.hpp b/targets.hpp
index 381ba75..768d451 100644
--- a/targets.hpp
+++ b/targets.hpp
@@ -34,13 +34,17 @@
  *  @param[in] hwmonRoot - The root hwmon path
  *  @param[in] instance - The target instance name
  *  @param[in] info - The sdbusplus server connection and interfaces
+ *
+ *  @return A shared pointer to the target interface object
+ *          Will be empty if no interface was created
  */
 template <typename T>
-void addTarget(const SensorSet::key_type& sensor,
-               const std::string& hwmonRoot,
-               const std::string& instance,
-               ObjectInfo& info)
+std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
+                             const std::string& hwmonRoot,
+                             const std::string& instance,
+                             ObjectInfo& info)
 {
+    std::shared_ptr<T> target;
     namespace fs = std::experimental::filesystem;
     static constexpr bool deferSignals = true;
 
@@ -56,13 +60,15 @@
                                          hwmon::entry::target);
     if (fs::exists(sysfsFullPath))
     {
-        auto iface = std::make_shared<T>(hwmonRoot,
-                                         instance,
-                                         sensor.second,
-                                         bus,
-                                         objPath.c_str(),
-                                         deferSignals);
+        target = std::make_shared<T>(hwmonRoot,
+                                     instance,
+                                     sensor.second,
+                                     bus,
+                                     objPath.c_str(),
+                                     deferSignals);
         auto type = Targets<T>::type;
-        obj[type] = iface;
+        obj[type] = target;
     }
+
+    return target;
 }