control: Support target_path option in configuration file

The target path containing the interface
xyz.openbmc_project.control.FanPwm or
xyz.openbmc_project.control.FanSpeed can be different between
phosphor-hwmon and dbus-sensor.

In phosphor-hwmon, it is "/xyz/openbmc_project/sensors/fan_tach/".
In dbus-sensor, it is "/xyz/openbmc_project/control/fanpwm/"

This commit supports making this path configurable via "target_path".
By default, it is "/xyz/openbmc_project/sensors/fan_tach/".

Signed-off-by: Chau Ly <chaul@amperecomputing.com>
Change-Id: Id799986ff69455b7c7054070ed2ab3b2e2500a6c
diff --git a/control/example/fans.yaml b/control/example/fans.yaml
index 2583256..206206c 100644
--- a/control/example/fans.yaml
+++ b/control/example/fans.yaml
@@ -11,6 +11,10 @@
 #   sensors: [The list of sensors for this fan]
 #   target_interface: [The interface implemented by the fan target.
 #                      Default is xyz.openbmc_project.Control.FanSpeed]
+#   target_path: [The relative target path, which implements
+#                 xyz.openbmc_project.Control.FanSpeed or
+#                 xyz.openbmc_project.Control.FanPwm interface.
+#                 Default is /xyz/openbmc_project/sensors/fan_tach/]
 
 #The cooling zone, a number, and the cooling profile, a string,
 #have to match the corresponding values in the fan zone yaml
@@ -30,3 +34,4 @@
 #    sensors:
 #     - fan1
 #    target_interface: xyz.openbmc_project.Control.FanPwm
+#    target_path: /xyz/openbmc_project/control/fanpwm/
diff --git a/control/fan.cpp b/control/fan.cpp
index d368791..98d4979 100644
--- a/control/fan.cpp
+++ b/control/fan.cpp
@@ -40,7 +40,7 @@
     auto sensors = std::get<sensorListPos>(def);
     for (auto& s : sensors)
     {
-        path = FAN_SENSOR_PATH + s;
+        path = std::get<targetControlPathPos>(def) + s;
         auto service = util::SDBusPlus::getService(bus, path, _interface);
         _sensors[path] = service;
     }
diff --git a/control/fan.hpp b/control/fan.hpp
index de0a85c..bb59493 100644
--- a/control/fan.hpp
+++ b/control/fan.hpp
@@ -67,7 +67,7 @@
     std::string _name;
 
     /**
-     * Map of hwmon target sensors to the service providing them
+     * Map of target sensors to the service providing them
      */
     std::map<std::string, std::string> _sensors;
 
diff --git a/control/gen-fan-zone-defs.py b/control/gen-fan-zone-defs.py
index 72c416d..e085570 100755
--- a/control/gen-fan-zone-defs.py
+++ b/control/gen-fan-zone-defs.py
@@ -697,6 +697,9 @@
         fan['target_interface'] = f.get(
             'target_interface',
             'xyz.openbmc_project.Control.FanSpeed')
+        fan['target_path'] = f.get(
+            'target_path',
+            '/xyz/openbmc_project/sensors/fan_tach/')
         fans.append(fan)
 
     return fans
diff --git a/control/json/fan.cpp b/control/json/fan.cpp
index b9c5a58..fdabea2 100644
--- a/control/json/fan.cpp
+++ b/control/json/fan.cpp
@@ -63,7 +63,18 @@
     std::string path;
     for (const auto& sensor : jsonObj["sensors"])
     {
-        path = FAN_SENSOR_PATH + sensor.get<std::string>();
+        if (!jsonObj.contains("target_path"))
+        {
+            // If target_path is not set in configuration,
+            // it is default to /xyz/openbmc_project/sensors/fan_tach/
+            path = FAN_SENSOR_PATH + sensor.get<std::string>();
+        }
+        else
+        {
+            path = jsonObj["target_path"].get<std::string>() +
+                   sensor.get<std::string>();
+        }
+
         auto service = util::SDBusPlus::getService(_bus, path, _interface);
         _sensors[path] = service;
     }
diff --git a/control/templates/fan_zone_defs.mako.cpp b/control/templates/fan_zone_defs.mako.cpp
index 214df56..687106f 100644
--- a/control/templates/fan_zone_defs.mako.cpp
+++ b/control/templates/fan_zone_defs.mako.cpp
@@ -90,7 +90,8 @@
                             "${sensor}",
                         %endfor
                         },
-                        "${fan['target_interface']}"
+                        "${fan['target_interface']}",
+                        "${fan['target_path']}"
                     },
                 %endfor
                 },
diff --git a/control/types.hpp b/control/types.hpp
index 570cf35..ca0fe44 100644
--- a/control/types.hpp
+++ b/control/types.hpp
@@ -35,8 +35,9 @@
 constexpr auto fanNamePos = 0;
 constexpr auto sensorListPos = 1;
 constexpr auto targetInterfacePos = 2;
+constexpr auto targetControlPathPos = 3;
 using FanDefinition =
-    std::tuple<std::string, std::vector<std::string>, std::string>;
+    std::tuple<std::string, std::vector<std::string>, std::string, std::string>;
 
 constexpr auto pathPos = 0;
 constexpr auto intfPos = 1;
diff --git a/docs/control/fans.md b/docs/control/fans.md
index c5c32d5..c6a3f5d 100644
--- a/docs/control/fans.md
+++ b/docs/control/fans.md
@@ -8,7 +8,8 @@
         "name": "fan0",
         "zone": "0",
         "sensors": ["fan0_0"],
-        "target_interface": "xyz.openbmc_project.Control.FanSpeed"
+        "target_interface": "xyz.openbmc_project.Control.FanSpeed",
+        "target_path": "/xyz/openbmc_project/control/fanpwm/"
     }
     ...
 ]
@@ -29,3 +30,8 @@
 The D-Bus interface to use for setting the fan target speed/PWM. Either
 `xyz.openbmc_project.Control.FanSpeed` for RPM controlled fans or
 `xyz.openbmc_project.Control.FanPWM` for PWM controlled fans. Required.
+
+### target_path
+The D-Bus object path used for setting the fan target speed/PWM via
+"target_interface". If not configured, it defaults to
+`/xyz/openbmc_project/sensors/fan_tach/`. Optional.
\ No newline at end of file