apm821xx: WNDR4700: use upstream tc654 cooling devices
authorChristian Lamparter <chunkeey@gmail.com>
Sat, 12 Feb 2022 18:53:37 +0000 (19:53 +0100)
committerChristian Lamparter <chunkeey@gmail.com>
Sat, 19 Feb 2022 18:34:18 +0000 (19:34 +0100)
Upstream hwmon-maintainer had various comments about
the changes to the tc654 driver. These have been
addressed and the cooling device support is destined
for inclusion.

One of the comments was the change of the cooling states
scaling. No longer the driver uses the same values as the
hwmon interface, instead the states are now the 17 states
the tc654 supports.

Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
target/linux/apm821xx/base-files/etc/init.d/hwmon_fancontrol [new file with mode: 0644]
target/linux/apm821xx/dts/netgear-wndr4700.dts
target/linux/apm821xx/patches-5.10/804-hwmon-tc654-add-thermal_cooling-device.patch

diff --git a/target/linux/apm821xx/base-files/etc/init.d/hwmon_fancontrol b/target/linux/apm821xx/base-files/etc/init.d/hwmon_fancontrol
new file mode 100644 (file)
index 0000000..d38964e
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh /etc/rc.common
+
+START=98
+
+boot() {
+       # configuring onboard temp/fan controller to run the fan on its own
+       # for more information, please read https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
+
+       case $(board_name) in
+       netgear,wndr4700)
+               path_to_hwmon='/sys/devices/platform/plb/plb:opb/4ef600700.i2c/i2c-0/0-001b/hwmon/hwmon1'
+               echo 1 > "$path_to_hwmon/pwm1_enable"
+               ;;
+       esac
+}
index 12d9dc0bfd1ee263c128a7a210f2644a9b41f555..fe0f7139430f08ae3f316abfb8561fb1355e6611 100644 (file)
 
                                map1 {
                                        trip = <&cpu_alert1>;
-                                       cooling-device = <&fan0 1 76>;
+                                       cooling-device = <&fan0 1 1>;
                                };
 
                                map2 {
                                        trip = <&cpu_alert2>;
-                                       cooling-device = <&fan0 77 101>;
+                                       cooling-device = <&fan0 2 4>;
                                };
 
                                map3 {
                                        trip = <&cpu_alert3>;
-                                       cooling-device = <&fan0 102 147>;
+                                       cooling-device = <&fan0 4 8>;
                                };
 
                                map4 {
                                        trip = <&cpu_alert4>;
-                                       cooling-device = <&fan0 148 207>;
+                                       cooling-device = <&fan0 9 12>;
                                };
 
                                map5 {
                                        trip = <&cpu_alert5>;
-                                       cooling-device = <&fan0 208 231>;
+                                       cooling-device = <&fan0 13 15>;
                                };
 
                                map6 {
                                        trip = <&cpu_alert6>;
-                                       cooling-device =<&fan0 232 THERMAL_NO_LIMIT>;
+                                       cooling-device =<&fan0 16 THERMAL_NO_LIMIT>;
                                };
                        };
                };
index 0d2bd79fd7749377271c45789810fd2cf7444731..466507a8fb417b94e566c68ecf0b4a6eda43d1ff 100644 (file)
@@ -1,16 +1,20 @@
-From 9cb27801b5cbad2e1aaf45aac428cb2fac5e1372 Mon Sep 17 00:00:00 2001
+From 4d49367c5303e3ebd17502a45b74de280f6be539 Mon Sep 17 00:00:00 2001
 From: Christian Lamparter <chunkeey@gmail.com>
-Date: Sun, 17 Dec 2017 17:29:13 +0100
-Subject: [PATCH] hwmon: tc654: add thermal_cooling device
+Date: Sun, 13 Feb 2022 01:47:33 +0100
+Subject: hwmon: (tc654) Add thermal_cooling device support
 
-This patch adds a thermaL_cooling device to the tc654 driver.
-This allows the chip to be used for DT-based cooling.
+Adds thermal_cooling device support to the tc654/tc655
+driver. This make it possible to integrate it into a
+device-tree supported thermal-zone node as a
+cooling device.
+
+I have been using this patch as part of the Netgear WNDR4700
+Centria NAS Router support within OpenWrt since 2016.
 
 Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
+Link: https://lore.kernel.org/r/20220213004733.2421193-1-chunkeey@gmail.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
 ---
- drivers/hwmon/tc654.c | 103 +++++++++++++++++++++++++++++++++++-------
- 1 file changed, 86 insertions(+), 17 deletions(-)
-
 --- a/drivers/hwmon/tc654.c
 +++ b/drivers/hwmon/tc654.c
 @@ -15,6 +15,7 @@
@@ -21,44 +25,8 @@ Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
  #include <linux/util_macros.h>
  
  enum tc654_regs {
-@@ -132,6 +133,9 @@ struct tc654_data {
-                        * writable register used to control the duty
-                        * cycle of the V OUT output.
-                        */
-+
-+      /* optional cooling device */
-+      struct thermal_cooling_device *cdev;
- };
- /* helper to grab and cache data, at most one time per second */
-@@ -367,36 +371,30 @@ static ssize_t pwm_mode_store(struct dev
- static const int tc654_pwm_map[16] = { 77,  88, 102, 112, 124, 136, 148, 160,
-                                     172, 184, 196, 207, 219, 231, 243, 255};
-+static int get_pwm(struct tc654_data *data)
-+{
-+      if (data->config & TC654_REG_CONFIG_SDM)
-+              return 0;
-+      else
-+              return tc654_pwm_map[data->duty_cycle];
-+}
-+
- static ssize_t pwm_show(struct device *dev, struct device_attribute *da,
-                       char *buf)
- {
-       struct tc654_data *data = tc654_update_client(dev);
--      int pwm;
-       if (IS_ERR(data))
-               return PTR_ERR(data);
--      if (data->config & TC654_REG_CONFIG_SDM)
--              pwm = 0;
--      else
--              pwm = tc654_pwm_map[data->duty_cycle];
--
--      return sprintf(buf, "%d\n", pwm);
-+      return sprintf(buf, "%d\n", get_pwm(data));
+@@ -384,28 +385,20 @@ static ssize_t pwm_show(struct device *d
+       return sprintf(buf, "%d\n", pwm);
  }
  
 -static ssize_t pwm_store(struct device *dev, struct device_attribute *da,
@@ -77,8 +45,22 @@ Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
 -
        mutex_lock(&data->update_lock);
  
-       if (val == 0)
-@@ -416,6 +414,22 @@ static ssize_t pwm_store(struct device *
+-      if (val == 0)
++      if (val == 0) {
+               data->config |= TC654_REG_CONFIG_SDM;
+-      else
++              data->duty_cycle = 0;
++      } else {
+               data->config &= ~TC654_REG_CONFIG_SDM;
+-
+-      data->duty_cycle = find_closest(val, tc654_pwm_map,
+-                                      ARRAY_SIZE(tc654_pwm_map));
++              data->duty_cycle = val - 1;
++      }
+       ret = i2c_smbus_write_byte_data(client, TC654_REG_CONFIG, data->config);
+       if (ret < 0)
+@@ -416,6 +409,24 @@ static ssize_t pwm_store(struct device *
  
  out:
        mutex_unlock(&data->update_lock);
@@ -86,7 +68,7 @@ Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
 +}
 +
 +static ssize_t pwm_store(struct device *dev, struct device_attribute *da,
-+                     const char *buf, size_t count)
++                       const char *buf, size_t count)
 +{
 +      struct tc654_data *data = dev_get_drvdata(dev);
 +      unsigned long val;
@@ -96,48 +78,60 @@ Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
 +              return -EINVAL;
 +      if (val > 255)
 +              return -EINVAL;
++      if (val > 0)
++              val = find_closest(val, tc654_pwm_map, ARRAY_SIZE(tc654_pwm_map)) + 1;
 +
 +      ret = _set_pwm(data, val);
        return ret < 0 ? ret : count;
  }
  
-@@ -447,6 +461,47 @@ static struct attribute *tc654_attrs[] =
+@@ -448,6 +459,58 @@ static struct attribute *tc654_attrs[] =
  ATTRIBUTE_GROUPS(tc654);
  
-+/* cooling device */
-+
-+static int tc654_get_max_state(struct thermal_cooling_device *cdev,
-+                             unsigned long *state)
+ /*
++ * thermal cooling device functions
++ *
++ * Account for the "ShutDown Mode (SDM)" state by offsetting
++ * the 16 PWM duty cycle states by 1.
++ *
++ * State  0 =   0% PWM | Shutdown - Fan(s) are off
++ * State  1 =  30% PWM | duty_cycle =  0
++ * State  2 = ~35% PWM | duty_cycle =  1
++ * [...]
++ * State 15 = ~95% PWM | duty_cycle = 14
++ * State 16 = 100% PWM | duty_cycle = 15
++ */
++#define TC654_MAX_COOLING_STATE       16
++
++static int tc654_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state)
 +{
-+      *state = 255;
++      *state = TC654_MAX_COOLING_STATE;
 +      return 0;
 +}
 +
-+static int tc654_get_cur_state(struct thermal_cooling_device *cdev,
-+                              unsigned long *state)
++static int tc654_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state)
 +{
 +      struct tc654_data *data = tc654_update_client(cdev->devdata);
 +
 +      if (IS_ERR(data))
 +              return PTR_ERR(data);
 +
-+      *state = get_pwm(data);
++      if (data->config & TC654_REG_CONFIG_SDM)
++              *state = 0;     /* FAN is off */
++      else
++              *state = data->duty_cycle + 1;  /* offset PWM States by 1 */
++
 +      return 0;
 +}
 +
-+static int tc654_set_cur_state(struct thermal_cooling_device *cdev,
-+                             unsigned long state)
++static int tc654_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
 +{
 +      struct tc654_data *data = tc654_update_client(cdev->devdata);
 +
 +      if (IS_ERR(data))
 +              return PTR_ERR(data);
 +
-+      if (state > 255)
-+              return -EINVAL;
-+
-+      return _set_pwm(data, state);
++      return _set_pwm(data, clamp_val(state, 0, TC654_MAX_COOLING_STATE));
 +}
 +
 +static const struct thermal_cooling_device_ops tc654_fan_cool_ops = {
@@ -146,10 +140,11 @@ Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
 +      .set_cur_state = tc654_set_cur_state,
 +};
 +
- /*
++/*
   * device probe and removal
   */
-@@ -477,7 +532,21 @@ static int tc654_probe(struct i2c_client
+@@ -477,7 +540,18 @@ static int tc654_probe(struct i2c_client
        hwmon_dev =
            devm_hwmon_device_register_with_groups(dev, client->name, data,
                                                   tc654_groups);
@@ -157,18 +152,15 @@ Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
 +      if (IS_ERR(hwmon_dev))
 +              return PTR_ERR(hwmon_dev);
 +
-+#if IS_ENABLED(CONFIG_OF)
-+      /* Optional cooling device register for Device tree platforms */
-+      data->cdev = thermal_of_cooling_device_register(client->dev.of_node,
-+                                                      "tc654", hwmon_dev,
-+                                                      &tc654_fan_cool_ops);
-+#else /* CONFIG_OF */
-+      /* Optional cooling device register for non Device tree platforms */
-+      data->cdev = thermal_cooling_device_register("tc654", hwmon_dev,
-+                                                   &tc654_fan_cool_ops);
-+#endif /* CONFIG_OF */
-+
-+      return PTR_ERR_OR_ZERO(data->cdev);
++      if (IS_ENABLED(CONFIG_THERMAL)) {
++              struct thermal_cooling_device *cdev;
++
++              cdev = devm_thermal_of_cooling_device_register(dev, dev->of_node, client->name,
++                                                             hwmon_dev, &tc654_fan_cool_ops);
++              return PTR_ERR_OR_ZERO(cdev);
++      }
++
++      return 0;
  }
  
  static const struct i2c_device_id tc654_id[] = {