]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
kernel: backport lm63 enhancements 23525/head
authorJan-Henrik Bruhn <git@jhbruhn.de>
Mon, 25 May 2026 08:37:11 +0000 (10:37 +0200)
committerJonas Jelonek <jelonek.jonas@gmail.com>
Mon, 25 May 2026 10:17:01 +0000 (12:17 +0200)
This was a pending patch before, it has been accepted by upstream.

The patch exposes the PWM frequency and temperature hysteresis values for the
LM63 fan controller.

Signed-off-by: Jan-Henrik Bruhn <git@jhbruhn.de>
Link: https://github.com/openwrt/openwrt/pull/23525
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
target/linux/generic/backport-6.18/842-v7.2-hwmon-lm63-make-pwm1_freq-and-lut-hyst-writable.patch [moved from target/linux/generic/pending-6.18/842-hwmon-lm63-make-pwm1_freq-and-lut-hyst-writable.patch with 70% similarity]

similarity index 70%
rename from target/linux/generic/pending-6.18/842-hwmon-lm63-make-pwm1_freq-and-lut-hyst-writable.patch
rename to target/linux/generic/backport-6.18/842-v7.2-hwmon-lm63-make-pwm1_freq-and-lut-hyst-writable.patch
index a7b1353abfc666661dded81b79ba8f3e4768ff64..e68aefba81696793ac0fad49576b1b133f0fb046 100644 (file)
@@ -1,6 +1,7 @@
+From 70159b00aff8c26069f25db8638cbfca970e06a0 Mon Sep 17 00:00:00 2001
 From: Jan-Henrik Bruhn <kernel@jhbruhn.de>
-Date: Wed, 21 May 2026 00:00:00 +0200
-Subject: [PATCH] hwmon: lm63: expose PWM frequency and LUT hysteresis as writable
+Date: Sat, 23 May 2026 15:36:17 +0200
+Subject: hwmon: (lm63) expose PWM frequency and LUT hysteresis as writable
 
 The driver caches the PWM frequency register and the CONFIG_FAN slow-clock
 select bit, but never lets userspace pick a different output frequency.
@@ -17,10 +18,22 @@ holding the hysteresis amount in millidegrees; the per-point attributes
 stay RO and continue to show the resulting absolute trip-down
 temperature for each entry.
 
+This was tested on a Linksys LGS328MPC switch hardware where the fan
+would not spin with the default PWM Frequency, which is why this change
+is required.
+
 Signed-off-by: Jan-Henrik Bruhn <kernel@jhbruhn.de>
+Link: https://lore.kernel.org/r/20260523133617.3439102-1-kernel@jhbruhn.de
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+---
+ drivers/hwmon/lm63.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 133 insertions(+)
+
+diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
+index a0d77a7386a9d..e2a429e579ac1 100644
 --- a/drivers/hwmon/lm63.c
 +++ b/drivers/hwmon/lm63.c
-@@ -92,6 +92,9 @@ static const unsigned short normal_i2c[]
+@@ -92,6 +92,9 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4c, 0x4e, I2C_CLIENT_END };
  #define LM96163_REG_REMOTE_TEMP_U_LSB 0x32
  #define LM96163_REG_CONFIG_ENHANCED   0x45
  
@@ -30,7 +43,7 @@ Signed-off-by: Jan-Henrik Bruhn <kernel@jhbruhn.de>
  #define LM63_MAX_CONVRATE             9
  
  #define LM63_MAX_CONVRATE_HZ          32
-@@ -447,6 +450,75 @@ static ssize_t pwm1_enable_store(struct
+@@ -455,6 +458,91 @@ static ssize_t pwm1_enable_store(struct device *dev,
        return count;
  }
  
@@ -38,10 +51,15 @@ Signed-off-by: Jan-Henrik Bruhn <kernel@jhbruhn.de>
 +                            struct device_attribute *dummy, char *buf)
 +{
 +      struct lm63_data *data = lm63_update_device(dev);
-+      unsigned int base = (data->config_fan & 0x08) ?
-+                          LM63_PWM_BASE_SLOW_HZ : LM63_PWM_BASE_FAST_HZ;
++      unsigned int base, freq;
++
++      mutex_lock(&data->update_lock);
++      base = (data->config_fan & 0x08) ?
++             LM63_PWM_BASE_SLOW_HZ : LM63_PWM_BASE_FAST_HZ;
++      freq = data->pwm1_freq;
++      mutex_unlock(&data->update_lock);
 +
-+      return sprintf(buf, "%u\n", base / data->pwm1_freq);
++      return sprintf(buf, "%u\n", base / freq);
 +}
 +
 +/*
@@ -58,14 +76,11 @@ Signed-off-by: Jan-Henrik Bruhn <kernel@jhbruhn.de>
 +      struct i2c_client *client = data->client;
 +      unsigned long val, pfr_fast, pfr_slow, err_fast, err_slow, pfr;
 +      bool slow_clock;
-+      int err;
-+
-+      if (!(data->config_fan & 0x20)) /* register is read-only */
-+              return -EPERM;
++      int ret;
 +
-+      err = kstrtoul(buf, 10, &val);
-+      if (err)
-+              return err;
++      ret = kstrtoul(buf, 10, &val);
++      if (ret)
++              return ret;
 +      if (val == 0)
 +              return -EINVAL;
 +
@@ -85,7 +100,27 @@ Signed-off-by: Jan-Henrik Bruhn <kernel@jhbruhn.de>
 +      }
 +
 +      mutex_lock(&data->update_lock);
-+      data->config_fan = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG_FAN);
++      ret = i2c_smbus_read_byte_data(client, LM63_REG_CONFIG_FAN);
++      if (ret < 0) {
++              mutex_unlock(&data->update_lock);
++              return ret;
++      }
++      data->config_fan = ret;
++
++      if (!(data->config_fan & 0x20)) { /* register is read-only */
++              mutex_unlock(&data->update_lock);
++              return -EPERM;
++      }
++
++      if (data->kind == lm96163) {
++              ret = i2c_smbus_read_byte_data(client, LM96163_REG_CONFIG_ENHANCED);
++              if (ret < 0) {
++                      mutex_unlock(&data->update_lock);
++                      return ret;
++              }
++              data->pwm_highres = !slow_clock && pfr == 8 && (ret & 0x10);
++      }
++
 +      if (slow_clock)
 +              data->config_fan |= 0x08;
 +      else
@@ -93,12 +128,6 @@ Signed-off-by: Jan-Henrik Bruhn <kernel@jhbruhn.de>
 +      i2c_smbus_write_byte_data(client, LM63_REG_CONFIG_FAN, data->config_fan);
 +      i2c_smbus_write_byte_data(client, LM63_REG_PWM_FREQ, pfr);
 +      data->pwm1_freq = pfr;
-+
-+      if (data->kind == lm96163) {
-+              u8 enh = i2c_smbus_read_byte_data(client,
-+                                                LM96163_REG_CONFIG_ENHANCED);
-+              data->pwm_highres = !slow_clock && pfr == 8 && (enh & 0x10);
-+      }
 +      mutex_unlock(&data->update_lock);
 +      return count;
 +}
@@ -106,10 +135,11 @@ Signed-off-by: Jan-Henrik Bruhn <kernel@jhbruhn.de>
  /*
   * There are 8bit registers for both local(temp1) and remote(temp2) sensor.
   * For remote sensor registers temp2_offset has to be considered,
-@@ -609,6 +681,42 @@ static ssize_t show_lut_temp_hyst(struct
+@@ -629,6 +717,47 @@ static ssize_t show_lut_temp_hyst(struct device *dev,
+       return sprintf(buf, "%d\n", temp);
  }
  
- /*
++/*
 + * The LM63 has a single hysteresis register shared by all LUT entries.
 + * Expose it as a chip-wide hysteresis amount in millidegrees; the
 + * per-point pwm1_auto_pointN_temp_hyst attributes remain read-only and
@@ -120,8 +150,13 @@ Signed-off-by: Jan-Henrik Bruhn <kernel@jhbruhn.de>
 +                                            char *buf)
 +{
 +      struct lm63_data *data = lm63_update_device(dev);
++      u8 hyst;
 +
-+      return sprintf(buf, "%d\n", TEMP8_FROM_REG(data->lut_temp_hyst));
++      mutex_lock(&data->update_lock);
++      hyst = data->lut_temp_hyst;
++      mutex_unlock(&data->update_lock);
++
++      return sprintf(buf, "%d\n", TEMP8_FROM_REG(hyst));
 +}
 +
 +static ssize_t pwm1_auto_point_temp_hyst_store(struct device *dev,
@@ -145,11 +180,10 @@ Signed-off-by: Jan-Henrik Bruhn <kernel@jhbruhn.de>
 +      return count;
 +}
 +
-+/*
+ /*
   * And now the other way around, user-space provides an absolute
   * hysteresis value and we have to store a relative one
-  */
-@@ -743,6 +851,8 @@ static SENSOR_DEVICE_ATTR(fan1_min, S_IW
+@@ -764,6 +893,8 @@ static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
  
  static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0);
  static DEVICE_ATTR_RW(pwm1_enable);
@@ -158,7 +192,7 @@ Signed-off-by: Jan-Henrik Bruhn <kernel@jhbruhn.de>
  static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO,
        show_pwm1, set_pwm1, 1);
  static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO,
-@@ -848,6 +958,8 @@ static DEVICE_ATTR_RW(update_interval);
+@@ -869,6 +1000,8 @@ static DEVICE_ATTR_RW(update_interval);
  static struct attribute *lm63_attributes[] = {
        &sensor_dev_attr_pwm1.dev_attr.attr,
        &dev_attr_pwm1_enable.attr,