Fansensor: Support ast26xx pwm/tach

Add new fantype for ast26xx tach driver.
Use pwm-fan driver to setup ast26xx pwm driver for easier usage.
User must define pwm-fan node in dts as below

pwm-fanX {
	compatible = "pwm-fan";
	.......
};
refer Documentation/devicetree/bindings/hwmon/pwm-fan.txt for details

and Connector in EM configuration
"Connector": {
    "Pwm": X,
    ......
}

where X is integer

Tested: On Facebook Bletchley (ast26xx) Platform with 1 fan

root@bletchley:/sys/class/leds# busctl set-property xyz.openbmc_project.FanSensor /xyz/openbmc_project/sensors/fan_pwm/Pwm_1 xyz.openbmc_project.Sensor.Value Value d 20
root@bletchley:/sys/class/leds# busctl introspect xyz.openbmc_project.FanSensor /xyz/openbmc_project/sensors/fan_tach/FAN0_TACH_IL xyz.openbmc_project.Sensor.Value
NAME                             TYPE      SIGNATURE RESULT/VALUE                             FLAGS
.MaxValue                        property  d         25000                                    emits-change
.MinValue                        property  d         0                                        emits-change
.Unit                            property  s         "xyz.openbmc_project.Sensor.Value.Uni... emits-change
.Value                           property  d         3189                                     emits-change writable
root@bletchley:/sys/class/leds# busctl introspect xyz.openbmc_project.FanSensor /xyz/openbmc_project/sensors/fan_tach/FAN0_TACH_OL xyz.openbmc_project.Sensor.Value
NAME                             TYPE      SIGNATURE RESULT/VALUE                             FLAGS
.MaxValue                        property  d         25000                                    emits-change
.MinValue                        property  d         0                                        emits-change
.Unit                            property  s         "xyz.openbmc_project.Sensor.Value.Uni... emits-change
.Value                           property  d         3006                                     emits-change writable

Signed-off-by: Howard Chiu <howard.chiu@quantatw.com>
Change-Id: Ifda89310590c9d914fa0a302df412fead807daa8
Signed-off-by: Potin Lai <potin.lai@quantatw.com>
diff --git a/src/FanMain.cpp b/src/FanMain.cpp
index 112848b..a5a5844 100644
--- a/src/FanMain.cpp
+++ b/src/FanMain.cpp
@@ -70,7 +70,8 @@
     fs::path linkPath = parentPath / "device";
     std::string canonical = fs::read_symlink(linkPath);
     if (boost::ends_with(canonical, "1e786000.pwm-tacho-controller") ||
-        boost::ends_with(canonical, "1e610000.pwm-tacho-controller"))
+        boost::ends_with(canonical, "1e610000.pwm-tacho-controller") ||
+        boost::ends_with(canonical, "1e610000.pwm_tach:tach"))
     {
         return FanTypes::aspeed;
     }
@@ -97,6 +98,63 @@
         enableFile << 1;
     }
 }
+bool findPwmfanPath(unsigned int configPwmfanIndex, fs::path& pwmPath)
+{
+    /* Search PWM since pwm-fan had separated
+     * PWM from tach directory and 1 channel only*/
+    std::vector<fs::path> pwmfanPaths;
+    std::string pwnfanDevName("pwm-fan");
+
+    pwnfanDevName += std::to_string(configPwmfanIndex);
+
+    if (!findFiles(fs::path("/sys/class/hwmon"), R"(pwm\d+)", pwmfanPaths))
+    {
+        std::cerr << "No PWMs are found!\n";
+        return false;
+    }
+    for (const auto& path : pwmfanPaths)
+    {
+        std::error_code ec;
+        fs::path link = fs::read_symlink(path.parent_path() / "device", ec);
+
+        if (ec)
+        {
+            std::cerr << "read_symlink() failed: " << ec.message() << " ("
+                      << ec.value() << ")\n";
+            continue;
+        }
+
+        if (link.filename().string() == pwnfanDevName)
+        {
+            pwmPath = path;
+            return true;
+        }
+    }
+    return false;
+}
+bool findPwmPath(const fs::path& directory, unsigned int pwm, fs::path& pwmPath)
+{
+    std::error_code ec;
+
+    /* Assuming PWM file is appeared in the same directory as fanX_input */
+    auto path = directory / ("pwm" + std::to_string(pwm + 1));
+    bool exists = fs::exists(path, ec);
+
+    if (ec || !exists)
+    {
+        /* PWM file not exist or error happened */
+        if (ec)
+        {
+            std::cerr << "exists() failed: " << ec.message() << " ("
+                      << ec.value() << ")\n";
+        }
+        /* try search form pwm-fanX directory */
+        return findPwmfanPath(pwm, pwmPath);
+    }
+
+    pwmPath = path;
+    return true;
+}
 void createRedundancySensor(
     const boost::container::flat_map<std::string, std::unique_ptr<TachSensor>>&
         sensors,
@@ -386,14 +444,21 @@
                     auto findPwm = connector->second.find("Pwm");
                     if (findPwm != connector->second.end())
                     {
-                        fs::path pwmEnableFile =
-                            "pwm" + std::to_string(index + 1) + "_enable";
-                        fs::path enablePath =
-                            path.parent_path() / pwmEnableFile;
-                        enablePwm(enablePath);
                         size_t pwm = std::visit(VariantToUnsignedIntVisitor(),
                                                 findPwm->second);
-                        pwmPath = directory / ("pwm" + std::to_string(pwm + 1));
+                        if (!findPwmPath(directory, pwm, pwmPath))
+                        {
+                            std::cerr << "Connector for " << sensorName
+                                      << " no pwm channel found!\n";
+                            continue;
+                        }
+
+                        fs::path pwmEnableFile =
+                            "pwm" + std::to_string(pwm + 1) + "_enable";
+                        fs::path enablePath =
+                            pwmPath.parent_path() / pwmEnableFile;
+                        enablePwm(enablePath);
+
                         /* use pwm name override if found in configuration else
                          * use default */
                         auto findOverride = connector->second.find("PwmName");