All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] hwmon: (nct6775) Add support for NCT5525
@ 2026-11-03 13:29 Anton Lundin
  2026-11-03 13:42 ` sashiko-bot
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Anton Lundin @ 2026-11-03 13:29 UTC (permalink / raw)
  To: linux-hwmon; +Cc: Guenter Roeck, Zev Weiss, Anton Lundin

Extend nct6775 driver to support NCT5525.

Assisted-by: Copilot:GPT-5.6-Terra
Signed-off-by: Anton Lundin <glance@ac2.se>
---
 .../bindings/hwmon/nuvoton,nct6775.yaml       |   1 +
 Documentation/hwmon/nct6775.rst               |  10 +-
 drivers/hwmon/nct6775-core.c                  | 130 +++++++++++++++++-
 drivers/hwmon/nct6775-i2c.c                   |   6 +-
 drivers/hwmon/nct6775-platform.c              |  12 ++
 drivers/hwmon/nct6775.h                       |   3 +-
 6 files changed, 156 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/hwmon/nuvoton,nct6775.yaml b/Documentation/devicetree/bindings/hwmon/nuvoton,nct6775.yaml
index 244470282890..16c21f1f46ef 100644
--- a/Documentation/devicetree/bindings/hwmon/nuvoton,nct6775.yaml
+++ b/Documentation/devicetree/bindings/hwmon/nuvoton,nct6775.yaml
@@ -25,6 +25,7 @@ properties:
       - nuvoton,nct6797
       - nuvoton,nct6798
       - nuvoton,nct6799
+      - nuvoton,nct5525
 
   reg:
     maxItems: 1
diff --git a/Documentation/hwmon/nct6775.rst b/Documentation/hwmon/nct6775.rst
index d2dedade0606..3e2992a1e24f 100644
--- a/Documentation/hwmon/nct6775.rst
+++ b/Documentation/hwmon/nct6775.rst
@@ -48,6 +48,14 @@ Supported chips:
 
     Datasheet: Available from the Nuvoton web site
 
+  * Nuvoton NCT5525D
+
+    Prefix: 'nct5525'
+
+    Addresses scanned: ISA address retrieved from Super I/O registers
+
+    Datasheet: Available from Nuvoton upon request
+
   * Nuvoton NCT5572D/NCT6771F/NCT6772F/NCT6775F/W83677HG-I
 
     Prefix: 'nct6775'
@@ -159,7 +167,7 @@ direct temperature sensor inputs, the others are special sources such as PECI,
 PCH, and SMBUS. Depending on the chip type, 2 to 6 of the temperature sources
 can be monitored and compared against minimum, maximum, and critical
 temperatures. The driver reports up to 10 of the temperatures to the user.
-There are 4 to 5 fan rotation speed sensors, 8 to 15 analog voltage sensors,
+There are 3 to 7 fan rotation speed sensors, 8 to 18 analog voltage sensors,
 one VID, alarms with beep warnings (control unimplemented), and some automatic
 fan regulation strategies (plus manual fan control mode).
 
diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c
index cf27b9c7a89e..fb99bdf16764 100644
--- a/drivers/hwmon/nct6775-core.c
+++ b/drivers/hwmon/nct6775-core.c
@@ -38,6 +38,7 @@
  * nct5585d    14      7       7       2+6    0xd428 0xc1    0x5ca3
  * nct6796d-s  18      7       7       6+2    0xd801 0xc1    0x5ca3
  * nct6799d-r  18      7       7       6+2    0xd802 0xc1    0x5ca3
+ * nct5525d     8      3       2       3+3    0xd2b3 0xc1    0x5ca3
  *
  * #temp lists the number of monitored temperature sources (first value) plus
  * the number of directly connectable temperature sensors (second value).
@@ -80,6 +81,7 @@ static const char * const nct6775_device_names[] = {
 	[nct6797] = "nct6797",
 	[nct6798] = "nct6798",
 	[nct6799] = "nct6799",
+	[nct5525] = "nct5525",
 };
 
 /* Common and NCT6775 specific data */
@@ -840,6 +842,33 @@ static const u16 NCT6106_REG_TEMP_CRIT[32] = {
 
 static const u16 NCT6106_REG_TSI_TEMP[] = { 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65, 0x67 };
 
+/* NCT5525D specific data */
+
+static const u16 NCT5525_REG_IN_MAX[] = {
+	0x92, 0x94, 0x96, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2 };
+static const u16 NCT5525_REG_IN_MIN[] = {
+	0x93, 0x95, 0x97, 0x9b, 0x9d, 0x9f, 0xa1, 0xa3 };
+static const u16 NCT5525_REG_IN[] = {
+	0x01, 0x02, 0x03, 0x05, 0x06, 0x07, 0x08, 0x09 };
+
+static const u16 NCT5525_REG_FAN[] = { 0x20, 0x22, 0x28 };
+static const u16 NCT5525_REG_FAN_MIN[] = { 0xe0, 0xe2, 0xe8 };
+static const u16 NCT5525_REG_FAN_PULSES[] = { 0xf6, 0xf6, 0xf5 };
+static const u16 NCT5525_FAN_PULSE_SHIFT[] = { 0, 2, 6 };
+
+static const s8 NCT5525_ALARM_BITS[NUM_ALARM_BITS] = {
+	 1,  2,  3,  5,  6,  7,  8,  9, -1, -1, -1, -1,	  /* in0-in11     */
+	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* in12-in23    */
+	32, 33, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* fan1-fan12   */
+	16, 17, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1,	  /* temp1-temp12 */
+	-1, -1,						  /* intr0-intr1  */
+};
+
+static const u16 NCT5525_REG_BEEP[NUM_REG_BEEP] = { 0 };
+static const s8 NCT5525_BEEP_BITS[NUM_BEEP_BITS] = {
+	[0 ... NUM_BEEP_BITS - 1] = -1,
+};
+
 /* NCT6112D/NCT6114D/NCT6116D specific data */
 
 static const u16 NCT6116_REG_FAN[] = { 0x20, 0x22, 0x24, 0x26, 0x28 };
@@ -1034,6 +1063,10 @@ static const u16 scale_in_6126[10] = {
 	800, 800, 1600, 1600, 800, 800, 1600, 1600, 1600, 800
 };
 
+static const u16 scale_in_5525[8] = {
+	800, 1600, 1600, 800, 1600, 1600, 1600, 800
+};
+
 static inline long in_from_reg(u8 reg, u8 nr, const u16 *scales)
 {
 	return DIV_ROUND_CLOSEST(reg * scales[nr], 100);
@@ -1191,6 +1224,10 @@ bool nct6775_reg_is_word_sized(struct nct6775_data *data, u16 reg)
 		  (reg >= 0x59 && reg < 0x69 && (reg & 1)) ||
 		  reg == 0xe0 || reg == 0xe2 || reg == 0xe4 ||
 		  reg == 0x111 || reg == 0x121 || reg == 0x131;
+	case nct5525:
+		return reg == 0x20 || reg == 0x22 || reg == 0x28 ||
+		  reg == 0x59 || reg == 0x5b || reg == 0xe0 || reg == 0xe2 ||
+		  reg == 0xe8 || reg == 0x111 || reg == 0x121;
 	case nct6116:
 	case nct6126:
 		return reg == 0x20 || reg == 0x22 || reg == 0x24 ||
@@ -1574,6 +1611,7 @@ static int nct6775_update_pwm_limits(struct device *dev)
 			data->auto_pwm[i][data->auto_pwm_num] = 0xff;
 			break;
 		case nct6106:
+		case nct5525:
 		case nct6116:
 		case nct6126:
 		case nct6779:
@@ -1955,6 +1993,8 @@ static umode_t nct6775_in_is_visible(struct kobject *kobj,
 
 	if (nr == 1 && data->ALARM_BITS[in] == -1)
 		return 0;
+	if (nr == 2 && data->BEEP_BITS[in] == -1)
+		return 0;
 
 	if (!(data->have_in & BIT(in)))
 		return 0;
@@ -2398,8 +2438,12 @@ static umode_t nct6775_temp_is_visible(struct kobject *kobj,
 	if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
 		return 0;				/* alarm */
 
-	if (nr == 3 && find_temp_source(data, temp, data->num_temp_beeps) < 0)
-		return 0;				/* beep */
+	if (nr == 3) {
+		int source = find_temp_source(data, temp, data->num_temp_beeps);
+
+		if (source < 0 || data->BEEP_BITS[source + TEMP_ALARM_BASE] == -1)
+			return 0;			/* beep */
+	}
 
 	if (nr == 4 && !data->reg_temp[1][temp])	/* max */
 		return 0;
@@ -3240,6 +3284,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
 		case nct6776:
 			break; /* always enabled, nothing to do */
 		case nct6106:
+		case nct5525:
 		case nct6116:
 		case nct6126:
 		case nct6779:
@@ -3640,6 +3685,87 @@ int nct6775_probe(struct device *dev, struct nct6775_data *data,
 		reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
 		reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
 
+		break;
+	case nct5525:
+		data->in_num = 8;
+		data->scale_in = scale_in_5525;
+		data->pwm_num = 2;
+		data->auto_pwm_num = 4;
+		data->temp_fixed_num = 3;
+		data->num_temp_alarms = 3;
+		data->num_temp_beeps = 0;
+
+		data->ALARM_BITS = NCT5525_ALARM_BITS;
+		data->BEEP_BITS = NCT5525_BEEP_BITS;
+
+		data->fan_from_reg = fan_from_reg13;
+		data->fan_from_reg_min = fan_from_reg13;
+		data->target_temp_mask = 0xff;
+		data->tolerance_mask = 0x07;
+		data->speed_tolerance_limit = 63;
+
+		data->temp_label = nct6776_temp_label;
+		data->temp_mask = NCT6776_TEMP_MASK;
+		data->virt_temp_mask = NCT6776_VIRT_TEMP_MASK;
+
+		data->REG_VBAT = NCT6106_REG_VBAT;
+		data->REG_DIODE = NCT6106_REG_DIODE;
+		data->DIODE_MASK = NCT6106_DIODE_MASK;
+		data->REG_VIN = NCT5525_REG_IN;
+		data->REG_IN_MINMAX[0] = NCT5525_REG_IN_MIN;
+		data->REG_IN_MINMAX[1] = NCT5525_REG_IN_MAX;
+		data->REG_TARGET = NCT6106_REG_TARGET;
+		data->REG_FAN = NCT5525_REG_FAN;
+		data->REG_FAN_MODE = NCT6106_REG_FAN_MODE;
+		data->REG_FAN_MIN = NCT5525_REG_FAN_MIN;
+		data->REG_FAN_PULSES = NCT5525_REG_FAN_PULSES;
+		data->FAN_PULSE_SHIFT = NCT5525_FAN_PULSE_SHIFT;
+		data->REG_FAN_TIME[0] = NCT6106_REG_FAN_STOP_TIME;
+		data->REG_FAN_TIME[1] = NCT6106_REG_FAN_STEP_UP_TIME;
+		data->REG_FAN_TIME[2] = NCT6106_REG_FAN_STEP_DOWN_TIME;
+		data->REG_TOLERANCE_H = NCT6106_REG_TOLERANCE_H;
+		data->REG_PWM[0] = NCT6116_REG_PWM;
+		data->REG_PWM[1] = NCT6106_REG_FAN_START_OUTPUT;
+		data->REG_PWM[2] = NCT6106_REG_FAN_STOP_OUTPUT;
+		data->REG_PWM[5] = NCT6106_REG_WEIGHT_DUTY_STEP;
+		data->REG_PWM[6] = NCT6106_REG_WEIGHT_DUTY_BASE;
+		data->REG_PWM_READ = NCT6106_REG_PWM_READ;
+		data->REG_PWM_MODE = NCT6106_REG_PWM_MODE;
+		data->PWM_MODE_MASK = NCT6106_PWM_MODE_MASK;
+		data->REG_AUTO_TEMP = NCT6106_REG_AUTO_TEMP;
+		data->REG_AUTO_PWM = NCT6106_REG_AUTO_PWM;
+		data->REG_CRITICAL_TEMP = NCT6106_REG_CRITICAL_TEMP;
+		data->REG_CRITICAL_TEMP_TOLERANCE
+		  = NCT6106_REG_CRITICAL_TEMP_TOLERANCE;
+		data->REG_CRITICAL_PWM_ENABLE = NCT6106_REG_CRITICAL_PWM_ENABLE;
+		data->CRITICAL_PWM_ENABLE_MASK
+		  = NCT6106_CRITICAL_PWM_ENABLE_MASK;
+		data->REG_CRITICAL_PWM = NCT6106_REG_CRITICAL_PWM;
+		data->REG_TEMP_OFFSET = NCT6106_REG_TEMP_OFFSET;
+		data->REG_TEMP_SOURCE = NCT6106_REG_TEMP_SOURCE;
+		data->REG_TEMP_SEL = NCT6116_REG_TEMP_SEL;
+		data->REG_WEIGHT_TEMP_SEL = NCT6106_REG_WEIGHT_TEMP_SEL;
+		data->REG_WEIGHT_TEMP[0] = NCT6106_REG_WEIGHT_TEMP_STEP;
+		data->REG_WEIGHT_TEMP[1] = NCT6106_REG_WEIGHT_TEMP_STEP_TOL;
+		data->REG_WEIGHT_TEMP[2] = NCT6106_REG_WEIGHT_TEMP_BASE;
+		data->REG_ALARM = NCT6106_REG_ALARM;
+		data->REG_BEEP = NCT5525_REG_BEEP;
+		data->REG_TSI_TEMP = NCT6116_REG_TSI_TEMP;
+
+		reg_temp = NCT6106_REG_TEMP;
+		reg_temp_mon = NCT6106_REG_TEMP_MON;
+		num_reg_temp = 3;
+		num_reg_temp_mon = 2;
+		num_reg_tsi_temp = ARRAY_SIZE(NCT6116_REG_TSI_TEMP);
+		reg_temp_over = NCT6106_REG_TEMP_OVER;
+		reg_temp_hyst = NCT6106_REG_TEMP_HYST;
+		reg_temp_config = NCT6106_REG_TEMP_CONFIG;
+		num_reg_temp_config = 3;
+		reg_temp_alternate = NCT6106_REG_TEMP_ALTERNATE;
+		reg_temp_crit = NCT6106_REG_TEMP_CRIT;
+		reg_temp_crit_l = NCT6106_REG_TEMP_CRIT_L;
+		reg_temp_crit_h = NCT6106_REG_TEMP_CRIT_H;
+
 		break;
 	case nct6116:
 		data->in_num = 9;
diff --git a/drivers/hwmon/nct6775-i2c.c b/drivers/hwmon/nct6775-i2c.c
index 07783910c058..3efae4bf5e4a 100644
--- a/drivers/hwmon/nct6775-i2c.c
+++ b/drivers/hwmon/nct6775-i2c.c
@@ -88,6 +88,7 @@ static const struct of_device_id __maybe_unused nct6775_i2c_of_match[] = {
 	{ .compatible = "nuvoton,nct6797", .data = (void *)nct6797, },
 	{ .compatible = "nuvoton,nct6798", .data = (void *)nct6798, },
 	{ .compatible = "nuvoton,nct6799", .data = (void *)nct6799, },
+	{ .compatible = "nuvoton,nct5525", .data = (void *)nct5525, },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, nct6775_i2c_of_match);
@@ -106,6 +107,7 @@ static const struct i2c_device_id nct6775_i2c_id[] = {
 	{ .name = "nct6797", .driver_data = nct6797 },
 	{ .name = "nct6798", .driver_data = nct6798 },
 	{ .name = "nct6799", .driver_data = nct6799 },
+	{ .name = "nct5525", .driver_data = nct5525 },
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, nct6775_i2c_id);
@@ -126,8 +128,8 @@ static int nct6775_i2c_probe_init(struct nct6775_data *data)
 	 * controlling/monitoring the fans -- these are thus unlikely to be
 	 * doing anything actually useful.
 	 */
-	data->has_fan = 0x03;
-	data->has_fan_min = 0x03;
+	data->has_fan = data->kind == nct5525 ? 0x07 : 0x03;
+	data->has_fan_min = data->has_fan;
 	data->has_pwm = 0x03;
 
 	/*
diff --git a/drivers/hwmon/nct6775-platform.c b/drivers/hwmon/nct6775-platform.c
index d359c28f3e0f..3bc7a27d58a6 100644
--- a/drivers/hwmon/nct6775-platform.c
+++ b/drivers/hwmon/nct6775-platform.c
@@ -37,6 +37,7 @@ static const char * const nct6775_sio_names[] __initconst = {
 	[nct6797] = "NCT6797D",
 	[nct6798] = "NCT6798D/NCT5585D",
 	[nct6799] = "NCT6796D-S/NCT6799D-R",
+	[nct5525] = "NCT5525D",
 };
 
 static unsigned short force_id;
@@ -91,6 +92,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
 #define SIO_NCT6797_ID		0xd450
 #define SIO_NCT6798_ID		0xd428
 #define SIO_NCT6799_ID		0xd800
+#define SIO_NCT5525_ID		0xd2b0
 #define SIO_ID_MASK		0xFFF8
 
 /*
@@ -552,6 +554,8 @@ nct6775_check_fan_inputs(struct nct6775_data *data, struct nct6775_sio_data *sio
 
 		fan3pin = !(cr24 & 0x80);
 		pwm3pin = cr24 & 0x08;
+	} else if (data->kind == nct5525) {
+		fan3pin = true;
 	} else if (data->kind == nct6116) {
 		int cr1a = sio_data->sio_inb(sio_data, 0x1a);
 		int cr1b = sio_data->sio_inb(sio_data, 0x1b);
@@ -839,6 +843,8 @@ static umode_t nct6775_other_is_visible(struct kobject *kobj,
 		if (data->BEEP_BITS[INTRUSION_ALARM_BASE + index - 3] < 0)
 			return 0;
 	}
+	if (index == 5 && data->BEEP_BITS[BEEP_ENABLE_BASE] < 0)
+		return 0;
 
 	return nct6775_attr_mode(data, attr);
 }
@@ -883,6 +889,7 @@ static int nct6775_platform_probe_init(struct nct6775_data *data)
 		data->have_vid = (cr2a & 0x60) == 0x40;
 		break;
 	case nct6106:
+	case nct5525:
 	case nct6116:
 	case nct6126:
 	case nct6779:
@@ -919,6 +926,8 @@ static int nct6775_platform_probe_init(struct nct6775_data *data)
 		case nct6126:
 			tmp |= 0xe0;
 			break;
+		case nct5525:
+			break;
 		case nct6775:
 			tmp |= 0x1e;
 			break;
@@ -1072,6 +1081,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
 	case SIO_NCT6799_ID:
 		sio_data->kind = nct6799;
 		break;
+	case SIO_NCT5525_ID:
+		sio_data->kind = nct5525;
+		break;
 	default:
 		if (val != 0xffff)
 			pr_debug("unsupported chip ID: 0x%04x\n", val);
diff --git a/drivers/hwmon/nct6775.h b/drivers/hwmon/nct6775.h
index d18ac91be497..d94a1c1a31f5 100644
--- a/drivers/hwmon/nct6775.h
+++ b/drivers/hwmon/nct6775.h
@@ -5,7 +5,8 @@
 #include <linux/types.h>
 
 enum kinds { nct6106, nct6116, nct6126, nct6775, nct6776, nct6779, nct6791,
-	     nct6792, nct6793, nct6795, nct6796, nct6797, nct6798, nct6799 };
+	     nct6792, nct6793, nct6795, nct6796, nct6797, nct6798, nct6799,
+	     nct5525 };
 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
 
 #define NUM_TEMP	12	/* Max number of temp attribute sets w/ limits*/
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-11-03 19:01 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-03 13:29 [PATCH] hwmon: (nct6775) Add support for NCT5525 Anton Lundin
2026-11-03 13:42 ` sashiko-bot
2026-11-03 13:47 ` Krzysztof Kozlowski
2026-11-03 15:06 ` Guenter Roeck
2026-11-03 17:33   ` Anton Lundin
2026-11-03 19:01     ` Guenter Roeck
2026-11-03 15:07 ` Guenter Roeck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.