[openwrt/openwrt] mvebu: puzzle: fix fan thermal cooling driver
LEDE Commits
lede-commits at lists.infradead.org
Sat Feb 25 11:21:07 PST 2023
dangole pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/ea33a5def506b0ba647f779e60e6ccca03c29a17
commit ea33a5def506b0ba647f779e60e6ccca03c29a17
Author: Daniel Golle <daniel at makrotopia.org>
AuthorDate: Sat Feb 25 02:35:16 2023 +0000
mvebu: puzzle: fix fan thermal cooling driver
Several fixes for the Puzzle WT61P803 hwmon driver were needed to make
it behave well as thermal cooling device:
- wire-up cooling device with OF node in device tree
- properly parse cooling-levels (u32 with range check vs. u8)
- actually use cooling-levels
- keep current state and only write to uC if state has changed
(avoids flooding the uC with commands which will result in uC crashing)
Signed-off-by: Daniel Golle <daniel at makrotopia.org>
---
...on-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch | 78 +++++++++++++++-------
...on-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch | 78 +++++++++++++++-------
2 files changed, 110 insertions(+), 46 deletions(-)
diff --git a/target/linux/mvebu/patches-5.10/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch b/target/linux/mvebu/patches-5.10/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch
index 684f09c800..d31709fd85 100644
--- a/target/linux/mvebu/patches-5.10/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch
+++ b/target/linux/mvebu/patches-5.10/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch
@@ -53,7 +53,7 @@ Cc: Robert Marko <robert.marko at sartura.hr>
obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
--- /dev/null
+++ b/drivers/hwmon/iei-wt61p803-puzzle-hwmon.c
-@@ -0,0 +1,413 @@
+@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* IEI WT61P803 PUZZLE MCU HWMON Driver
+ *
@@ -84,13 +84,17 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+ * @name: Thermal cooling device name
+ * @pwm_channel: Controlled PWM channel (0 or 1)
+ * @cooling_levels: Thermal cooling device cooling levels (DT)
++ * @cur_level: Current cooling level
++ * @num_levels: Number of cooling levels
+ */
+struct iei_wt61p803_puzzle_thermal_cooling_device {
+ struct iei_wt61p803_puzzle_hwmon *mcu_hwmon;
+ struct thermal_cooling_device *tcdev;
+ char name[THERMAL_NAME_LENGTH];
+ int pwm_channel;
-+ u8 *cooling_levels;
++ u32 *cooling_levels;
++ int cur_level;
++ u8 num_levels;
+};
+
+/**
@@ -326,8 +330,12 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+static int iei_wt61p803_puzzle_get_max_state(struct thermal_cooling_device *tcdev,
+ unsigned long *state)
+{
-+ *state = IEI_WT61P803_PUZZLE_HWMON_MAX_PWM_VAL;
++ struct iei_wt61p803_puzzle_thermal_cooling_device *cdev = tcdev->devdata;
++
++ if (!cdev)
++ return -EINVAL;
+
++ *state = cdev->num_levels - 1;
+ return 0;
+}
+
@@ -335,14 +343,14 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+ unsigned long *state)
+{
+ struct iei_wt61p803_puzzle_thermal_cooling_device *cdev = tcdev->devdata;
-+ struct iei_wt61p803_puzzle_hwmon *mcu_hwmon = cdev->mcu_hwmon;
-+ long value;
-+ int ret;
+
-+ ret = iei_wt61p803_puzzle_read_pwm_channel(mcu_hwmon, cdev->pwm_channel, &value);
-+ if (ret)
-+ return ret;
-+ *state = value;
++ if (!cdev)
++ return -EINVAL;
++
++ if (cdev->cur_level < 0)
++ return -EAGAIN;
++
++ *state = cdev->cur_level;
+ return 0;
+}
+
@@ -350,9 +358,21 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+ unsigned long state)
+{
+ struct iei_wt61p803_puzzle_thermal_cooling_device *cdev = tcdev->devdata;
-+ struct iei_wt61p803_puzzle_hwmon *mcu_hwmon = cdev->mcu_hwmon;
++ u8 pwm_level;
++
++ if (!cdev)
++ return -EINVAL;
+
-+ return iei_wt61p803_puzzle_write_pwm_channel(mcu_hwmon, cdev->pwm_channel, state);
++ if (state >= cdev->num_levels)
++ return -EINVAL;
++
++ if (state == cdev->cur_level)
++ return 0;
++
++ cdev->cur_level = state;
++ pwm_level = cdev->cooling_levels[state];
++
++ return iei_wt61p803_puzzle_write_pwm_channel(cdev->mcu_hwmon, cdev->pwm_channel, pwm_level);
+}
+
+static const struct thermal_cooling_device_ops iei_wt61p803_puzzle_cooling_ops = {
@@ -369,7 +389,7 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+ struct iei_wt61p803_puzzle_thermal_cooling_device *cdev;
+ u32 pwm_channel;
+ u8 num_levels;
-+ int ret;
++ int i, ret;
+
+ ret = fwnode_property_read_u32(child, "reg", &pwm_channel);
+ if (ret)
@@ -377,7 +397,7 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+
+ mcu_hwmon->thermal_cooling_dev_present[pwm_channel] = true;
+
-+ num_levels = fwnode_property_count_u8(child, "cooling-levels");
++ num_levels = fwnode_property_count_u32(child, "cooling-levels");
+ if (!num_levels)
+ return -EINVAL;
+
@@ -385,28 +405,40 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+ if (!cdev)
+ return -ENOMEM;
+
-+ cdev->cooling_levels = devm_kmalloc_array(dev, num_levels, sizeof(u8), GFP_KERNEL);
++ cdev->cooling_levels = devm_kmalloc_array(dev, num_levels, sizeof(u32), GFP_KERNEL);
+ if (!cdev->cooling_levels)
+ return -ENOMEM;
+
-+ ret = fwnode_property_read_u8_array(child, "cooling-levels",
-+ cdev->cooling_levels,
-+ num_levels);
++ ret = fwnode_property_read_u32_array(child, "cooling-levels",
++ cdev->cooling_levels,
++ num_levels);
+ if (ret) {
+ dev_err(dev, "Couldn't read property 'cooling-levels'\n");
+ return ret;
+ }
+
-+ snprintf(cdev->name, THERMAL_NAME_LENGTH, "wt61p803_puzzle_%d", pwm_channel);
-+ cdev->tcdev = devm_thermal_of_cooling_device_register(dev, NULL, cdev->name, cdev,
-+ &iei_wt61p803_puzzle_cooling_ops);
-+ if (IS_ERR(cdev->tcdev))
-+ return PTR_ERR(cdev->tcdev);
++ for (i = 0; i < num_levels; i++) {
++ if (cdev->cooling_levels[i] >
++ IEI_WT61P803_PUZZLE_HWMON_MAX_PWM_VAL) {
++ dev_err(dev, "iei_wt61p803_fan state[%d]:%d > %d\n", i,
++ cdev->cooling_levels[i],
++ IEI_WT61P803_PUZZLE_HWMON_MAX_PWM_VAL);
++ return -EINVAL;
++ }
++ }
+
+ cdev->mcu_hwmon = mcu_hwmon;
+ cdev->pwm_channel = pwm_channel;
++ cdev->num_levels = num_levels;
++ cdev->cur_level = -1;
+ mcu_hwmon->cdev[pwm_channel] = cdev;
+
++ snprintf(cdev->name, THERMAL_NAME_LENGTH, "wt61p803_puzzle_%d", pwm_channel);
++ cdev->tcdev = devm_thermal_of_cooling_device_register(dev, to_of_node(child), cdev->name,
++ cdev, &iei_wt61p803_puzzle_cooling_ops);
++ if (IS_ERR(cdev->tcdev))
++ return PTR_ERR(cdev->tcdev);
++
+ return 0;
+}
+
diff --git a/target/linux/mvebu/patches-5.15/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch b/target/linux/mvebu/patches-5.15/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch
index c22314e41c..023495373b 100644
--- a/target/linux/mvebu/patches-5.15/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch
+++ b/target/linux/mvebu/patches-5.15/903-drivers-hwmon-Add-the-IEI-WT61P803-PUZZLE-HWMON-driv.patch
@@ -53,7 +53,7 @@ Cc: Robert Marko <robert.marko at sartura.hr>
obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
--- /dev/null
+++ b/drivers/hwmon/iei-wt61p803-puzzle-hwmon.c
-@@ -0,0 +1,413 @@
+@@ -0,0 +1,445 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* IEI WT61P803 PUZZLE MCU HWMON Driver
+ *
@@ -84,13 +84,17 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+ * @name: Thermal cooling device name
+ * @pwm_channel: Controlled PWM channel (0 or 1)
+ * @cooling_levels: Thermal cooling device cooling levels (DT)
++ * @cur_level: Current cooling level
++ * @num_levels: Number of cooling levels
+ */
+struct iei_wt61p803_puzzle_thermal_cooling_device {
+ struct iei_wt61p803_puzzle_hwmon *mcu_hwmon;
+ struct thermal_cooling_device *tcdev;
+ char name[THERMAL_NAME_LENGTH];
+ int pwm_channel;
-+ u8 *cooling_levels;
++ u32 *cooling_levels;
++ int cur_level;
++ u8 num_levels;
+};
+
+/**
@@ -326,8 +330,12 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+static int iei_wt61p803_puzzle_get_max_state(struct thermal_cooling_device *tcdev,
+ unsigned long *state)
+{
-+ *state = IEI_WT61P803_PUZZLE_HWMON_MAX_PWM_VAL;
++ struct iei_wt61p803_puzzle_thermal_cooling_device *cdev = tcdev->devdata;
++
++ if (!cdev)
++ return -EINVAL;
+
++ *state = cdev->num_levels - 1;
+ return 0;
+}
+
@@ -335,14 +343,14 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+ unsigned long *state)
+{
+ struct iei_wt61p803_puzzle_thermal_cooling_device *cdev = tcdev->devdata;
-+ struct iei_wt61p803_puzzle_hwmon *mcu_hwmon = cdev->mcu_hwmon;
-+ long value;
-+ int ret;
+
-+ ret = iei_wt61p803_puzzle_read_pwm_channel(mcu_hwmon, cdev->pwm_channel, &value);
-+ if (ret)
-+ return ret;
-+ *state = value;
++ if (!cdev)
++ return -EINVAL;
++
++ if (cdev->cur_level < 0)
++ return -EAGAIN;
++
++ *state = cdev->cur_level;
+ return 0;
+}
+
@@ -350,9 +358,21 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+ unsigned long state)
+{
+ struct iei_wt61p803_puzzle_thermal_cooling_device *cdev = tcdev->devdata;
-+ struct iei_wt61p803_puzzle_hwmon *mcu_hwmon = cdev->mcu_hwmon;
++ u8 pwm_level;
++
++ if (!cdev)
++ return -EINVAL;
+
-+ return iei_wt61p803_puzzle_write_pwm_channel(mcu_hwmon, cdev->pwm_channel, state);
++ if (state >= cdev->num_levels)
++ return -EINVAL;
++
++ if (state == cdev->cur_level)
++ return 0;
++
++ cdev->cur_level = state;
++ pwm_level = cdev->cooling_levels[state];
++
++ return iei_wt61p803_puzzle_write_pwm_channel(cdev->mcu_hwmon, cdev->pwm_channel, pwm_level);
+}
+
+static const struct thermal_cooling_device_ops iei_wt61p803_puzzle_cooling_ops = {
@@ -369,7 +389,7 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+ struct iei_wt61p803_puzzle_thermal_cooling_device *cdev;
+ u32 pwm_channel;
+ u8 num_levels;
-+ int ret;
++ int i, ret;
+
+ ret = fwnode_property_read_u32(child, "reg", &pwm_channel);
+ if (ret)
@@ -377,7 +397,7 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+
+ mcu_hwmon->thermal_cooling_dev_present[pwm_channel] = true;
+
-+ num_levels = fwnode_property_count_u8(child, "cooling-levels");
++ num_levels = fwnode_property_count_u32(child, "cooling-levels");
+ if (!num_levels)
+ return -EINVAL;
+
@@ -385,28 +405,40 @@ Cc: Robert Marko <robert.marko at sartura.hr>
+ if (!cdev)
+ return -ENOMEM;
+
-+ cdev->cooling_levels = devm_kmalloc_array(dev, num_levels, sizeof(u8), GFP_KERNEL);
++ cdev->cooling_levels = devm_kmalloc_array(dev, num_levels, sizeof(u32), GFP_KERNEL);
+ if (!cdev->cooling_levels)
+ return -ENOMEM;
+
-+ ret = fwnode_property_read_u8_array(child, "cooling-levels",
-+ cdev->cooling_levels,
-+ num_levels);
++ ret = fwnode_property_read_u32_array(child, "cooling-levels",
++ cdev->cooling_levels,
++ num_levels);
+ if (ret) {
+ dev_err(dev, "Couldn't read property 'cooling-levels'\n");
+ return ret;
+ }
+
-+ snprintf(cdev->name, THERMAL_NAME_LENGTH, "wt61p803_puzzle_%d", pwm_channel);
-+ cdev->tcdev = devm_thermal_of_cooling_device_register(dev, NULL, cdev->name, cdev,
-+ &iei_wt61p803_puzzle_cooling_ops);
-+ if (IS_ERR(cdev->tcdev))
-+ return PTR_ERR(cdev->tcdev);
++ for (i = 0; i < num_levels; i++) {
++ if (cdev->cooling_levels[i] >
++ IEI_WT61P803_PUZZLE_HWMON_MAX_PWM_VAL) {
++ dev_err(dev, "iei_wt61p803_fan state[%d]:%d > %d\n", i,
++ cdev->cooling_levels[i],
++ IEI_WT61P803_PUZZLE_HWMON_MAX_PWM_VAL);
++ return -EINVAL;
++ }
++ }
+
+ cdev->mcu_hwmon = mcu_hwmon;
+ cdev->pwm_channel = pwm_channel;
++ cdev->num_levels = num_levels;
++ cdev->cur_level = -1;
+ mcu_hwmon->cdev[pwm_channel] = cdev;
+
++ snprintf(cdev->name, THERMAL_NAME_LENGTH, "wt61p803_puzzle_%d", pwm_channel);
++ cdev->tcdev = devm_thermal_of_cooling_device_register(dev, to_of_node(child), cdev->name,
++ cdev, &iei_wt61p803_puzzle_cooling_ops);
++ if (IS_ERR(cdev->tcdev))
++ return PTR_ERR(cdev->tcdev);
++
+ return 0;
+}
+
More information about the lede-commits
mailing list