* [PATCH v4 0/2] Add JHB100 Fan-Tach support
@ 2026-08-30 1:19 Changhuang Liang
2026-08-30 1:19 ` [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach Changhuang Liang
2026-08-30 1:19 ` [PATCH v4 2/2] hwmon: (starfive-fan-tach) Add fan tach driver for StarFive JHB100 Changhuang Liang
0 siblings, 2 replies; 11+ messages in thread
From: Changhuang Liang @ 2026-08-30 1:19 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-hwmon, devicetree, Changhuang Liang
StarFive Fan-Tach controller can support up to 16 fan tach input.
The series has been tested on the EVB1 board.
Change since v3:
PATCH 2:
- writing 0 to INT_EN before touching the STATUS and requesting the IRQ.
v3: https://lore.kernel.org/all/20260824030234.9321-1-changhuang.liang@starfivetech.com/
v2: https://lore.kernel.org/all/20260819091601.41077-1-changhuang.liang@starfivetech.com/
v1: https://lore.kernel.org/all/20260428082337.743546-1-changhuang.liang@starfivetech.com/
Changhuang Liang (2):
dt-bindings: hwmon: Add starfive,jhb100-fan-tach
hwmon: (starfive-fan-tach) Add fan tach driver for StarFive JHB100
.../hwmon/starfive,jhb100-fan-tach.yaml | 93 +++
Documentation/hwmon/index.rst | 1 +
Documentation/hwmon/starfive-fan-tach.rst | 38 ++
MAINTAINERS | 8 +
drivers/hwmon/Kconfig | 14 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/starfive-fan-tach.c | 542 ++++++++++++++++++
7 files changed, 697 insertions(+)
create mode 100644 Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
create mode 100644 Documentation/hwmon/starfive-fan-tach.rst
create mode 100644 drivers/hwmon/starfive-fan-tach.c
--
2.25.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach
2026-08-30 1:19 [PATCH v4 0/2] Add JHB100 Fan-Tach support Changhuang Liang
@ 2026-08-30 1:19 ` Changhuang Liang
2026-08-30 3:56 ` sashiko-bot
2026-08-31 16:32 ` Conor Dooley
2026-08-30 1:19 ` [PATCH v4 2/2] hwmon: (starfive-fan-tach) Add fan tach driver for StarFive JHB100 Changhuang Liang
1 sibling, 2 replies; 11+ messages in thread
From: Changhuang Liang @ 2026-08-30 1:19 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-hwmon, devicetree, Changhuang Liang
Add compatible "starfive,jhb100-fan-tach" for StarFive JHB100 Fan-Tach
controller.
Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
---
.../hwmon/starfive,jhb100-fan-tach.yaml | 93 +++++++++++++++++++
1 file changed, 93 insertions(+)
create mode 100644 Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
diff --git a/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml b/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
new file mode 100644
index 000000000000..1dcd4932768f
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwmon/starfive,jhb100-fan-tach.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JHB100 Fan-Tach controller
+
+maintainers:
+ - Changhuang Liang <changhuang.liang@starfivetech.com>
+
+description:
+ The StarFive Fan-Tach controller can support up to 16 fan tach input.
+
+properties:
+ compatible:
+ enum:
+ - starfive,jhb100-fan-tach
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+patternProperties:
+ "^fan@[0-9a-f]+$":
+ $ref: fan-common.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ reg:
+ description:
+ PWM channel index. The driver allows two fans to share the same
+ PWM channel, or each fan to use a dedicated channel.
+ maximum: 15
+
+ tach-ch:
+ description:
+ The tachometer channel(s) wired to the fan(s) driven by this PWM
+ channel. Integer values in the range 0-15.
+ minItems: 1
+ maxItems: 2
+ items:
+ maximum: 15
+
+ required:
+ - reg
+ - tach-ch
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - resets
+ - interrupts
+
+additionalProperties: false
+
+examples:
+ - |
+ fan-controller@11be0000 {
+ compatible = "starfive,jhb100-fan-tach";
+ reg = <0x11be0000 0x400>;
+ interrupts = <128>;
+ clocks = <&per2crg 33>;
+ resets = <&per2crg 5>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fan@0 {
+ reg = <0x0>;
+ tach-ch = /bits/ 8 <0x0 0x8>;
+ pulses-per-revolution = <2>;
+ };
+ fan@1 {
+ reg = <0x1>;
+ tach-ch = /bits/ 8 <0x1>;
+ pulses-per-revolution = <2>;
+ };
+ };
--
2.25.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v4 2/2] hwmon: (starfive-fan-tach) Add fan tach driver for StarFive JHB100
2026-08-30 1:19 [PATCH v4 0/2] Add JHB100 Fan-Tach support Changhuang Liang
2026-08-30 1:19 ` [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach Changhuang Liang
@ 2026-08-30 1:19 ` Changhuang Liang
2026-08-30 3:58 ` sashiko-bot
1 sibling, 1 reply; 11+ messages in thread
From: Changhuang Liang @ 2026-08-30 1:19 UTC (permalink / raw)
To: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-kernel, linux-hwmon, devicetree, Changhuang Liang
Add fan tach driver for StarFive JHB100 SoC.
The controller supports up to 16 independent fan tachometer inputs and
reports fan speed in RPM through the hwmon sysfs interface, along with
stall and low-speed alarms.
For this controller, the special clock and reset operation sequence is:
probe: clk_prepare_enable() then reset_control_deassert()
remove: clk_disable_unprepare() then reset_control_assert()
Co-developed-by: William Qiu <william.qiu@starfivetech.com>
Signed-off-by: William Qiu <william.qiu@starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
---
Documentation/hwmon/index.rst | 1 +
Documentation/hwmon/starfive-fan-tach.rst | 38 ++
MAINTAINERS | 8 +
drivers/hwmon/Kconfig | 14 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/starfive-fan-tach.c | 542 ++++++++++++++++++++++
6 files changed, 604 insertions(+)
create mode 100644 Documentation/hwmon/starfive-fan-tach.rst
create mode 100644 drivers/hwmon/starfive-fan-tach.c
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 29130df44d12..0d64e4cf1051 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -253,6 +253,7 @@ Hardware Monitoring Kernel Drivers
smsc47m1
sparx5-temp
spd5118
+ starfive-fan-tach
stpddc60
surface_fan
sy7636a-hwmon
diff --git a/Documentation/hwmon/starfive-fan-tach.rst b/Documentation/hwmon/starfive-fan-tach.rst
new file mode 100644
index 000000000000..1931472993c9
--- /dev/null
+++ b/Documentation/hwmon/starfive-fan-tach.rst
@@ -0,0 +1,38 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver starfive-fan-tach
+===============================
+
+Supported chips:
+
+ * StarFive JHB100
+
+ Prefix: 'starfive_fan_tach'
+
+ Addresses scanned: -
+
+Authors:
+ - Changhuang Liang <changhuang.liang@starfivetech.com>
+
+Description
+-----------
+
+This driver implements support for the fan tachometer controller found on
+the StarFive JHB100 SoC. The controller supports up to 16 independent fan
+tachometer inputs. Each tachometer channel measures the number of pulses
+within a fixed 100 ms window.
+
+Sysfs entries
+-------------
+
+===================== =======================================================
+fan[1-16]_input Fan speed in RPM (read-only), without a fan connected,
+ reading this value can be significantly slow.
+fan[1-16]_min Lower fan speed limit in RPM (read/write)
+fan[1-16]_enable Enable/disable the tachometer channel (read/write)
+fan[1-16]_fault Fan stall indication (read-only), with the fan running
+ normally, reading this value can be significantly slow.
+fan[1-16]_min_alarm Fan speed below fan[1-16]_min (read-only), when
+ fan[1-16]_input is greater than or equal fan[1-16]_min,
+ reading this value can be significantly slow.
+===================== =======================================================
diff --git a/MAINTAINERS b/MAINTAINERS
index c545aa121d51..83318d2e3e2e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25897,6 +25897,14 @@ S: Supported
F: Documentation/devicetree/bindings/interrupt-controller/starfive,jhb100-intc.yaml
F: drivers/irqchip/irq-starfive-jhb100-intc.c
+STARFIVE JHB100 FAN-TACH DRIVER
+M: Changhuang Liang <changhuang.liang@starfivetech.com>
+L: linux-hwmon@vger.kernel.org
+S: Supported
+F: Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
+F: Documentation/hwmon/starfive-fan-tach.rst
+F: drivers/hwmon/starfive-fan-tach.c
+
STATIC BRANCH/CALL
M: Peter Zijlstra <peterz@infradead.org>
M: Josh Poimboeuf <jpoimboe@kernel.org>
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 5c2d3ff5fce8..2c0000f8e777 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -2383,6 +2383,20 @@ config SENSORS_SPD5118_DETECT
If unsure, say Y.
+config SENSORS_STARFIVE_FAN_TACH
+ tristate "StarFive Fan-Tach driver"
+ depends on ARCH_STARFIVE || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ This driver provides support for the fan tachometer controller
+ found on StarFive SoCs such as the JHB100. The controller supports
+ up to 16 independent fan tachometer inputs and reports fan speed
+ in RPM through the hwmon sysfs interface, along with stall and
+ low-speed alarms.
+
+ This driver can also be built as a module. If so, the module
+ will be called starfive-fan-tach.
+
config SENSORS_TC74
tristate "Microchip TC74"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 63effc0ab8d1..80b2704b94e5 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -223,6 +223,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o
obj-$(CONFIG_SENSORS_SPD5118) += spd5118.o
+obj-$(CONFIG_SENSORS_STARFIVE_FAN_TACH) += starfive-fan-tach.o
obj-$(CONFIG_SENSORS_STTS751) += stts751.o
obj-$(CONFIG_SENSORS_SURFACE_FAN)+= surface_fan.o
obj-$(CONFIG_SENSORS_SURFACE_TEMP)+= surface_temp.o
diff --git a/drivers/hwmon/starfive-fan-tach.c b/drivers/hwmon/starfive-fan-tach.c
new file mode 100644
index 000000000000..d2f539cbaee5
--- /dev/null
+++ b/drivers/hwmon/starfive-fan-tach.c
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * FAN-TACH controller driver for StarFive JHB100
+ *
+ * Copyright (C) 2018-2026 StarFive Technology Co., Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/hwmon.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+
+#define STARFIVE_FAN_TACH_CH 16
+
+/* Fan-tach register offest */
+#define STARFIVE_FAN_TACH_STATUS 0x0c
+
+#define STARFIVE_FAN_TACH_SPEED(ch) (((ch) * 0x04) + 0x10)
+#define STARFIVE_FAN_TACH_SPEED_VALID BIT(31)
+#define STARFIVE_FAN_TACH_VALUE_MASK GENMASK(30, 0)
+
+#define STARFIVE_FAN_TACH_THRESHOLD(ch) (((ch) * 0x04) + 0x50)
+
+#define STARFIVE_FAN_TACH_INT_EN 0x90
+#define STARFIVE_FAN_TACH_STALL_INT_MASK GENMASK(15, 0)
+#define STARFIVE_FAN_TACH_SLOW_INT_MASK GENMASK(31, 16)
+#define STARFIVE_FAN_TACH_STALL_INT(ch) BIT(ch)
+#define STARFIVE_FAN_TACH_SLOW_INT(ch) (BIT(ch) << 16)
+
+#define STARFIVE_FAN_TACH_MEASURE_TIME 0x94
+
+#define STARFIVE_FAN_TACH_CH_EN 0x98
+#define STARFIVE_FAN_TACH_EN(ch) BIT(ch)
+
+#define STARFIVE_FAN_DEFAULT_PULSE_PR 2
+#define STARFIVE_FAN_DEFAULT_MEASURE_RATIO 10
+#define STARFIVE_FAN_DEFAULT_RPM_PAUSE_TIME (60 * STARFIVE_FAN_DEFAULT_MEASURE_RATIO)
+
+#define STARFIVE_FAN_TACH_TIMEOUT \
+ (USEC_PER_SEC / STARFIVE_FAN_DEFAULT_MEASURE_RATIO)
+
+#define STARFIVE_FAN_TACH_TIMEOUT_JIFFIES \
+ (msecs_to_jiffies(1000) / STARFIVE_FAN_DEFAULT_MEASURE_RATIO)
+
+#define FAN_ATTRIBUTE_SET \
+ (HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ENABLE | \
+ HWMON_F_FAULT | HWMON_F_MIN_ALARM)
+
+struct starfive_fan_tach_data {
+ void __iomem *regs;
+ struct reset_control *rst;
+ struct clk *clk;
+ bool tach_present[STARFIVE_FAN_TACH_CH];
+ unsigned long clk_rate; /* APB clock frequency */
+ u8 pulses_per_rev[STARFIVE_FAN_TACH_CH];
+ struct completion comp_stall[STARFIVE_FAN_TACH_CH];
+ struct completion comp_slow[STARFIVE_FAN_TACH_CH];
+ u8 fan_stall[STARFIVE_FAN_TACH_CH];
+ u8 fan_slow[STARFIVE_FAN_TACH_CH];
+ u32 armed_stall;
+ u32 armed_slow;
+ /* protects fan_stall[]/fan_slow[]/armed_* and the STATUS register */
+ spinlock_t lock;
+};
+
+static void starfive_fan_tach_ch_enable(struct starfive_fan_tach_data *priv, u8 tach_ch,
+ bool enable)
+{
+ if (enable) {
+ writel(readl(priv->regs + STARFIVE_FAN_TACH_CH_EN) |
+ STARFIVE_FAN_TACH_EN(tach_ch),
+ priv->regs + STARFIVE_FAN_TACH_CH_EN);
+ } else {
+ writel(readl(priv->regs + STARFIVE_FAN_TACH_CH_EN) &
+ ~(STARFIVE_FAN_TACH_EN(tach_ch)),
+ priv->regs + STARFIVE_FAN_TACH_CH_EN);
+ }
+}
+
+static void starfive_fan_tach_ch_stall_unmask(struct starfive_fan_tach_data *priv, u8 tach_ch,
+ bool unmask)
+{
+ if (unmask) {
+ writel(readl(priv->regs + STARFIVE_FAN_TACH_INT_EN) |
+ STARFIVE_FAN_TACH_STALL_INT(tach_ch),
+ priv->regs + STARFIVE_FAN_TACH_INT_EN);
+ } else {
+ writel(readl(priv->regs + STARFIVE_FAN_TACH_INT_EN) &
+ ~STARFIVE_FAN_TACH_STALL_INT(tach_ch),
+ priv->regs + STARFIVE_FAN_TACH_INT_EN);
+ }
+}
+
+static void starfive_fan_tach_ch_slow_unmask(struct starfive_fan_tach_data *priv, u8 tach_ch,
+ bool unmask)
+{
+ if (unmask) {
+ writel(readl(priv->regs + STARFIVE_FAN_TACH_INT_EN) |
+ STARFIVE_FAN_TACH_SLOW_INT(tach_ch),
+ priv->regs + STARFIVE_FAN_TACH_INT_EN);
+ } else {
+ writel(readl(priv->regs + STARFIVE_FAN_TACH_INT_EN) &
+ ~STARFIVE_FAN_TACH_SLOW_INT(tach_ch),
+ priv->regs + STARFIVE_FAN_TACH_INT_EN);
+ }
+}
+
+static u32 starfive_fan_tach_rpm_to_val(struct starfive_fan_tach_data *priv, u8 tach_ch, u32 rpm)
+{
+ u64 tach_val;
+ u8 ppr;
+
+ ppr = priv->pulses_per_rev[tach_ch];
+
+ tach_val = (u64)rpm * ppr;
+ tach_val = div_u64(tach_val, STARFIVE_FAN_DEFAULT_RPM_PAUSE_TIME);
+
+ return min_t(u64, tach_val, STARFIVE_FAN_TACH_VALUE_MASK);
+}
+
+static long starfive_fan_tach_val_to_rpm(struct starfive_fan_tach_data *priv, u8 tach_ch,
+ u32 tach_val)
+{
+ u64 rpm;
+ u8 ppr;
+
+ ppr = priv->pulses_per_rev[tach_ch];
+
+ rpm = (u64)tach_val * STARFIVE_FAN_DEFAULT_RPM_PAUSE_TIME;
+
+ return div_u64(rpm, ppr);
+}
+
+static int starfive_fan_tach_get_rpm(struct starfive_fan_tach_data *priv,
+ u8 tach_ch, long *rpm)
+{
+ u32 val;
+ int ret;
+
+ ret = readl_poll_timeout(priv->regs + STARFIVE_FAN_TACH_SPEED(tach_ch),
+ val, val & STARFIVE_FAN_TACH_SPEED_VALID,
+ 100, STARFIVE_FAN_TACH_TIMEOUT);
+ if (ret)
+ return -ENODATA;
+
+ val = FIELD_GET(STARFIVE_FAN_TACH_VALUE_MASK, val);
+ if (!val) {
+ /* Sampling = 0 may mean no valid capture; wait 1.5 more cycles for valid read. */
+ fsleep(STARFIVE_FAN_TACH_TIMEOUT + STARFIVE_FAN_TACH_TIMEOUT / 2);
+ ret = readl_poll_timeout(priv->regs + STARFIVE_FAN_TACH_SPEED(tach_ch),
+ val, val & STARFIVE_FAN_TACH_SPEED_VALID,
+ 100, STARFIVE_FAN_TACH_TIMEOUT);
+ if (ret)
+ return -ENODATA;
+
+ val = FIELD_GET(STARFIVE_FAN_TACH_VALUE_MASK, val);
+ }
+
+ *rpm = starfive_fan_tach_val_to_rpm(priv, tach_ch, val);
+
+ return 0;
+}
+
+static long starfive_fan_tach_get_rpm_threshold(struct starfive_fan_tach_data *priv,
+ u8 tach_ch)
+{
+ u32 val;
+
+ val = readl(priv->regs + STARFIVE_FAN_TACH_THRESHOLD(tach_ch));
+
+ val = FIELD_GET(STARFIVE_FAN_TACH_VALUE_MASK, val);
+
+ return starfive_fan_tach_val_to_rpm(priv, tach_ch, val);
+}
+
+static void starfive_set_tach_rpm_threshold(struct starfive_fan_tach_data *priv,
+ u8 tach_ch, u32 val)
+{
+ u32 reg_val;
+
+ reg_val = starfive_fan_tach_rpm_to_val(priv, tach_ch, val);
+ reg_val = clamp_val(reg_val, 1, STARFIVE_FAN_TACH_VALUE_MASK);
+
+ writel(reg_val, priv->regs + STARFIVE_FAN_TACH_THRESHOLD(tach_ch));
+}
+
+static bool starfive_fan_tach_get_ch_en(struct starfive_fan_tach_data *priv,
+ u8 tach_ch)
+{
+ u32 enable;
+
+ enable = readl(priv->regs + STARFIVE_FAN_TACH_CH_EN);
+
+ return !!(enable & STARFIVE_FAN_TACH_EN(tach_ch));
+}
+
+static int starfive_fan_tach_hwmon_read(struct device *dev,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel, long *val)
+{
+ struct starfive_fan_tach_data *priv = dev_get_drvdata(dev);
+ int ret = 0;
+
+ switch (attr) {
+ case hwmon_fan_fault:
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ writel(STARFIVE_FAN_TACH_STALL_INT(channel),
+ priv->regs + STARFIVE_FAN_TACH_STATUS);
+ /* clear fan_stall first */
+ priv->fan_stall[channel] = 0;
+ reinit_completion(&priv->comp_stall[channel]);
+ priv->armed_stall |= BIT(channel);
+ }
+
+ starfive_fan_tach_ch_stall_unmask(priv, channel, true);
+
+ /* Waiting for hardware to measure */
+ wait_for_completion_timeout(&priv->comp_stall[channel],
+ 2 * STARFIVE_FAN_TACH_TIMEOUT_JIFFIES);
+
+ starfive_fan_tach_ch_stall_unmask(priv, channel, false);
+
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ priv->armed_stall &= ~BIT(channel);
+ *val = priv->fan_stall[channel];
+ }
+
+ break;
+ case hwmon_fan_input:
+ if (!starfive_fan_tach_get_ch_en(priv, channel))
+ return -ENODATA;
+
+ ret = starfive_fan_tach_get_rpm(priv, channel, val);
+ if (ret < 0)
+ return ret;
+
+ break;
+ case hwmon_fan_min:
+ *val = starfive_fan_tach_get_rpm_threshold(priv, channel);
+
+ break;
+ case hwmon_fan_min_alarm:
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ writel(STARFIVE_FAN_TACH_SLOW_INT(channel),
+ priv->regs + STARFIVE_FAN_TACH_STATUS);
+ /* clear fan_slow first */
+ priv->fan_slow[channel] = 0;
+ reinit_completion(&priv->comp_slow[channel]);
+ priv->armed_slow |= BIT(channel);
+ }
+
+ starfive_fan_tach_ch_slow_unmask(priv, channel, true);
+
+ /* Waiting for hardware to measure */
+ wait_for_completion_timeout(&priv->comp_slow[channel],
+ 2 * STARFIVE_FAN_TACH_TIMEOUT_JIFFIES);
+
+ starfive_fan_tach_ch_slow_unmask(priv, channel, false);
+
+ scoped_guard(spinlock_irqsave, &priv->lock) {
+ priv->armed_slow &= ~BIT(channel);
+ *val = priv->fan_slow[channel];
+ }
+
+ break;
+ case hwmon_fan_enable:
+ *val = starfive_fan_tach_get_ch_en(priv, channel);
+
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int starfive_fan_tach_hwmon_write(struct device *dev,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel, long val)
+{
+ struct starfive_fan_tach_data *priv = dev_get_drvdata(dev);
+
+ switch (attr) {
+ case hwmon_fan_min:
+ if (val < 0 || val > U32_MAX)
+ return -EINVAL;
+
+ starfive_set_tach_rpm_threshold(priv, channel, val);
+ break;
+ case hwmon_fan_enable:
+ if (val != 0 && val != 1)
+ return -EINVAL;
+
+ starfive_fan_tach_ch_enable(priv, channel, val);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static umode_t starfive_fan_tach_dev_is_visible(const void *drvdata,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct starfive_fan_tach_data *priv = drvdata;
+
+ if (!priv->tach_present[channel])
+ return 0;
+
+ switch (attr) {
+ case hwmon_fan_input:
+ case hwmon_fan_fault:
+ case hwmon_fan_min_alarm:
+ return 0444;
+ case hwmon_fan_min:
+ case hwmon_fan_enable:
+ return 0644;
+ }
+
+ return 0;
+}
+
+static const struct hwmon_ops starfive_fan_tach_ops = {
+ .is_visible = starfive_fan_tach_dev_is_visible,
+ .read = starfive_fan_tach_hwmon_read,
+ .write = starfive_fan_tach_hwmon_write
+};
+
+static const struct hwmon_channel_info *starfive_fan_tach_info[] = {
+ HWMON_CHANNEL_INFO(fan,
+ FAN_ATTRIBUTE_SET, FAN_ATTRIBUTE_SET,
+ FAN_ATTRIBUTE_SET, FAN_ATTRIBUTE_SET,
+ FAN_ATTRIBUTE_SET, FAN_ATTRIBUTE_SET,
+ FAN_ATTRIBUTE_SET, FAN_ATTRIBUTE_SET,
+ FAN_ATTRIBUTE_SET, FAN_ATTRIBUTE_SET,
+ FAN_ATTRIBUTE_SET, FAN_ATTRIBUTE_SET,
+ FAN_ATTRIBUTE_SET, FAN_ATTRIBUTE_SET,
+ FAN_ATTRIBUTE_SET, FAN_ATTRIBUTE_SET),
+ NULL
+};
+
+static const struct hwmon_chip_info starfive_fan_tach_chip_info = {
+ .ops = &starfive_fan_tach_ops,
+ .info = starfive_fan_tach_info,
+};
+
+static int starfive_fan_tach_create_fan(struct device *dev, struct device_node *child,
+ struct starfive_fan_tach_data *priv)
+{
+ u8 tach_ch[STARFIVE_FAN_TACH_CH];
+ int ret, count;
+ u32 ppr, index;
+
+ count = of_property_count_u8_elems(child, "tach-ch");
+ if (count < 1 || count > STARFIVE_FAN_TACH_CH)
+ return -EINVAL;
+
+ ret = of_property_read_u8_array(child, "tach-ch", tach_ch, count);
+ if (ret)
+ return ret;
+
+ /* Parse pulses-per-revolution, default to 2 if not specified */
+ ppr = STARFIVE_FAN_DEFAULT_PULSE_PR;
+ of_property_read_u32(child, "pulses-per-revolution", &ppr);
+
+ if (!ppr || ppr > 4)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid pulses-per-revolution %u, must be 1-4\n", ppr);
+
+ for (index = 0; index < count; index++) {
+ u8 ch = tach_ch[index];
+
+ if (ch >= STARFIVE_FAN_TACH_CH)
+ return dev_err_probe(dev, -EINVAL, "Invalid tach-ch %d\n", ch);
+
+ priv->pulses_per_rev[ch] = ppr;
+ priv->tach_present[ch] = true;
+ starfive_fan_tach_ch_enable(priv, ch, true);
+ }
+
+ return 0;
+}
+
+static irqreturn_t starfive_fan_tach_irq(int irq, void *dev_id)
+{
+ struct starfive_fan_tach_data *priv = dev_id;
+ u32 fan_status;
+ int i;
+
+ guard(spinlock)(&priv->lock);
+
+ fan_status = readl(priv->regs + STARFIVE_FAN_TACH_STATUS);
+ if (!fan_status)
+ return IRQ_NONE;
+
+ writel(fan_status, priv->regs + STARFIVE_FAN_TACH_STATUS);
+
+ for (i = 0; i < STARFIVE_FAN_TACH_CH; i++) {
+ if (!priv->tach_present[i])
+ continue;
+
+ if ((fan_status & STARFIVE_FAN_TACH_STALL_INT(i)) &&
+ (priv->armed_stall & BIT(i))) {
+ priv->fan_stall[i] = 1;
+ complete(&priv->comp_stall[i]);
+ }
+
+ if ((fan_status & STARFIVE_FAN_TACH_SLOW_INT(i)) &&
+ (priv->armed_slow & BIT(i))) {
+ priv->fan_slow[i] = 1;
+ complete(&priv->comp_slow[i]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void starfive_fan_tach_disable(void *data)
+{
+ struct starfive_fan_tach_data *priv = data;
+
+ clk_disable_unprepare(priv->clk);
+ reset_control_assert(priv->rst);
+}
+
+static int starfive_fan_tach_probe(struct platform_device *pdev)
+{
+ struct device *hwmon_dev, *dev = &pdev->dev;
+ struct starfive_fan_tach_data *priv;
+ int irq;
+ int ret;
+ u32 i;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ spin_lock_init(&priv->lock);
+
+ for (i = 0; i < STARFIVE_FAN_TACH_CH; i++) {
+ init_completion(&priv->comp_stall[i]);
+ init_completion(&priv->comp_slow[i]);
+ }
+
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs),
+ "Unable to map IO resources\n");
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "Unable to get fan tach's clock\n");
+
+ priv->rst = devm_reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(priv->rst))
+ return dev_err_probe(dev, PTR_ERR(priv->rst),
+ "Unable to get fan tach's reset\n");
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable clock\n");
+
+ priv->clk_rate = clk_get_rate(priv->clk);
+ if (!priv->clk_rate) {
+ clk_disable_unprepare(priv->clk);
+ return dev_err_probe(dev, -EINVAL, "Unable to get clock's rate\n");
+ }
+
+ ret = reset_control_deassert(priv->rst);
+ if (ret) {
+ clk_disable_unprepare(priv->clk);
+ return dev_err_probe(dev, ret, "Failed to deassert reset\n");
+ }
+
+ ret = devm_add_action_or_reset(dev, starfive_fan_tach_disable, priv);
+ if (ret)
+ return ret;
+
+ /* Mask all sources before touching status / requesting the IRQ. */
+ writel(0, priv->regs + STARFIVE_FAN_TACH_INT_EN);
+ writel(STARFIVE_FAN_TACH_STALL_INT_MASK | STARFIVE_FAN_TACH_SLOW_INT_MASK,
+ priv->regs + STARFIVE_FAN_TACH_STATUS);
+ writel(priv->clk_rate / STARFIVE_FAN_DEFAULT_MEASURE_RATIO,
+ priv->regs + STARFIVE_FAN_TACH_MEASURE_TIME);
+
+ for_each_child_of_node_scoped(dev->of_node, child) {
+ ret = starfive_fan_tach_create_fan(dev, child, priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to create fan %pOF\n", child);
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get IRQ\n");
+
+ ret = devm_request_irq(dev, irq, starfive_fan_tach_irq, 0, pdev->name, priv);
+ if (ret)
+ return ret;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, "starfive_fan_tach",
+ priv, &starfive_fan_tach_chip_info,
+ NULL);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const struct of_device_id starfive_fan_tach_of_match[] = {
+ { .compatible = "starfive,jhb100-fan-tach", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, starfive_fan_tach_of_match);
+
+static struct platform_driver starfive_fan_tach_driver = {
+ .probe = starfive_fan_tach_probe,
+ .driver = {
+ .name = "starfive-fan-tach",
+ .of_match_table = starfive_fan_tach_of_match,
+ },
+};
+
+module_platform_driver(starfive_fan_tach_driver);
+
+MODULE_AUTHOR("William Qiu <william.qiu@starfivetech.com>");
+MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>");
+MODULE_DESCRIPTION("StarFive JHB100 Fan Tach device driver");
+MODULE_LICENSE("GPL");
--
2.25.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach
2026-08-30 1:19 ` [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach Changhuang Liang
@ 2026-08-30 3:56 ` sashiko-bot
2026-08-31 16:32 ` Conor Dooley
1 sibling, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-30 3:56 UTC (permalink / raw)
To: Changhuang Liang; +Cc: linux-hwmon, devicetree, robh, conor+dt
> Add compatible "starfive,jhb100-fan-tach" for StarFive JHB100 Fan-Tach
> controller.
>
> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260830011941.40199-1-changhuang.liang@starfivetech.com?part=1
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v4 2/2] hwmon: (starfive-fan-tach) Add fan tach driver for StarFive JHB100
2026-08-30 1:19 ` [PATCH v4 2/2] hwmon: (starfive-fan-tach) Add fan tach driver for StarFive JHB100 Changhuang Liang
@ 2026-08-30 3:58 ` sashiko-bot
0 siblings, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-08-30 3:58 UTC (permalink / raw)
To: Changhuang Liang; +Cc: conor+dt, robh, devicetree, linux-hwmon
> Add fan tach driver for StarFive JHB100 SoC.
>
> The controller supports up to 16 independent fan tachometer inputs and
> reports fan speed in RPM through the hwmon sysfs interface, along with
> stall and low-speed alarms.
>
> For this controller, the special clock and reset operation sequence is:
> probe: clk_prepare_enable() then reset_control_deassert()
> remove: clk_disable_unprepare() then reset_control_assert()
>
> Co-developed-by: William Qiu <william.qiu@starfivetech.com>
> Signed-off-by: William Qiu <william.qiu@starfivetech.com>
> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260830011941.40199-1-changhuang.liang@starfivetech.com?part=2
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach
2026-08-30 1:19 ` [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach Changhuang Liang
2026-08-30 3:56 ` sashiko-bot
@ 2026-08-31 16:32 ` Conor Dooley
2026-08-31 17:54 ` Guenter Roeck
2026-09-01 1:24 ` Changhuang Liang
1 sibling, 2 replies; 11+ messages in thread
From: Conor Dooley @ 2026-08-31 16:32 UTC (permalink / raw)
To: Changhuang Liang
Cc: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel, linux-hwmon, devicetree
[-- Attachment #1: Type: text/plain, Size: 3656 bytes --]
On Sat, Aug 29, 2026 at 06:19:40PM -0700, Changhuang Liang wrote:
> Add compatible "starfive,jhb100-fan-tach" for StarFive JHB100 Fan-Tach
> controller.
>
> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
> ---
> .../hwmon/starfive,jhb100-fan-tach.yaml | 93 +++++++++++++++++++
> 1 file changed, 93 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
>
> diff --git a/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml b/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
> new file mode 100644
> index 000000000000..1dcd4932768f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
> @@ -0,0 +1,93 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/hwmon/starfive,jhb100-fan-tach.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: StarFive JHB100 Fan-Tach controller
> +
> +maintainers:
> + - Changhuang Liang <changhuang.liang@starfivetech.com>
> +
> +description:
> + The StarFive Fan-Tach controller can support up to 16 fan tach input.
> +
> +properties:
> + compatible:
> + enum:
> + - starfive,jhb100-fan-tach
> +
> + reg:
> + maxItems: 1
> +
> + clocks:
> + maxItems: 1
> +
> + resets:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + "#address-cells":
> + const: 1
> +
> + "#size-cells":
> + const: 0
> +
> +patternProperties:
> + "^fan@[0-9a-f]+$":
> + $ref: fan-common.yaml#
> + unevaluatedProperties: false
> +
> + properties:
> + reg:
> + description:
> + PWM channel index. The driver allows two fans to share the same
> + PWM channel, or each fan to use a dedicated channel.
Doesn't matter what the driver can do, the description should describe
what the hardware supports.
pw-bot: changes-requested
Does this fan-tach controller provide the PWMs?
If so (although Guenter may correct me), I think the fan-tach controller
needs to be.
If you don't do that, I think you're going to run into problems with
having multiple nodes with the same unit address when two fans share a
pwm?
I think what you're supposed to do is drop "reg" and replace it with
"pwms", but once again Guenter may correct me there.
e.g. aspeed,g6-pwm-tach.yaml
Cheers,
Conor.
> + maximum: 15
> +
> + tach-ch:
> + description:
> + The tachometer channel(s) wired to the fan(s) driven by this PWM
> + channel. Integer values in the range 0-15.
> + minItems: 1
> + maxItems: 2
> + items:
> + maximum: 15
> +
> + required:
> + - reg
> + - tach-ch
> +
> +required:
> + - compatible
> + - reg
> + - clocks
> + - resets
> + - interrupts
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + fan-controller@11be0000 {
> + compatible = "starfive,jhb100-fan-tach";
> + reg = <0x11be0000 0x400>;
> + interrupts = <128>;
> + clocks = <&per2crg 33>;
> + resets = <&per2crg 5>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + fan@0 {
> + reg = <0x0>;
> + tach-ch = /bits/ 8 <0x0 0x8>;
> + pulses-per-revolution = <2>;
> + };
> + fan@1 {
> + reg = <0x1>;
> + tach-ch = /bits/ 8 <0x1>;
> + pulses-per-revolution = <2>;
> + };
> + };
> --
> 2.25.1
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach
2026-08-31 16:32 ` Conor Dooley
@ 2026-08-31 17:54 ` Guenter Roeck
2026-09-01 10:17 ` Conor Dooley
2026-09-01 1:24 ` Changhuang Liang
1 sibling, 1 reply; 11+ messages in thread
From: Guenter Roeck @ 2026-08-31 17:54 UTC (permalink / raw)
To: Conor Dooley, Changhuang Liang
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-kernel,
linux-hwmon, devicetree
On 8/31/26 09:32, Conor Dooley wrote:
> On Sat, Aug 29, 2026 at 06:19:40PM -0700, Changhuang Liang wrote:
>> Add compatible "starfive,jhb100-fan-tach" for StarFive JHB100 Fan-Tach
>> controller.
>>
>> Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
>> ---
>> .../hwmon/starfive,jhb100-fan-tach.yaml | 93 +++++++++++++++++++
>> 1 file changed, 93 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml b/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
>> new file mode 100644
>> index 000000000000..1dcd4932768f
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
>> @@ -0,0 +1,93 @@
>> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/hwmon/starfive,jhb100-fan-tach.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: StarFive JHB100 Fan-Tach controller
>> +
>> +maintainers:
>> + - Changhuang Liang <changhuang.liang@starfivetech.com>
>> +
>> +description:
>> + The StarFive Fan-Tach controller can support up to 16 fan tach input.
>> +
>> +properties:
>> + compatible:
>> + enum:
>> + - starfive,jhb100-fan-tach
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + clocks:
>> + maxItems: 1
>> +
>> + resets:
>> + maxItems: 1
>> +
>> + interrupts:
>> + maxItems: 1
>> +
>> + "#address-cells":
>> + const: 1
>> +
>> + "#size-cells":
>> + const: 0
>> +
>> +patternProperties:
>> + "^fan@[0-9a-f]+$":
>> + $ref: fan-common.yaml#
>> + unevaluatedProperties: false
>> +
>> + properties:
>> + reg:
>> + description:
>> + PWM channel index. The driver allows two fans to share the same
>> + PWM channel, or each fan to use a dedicated channel.
>
> Doesn't matter what the driver can do, the description should describe
> what the hardware supports.
> pw-bot: changes-requested
>
> Does this fan-tach controller provide the PWMs?
> If so (although Guenter may correct me), I think the fan-tach controller
> needs to be.
>
> If you don't do that, I think you're going to run into problems with
> having multiple nodes with the same unit address when two fans share a
> pwm?
>
Depends on how the controller works. Normally fan controllers have a feedback
mechanism which can be either temperature -> pwm output or fan speed -> pwm output.
I don't know how this controller works, specifically if the fan speed inputs are
internally associated with pwm outputs or if they are completely independent
of each other. If it is the latter, aspeed,g6-pwm-tach.yaml would probably
be a good baseline.
> I think what you're supposed to do is drop "reg" and replace it with
> "pwms", but once again Guenter may correct me there.
> e.g. aspeed,g6-pwm-tach.yaml
>
Sorry, when it comes to devicetree properties, I am completely clueless.
Usually the devicetree and pwm maintainers insist that all fan controllers
are modeled as pwm controllers because they have pwm outputs. My approach
is "use whatever bindings are acceptable by DT maintainers".
Guenter
> Cheers,
> Conor.
>
>> + maximum: 15
>> +
>> + tach-ch:
>> + description:
>> + The tachometer channel(s) wired to the fan(s) driven by this PWM
>> + channel. Integer values in the range 0-15.
>> + minItems: 1
>> + maxItems: 2
>> + items:
>> + maximum: 15
>> +
>> + required:
>> + - reg
>> + - tach-ch
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - clocks
>> + - resets
>> + - interrupts
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + fan-controller@11be0000 {
>> + compatible = "starfive,jhb100-fan-tach";
>> + reg = <0x11be0000 0x400>;
>> + interrupts = <128>;
>> + clocks = <&per2crg 33>;
>> + resets = <&per2crg 5>;
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + fan@0 {
>> + reg = <0x0>;
>> + tach-ch = /bits/ 8 <0x0 0x8>;
>> + pulses-per-revolution = <2>;
>> + };
>> + fan@1 {
>> + reg = <0x1>;
>> + tach-ch = /bits/ 8 <0x1>;
>> + pulses-per-revolution = <2>;
>> + };
>> + };
>> --
>> 2.25.1
>>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach
2026-08-31 16:32 ` Conor Dooley
2026-08-31 17:54 ` Guenter Roeck
@ 2026-09-01 1:24 ` Changhuang Liang
2026-09-01 10:14 ` Conor Dooley
1 sibling, 1 reply; 11+ messages in thread
From: Changhuang Liang @ 2026-09-01 1:24 UTC (permalink / raw)
To: Conor Dooley
Cc: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org,
devicetree@vger.kernel.org
Hi, Conor
Thanks for the review.
> On Sat, Aug 29, 2026 at 06:19:40PM -0700, Changhuang Liang wrote:
> > Add compatible "starfive,jhb100-fan-tach" for StarFive JHB100 Fan-Tach
> > controller.
> >
> > Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
> > ---
> > .../hwmon/starfive,jhb100-fan-tach.yaml | 93
> +++++++++++++++++++
> > 1 file changed, 93 insertions(+)
> > create mode 100644
> > Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
> >
> > diff --git
> >
> a/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yam
> > l
> >
> b/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yam
> > l
> > new file mode 100644
> > index 000000000000..1dcd4932768f
> > --- /dev/null
> > +++
> b/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach
> > +++ .yaml
> > @@ -0,0 +1,93 @@
> > +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause %YAML 1.2
> > +---
> > +$id:
> > +http://devicetree.org/schemas/hwmon/starfive,jhb100-fan-tach.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: StarFive JHB100 Fan-Tach controller
> > +
> > +maintainers:
> > + - Changhuang Liang <changhuang.liang@starfivetech.com>
> > +
> > +description:
> > + The StarFive Fan-Tach controller can support up to 16 fan tach input.
> > +
> > +properties:
> > + compatible:
> > + enum:
> > + - starfive,jhb100-fan-tach
> > +
> > + reg:
> > + maxItems: 1
> > +
> > + clocks:
> > + maxItems: 1
> > +
> > + resets:
> > + maxItems: 1
> > +
> > + interrupts:
> > + maxItems: 1
> > +
> > + "#address-cells":
> > + const: 1
> > +
> > + "#size-cells":
> > + const: 0
> > +
> > +patternProperties:
> > + "^fan@[0-9a-f]+$":
> > + $ref: fan-common.yaml#
> > + unevaluatedProperties: false
> > +
> > + properties:
> > + reg:
> > + description:
> > + PWM channel index. The driver allows two fans to share the
> same
> > + PWM channel, or each fan to use a dedicated channel.
>
> Doesn't matter what the driver can do, the description should describe what
> the hardware supports.
> pw-bot: changes-requested
> Does this fan-tach controller provide the PWMs?
> If so (although Guenter may correct me), I think the fan-tach controller needs
> to be.
>
> If you don't do that, I think you're going to run into problems with having
> multiple nodes with the same unit address when two fans share a pwm?
>
> I think what you're supposed to do is drop "reg" and replace it with "pwms",
> but once again Guenter may correct me there.
> e.g. aspeed,g6-pwm-tach.yaml
>
Perhaps I can refer to aspeed,g6-pwm-tach.yaml and change "^fan@[0-9a-f]+$" to
"^fan-[0-9]+$", which would remove the reg property. In fact, the driver does not
use reg either.
Our fan-tach controller does not include PWM. The JHB100 SoC will have a separate
PWM controller. (This controller uses the same IP as the JH7110 SoC, but there are
some differences in driver implementation.)
The JHB100 has 8 PWM channels and 16 fan tach channels.
So currently we expect the Device Tree to be configured like this:
pwm0: pwm {
compatible = "starfive,jhb100-pwm";
};
pwm1: pwm {
compatible = "starfive,jhb100-pwm";
};
pwm2: pwm {
compatible = "starfive,jhb100-pwm";
};
pwm3: pwm {
compatible = "starfive,jhb100-pwm";
};
pwm4: pwm {
compatible = "starfive,jhb100-pwm";
};
pwm5: pwm {
compatible = "starfive,jhb100-pwm";
};
pwm6: pwm {
compatible = "starfive,jhb100-pwm";
};
pwm7: pwm {
compatible = "starfive,jhb100-pwm";
};
fan0: pwm-fan0 {
compatible = "pwm-fan";
pwms = <&pwm0 0 40000 0>;
};
fan1: pwm-fan1 {
compatible = "pwm-fan";
pwms = <&pwm1 0 40000 0>;
};
fan2: pwm-fan2 {
compatible = "pwm-fan";
pwms = <&pwm2 0 40000 0>;
};
fan3: pwm-fan3 {
compatible = "pwm-fan";
pwms = <&pwm3 0 40000 0>;
};
fan4: pwm-fan4 {
compatible = "pwm-fan";
pwms = <&pwm4 0 40000 0>;
};
fan5: pwm-fan5 {
compatible = "pwm-fan";
pwms = <&pwm5 0 40000 0>;
};
fan6: pwm-fan6 {
compatible = "pwm-fan";
pwms = <&pwm6 0 40000 0>;
};
fan7: pwm-fan7 {
compatible = "pwm-fan";
pwms = <&pwm7 0 40000 0>;
};
fan-controller {
compatible = "starfive,jhb100-fan-tach";
fan@0 {
tach-ch = <0x0>, <0x8>;
};
fan@1 {
tach-ch = <0x1>, <0x9>;
};
fan@2 {
tach-ch = <0x2>, <0xa>;
};
fan@3 {
tach-ch = <0x3>, <0xb>;
};
fan@4 {
tach-ch = <0x4>, <0xc>;
};
fan@5 {
tach-ch = <0x5>, <0xd>;
};
fan@6 {
tach-ch = <0x6>, <0xe>;
};
fan@7 {
tach-ch = <0x7>, <0xf>;
};
};
> Cheers,
> Conor.
>
> > + maximum: 15
> > +
> > + tach-ch:
> > + description:
> > + The tachometer channel(s) wired to the fan(s) driven by this
> PWM
> > + channel. Integer values in the range 0-15.
> > + minItems: 1
> > + maxItems: 2
> > + items:
> > + maximum: 15
> > +
> > + required:
> > + - reg
> > + - tach-ch
> > +
> > +required:
> > + - compatible
> > + - reg
> > + - clocks
> > + - resets
> > + - interrupts
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > + - |
> > + fan-controller@11be0000 {
> > + compatible = "starfive,jhb100-fan-tach";
> > + reg = <0x11be0000 0x400>;
> > + interrupts = <128>;
> > + clocks = <&per2crg 33>;
> > + resets = <&per2crg 5>;
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + fan@0 {
> > + reg = <0x0>;
> > + tach-ch = /bits/ 8 <0x0 0x8>;
> > + pulses-per-revolution = <2>;
> > + };
> > + fan@1 {
> > + reg = <0x1>;
> > + tach-ch = /bits/ 8 <0x1>;
> > + pulses-per-revolution = <2>;
> > + };
> > + };
> > --
> > 2.25.1
> >
Best Regards,
Changhuang
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach
2026-09-01 1:24 ` Changhuang Liang
@ 2026-09-01 10:14 ` Conor Dooley
2026-09-01 15:52 ` Guenter Roeck
0 siblings, 1 reply; 11+ messages in thread
From: Conor Dooley @ 2026-09-01 10:14 UTC (permalink / raw)
To: Changhuang Liang
Cc: Guenter Roeck, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org,
devicetree@vger.kernel.org
[-- Attachment #1: Type: text/plain, Size: 2284 bytes --]
On Tue, Sep 01, 2026 at 01:24:39AM +0000, Changhuang Liang wrote:
> > On Sat, Aug 29, 2026 at 06:19:40PM -0700, Changhuang Liang wrote:
> > > +patternProperties:
> > > + "^fan@[0-9a-f]+$":
> > > + $ref: fan-common.yaml#
> > > + unevaluatedProperties: false
> > > +
> > > + properties:
> > > + reg:
> > > + description:
> > > + PWM channel index. The driver allows two fans to share the
> > same
> > > + PWM channel, or each fan to use a dedicated channel.
> >
> > Doesn't matter what the driver can do, the description should describe what
> > the hardware supports.
> > pw-bot: changes-requested
> > Does this fan-tach controller provide the PWMs?
> > If so (although Guenter may correct me), I think the fan-tach controller needs
> > to be.
> >
> > If you don't do that, I think you're going to run into problems with having
> > multiple nodes with the same unit address when two fans share a pwm?
> >
> > I think what you're supposed to do is drop "reg" and replace it with "pwms",
> > but once again Guenter may correct me there.
> > e.g. aspeed,g6-pwm-tach.yaml
> >
>
> Perhaps I can refer to aspeed,g6-pwm-tach.yaml and change "^fan@[0-9a-f]+$" to
> "^fan-[0-9]+$", which would remove the reg property. In fact, the driver does not
> use reg either.
>
> Our fan-tach controller does not include PWM. The JHB100 SoC will have a separate
> PWM controller. (This controller uses the same IP as the JH7110 SoC, but there are
> some differences in driver implementation.)
>
> The JHB100 has 8 PWM channels and 16 fan tach channels.
>
> So currently we expect the Device Tree to be configured like this:
>
> pwm0: pwm {
> compatible = "starfive,jhb100-pwm";
> };
>
>
> fan0: pwm-fan0 {
> compatible = "pwm-fan";
> pwms = <&pwm0 0 40000 0>;
> };
>
> fan-controller {
> compatible = "starfive,jhb100-fan-tach";
>
> fan@0 {
> tach-ch = <0x0>, <0x8>;
> };
Truncating this for readability, but it looks wrong to me. How does the
feedback loop work here when there's no way to determine which fan is
connected to a tach channel? The unit address of the child nodes has no
dt enforced guarantee to line up with node names of the fans or pwm
indices.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach
2026-08-31 17:54 ` Guenter Roeck
@ 2026-09-01 10:17 ` Conor Dooley
0 siblings, 0 replies; 11+ messages in thread
From: Conor Dooley @ 2026-09-01 10:17 UTC (permalink / raw)
To: Guenter Roeck
Cc: Changhuang Liang, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel, linux-hwmon, devicetree
[-- Attachment #1: Type: text/plain, Size: 5474 bytes --]
On Mon, Aug 31, 2026 at 10:54:32AM -0700, Guenter Roeck wrote:
> On 8/31/26 09:32, Conor Dooley wrote:
> > On Sat, Aug 29, 2026 at 06:19:40PM -0700, Changhuang Liang wrote:
> > > Add compatible "starfive,jhb100-fan-tach" for StarFive JHB100 Fan-Tach
> > > controller.
> > >
> > > Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
> > > ---
> > > .../hwmon/starfive,jhb100-fan-tach.yaml | 93 +++++++++++++++++++
> > > 1 file changed, 93 insertions(+)
> > > create mode 100644 Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
> > >
> > > diff --git a/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml b/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
> > > new file mode 100644
> > > index 000000000000..1dcd4932768f
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/hwmon/starfive,jhb100-fan-tach.yaml
> > > @@ -0,0 +1,93 @@
> > > +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/hwmon/starfive,jhb100-fan-tach.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: StarFive JHB100 Fan-Tach controller
> > > +
> > > +maintainers:
> > > + - Changhuang Liang <changhuang.liang@starfivetech.com>
> > > +
> > > +description:
> > > + The StarFive Fan-Tach controller can support up to 16 fan tach input.
> > > +
> > > +properties:
> > > + compatible:
> > > + enum:
> > > + - starfive,jhb100-fan-tach
> > > +
> > > + reg:
> > > + maxItems: 1
> > > +
> > > + clocks:
> > > + maxItems: 1
> > > +
> > > + resets:
> > > + maxItems: 1
> > > +
> > > + interrupts:
> > > + maxItems: 1
> > > +
> > > + "#address-cells":
> > > + const: 1
> > > +
> > > + "#size-cells":
> > > + const: 0
> > > +
> > > +patternProperties:
> > > + "^fan@[0-9a-f]+$":
> > > + $ref: fan-common.yaml#
> > > + unevaluatedProperties: false
> > > +
> > > + properties:
> > > + reg:
> > > + description:
> > > + PWM channel index. The driver allows two fans to share the same
> > > + PWM channel, or each fan to use a dedicated channel.
> >
> > Doesn't matter what the driver can do, the description should describe
> > what the hardware supports.
> > pw-bot: changes-requested
> >
> > Does this fan-tach controller provide the PWMs?
> > If so (although Guenter may correct me), I think the fan-tach controller
> > needs to be.
> >
> > If you don't do that, I think you're going to run into problems with
> > having multiple nodes with the same unit address when two fans share a
> > pwm?
> >
>
> Depends on how the controller works. Normally fan controllers have a feedback
> mechanism which can be either temperature -> pwm output or fan speed -> pwm output.
> I don't know how this controller works, specifically if the fan speed inputs are
> internally associated with pwm outputs or if they are completely independent
> of each other. If it is the latter, aspeed,g6-pwm-tach.yaml would probably
> be a good baseline.
Judging from the other reply, it probably isn't a good baseline because
this is not a pwm provider.
> > I think what you're supposed to do is drop "reg" and replace it with
> > "pwms", but once again Guenter may correct me there.
> > e.g. aspeed,g6-pwm-tach.yaml
> >
>
> Sorry, when it comes to devicetree properties, I am completely clueless.
> Usually the devicetree and pwm maintainers insist that all fan controllers
> are modeled as pwm controllers because they have pwm outputs. My approach
> is "use whatever bindings are acceptable by DT maintainers".
Would you mind taking a look at my question in the other reply about how
the feedback path works (or doesn't) in that case? My lack of
familiarity with the subsystem has me scratching my head about how the
tach would be used to adjust the pwm duty cycle with the dt setup
described there!
Thanks,
Conor.
>
> Guenter
>
> > Cheers,
> > Conor.
> >
> > > + maximum: 15
> > > +
> > > + tach-ch:
> > > + description:
> > > + The tachometer channel(s) wired to the fan(s) driven by this PWM
> > > + channel. Integer values in the range 0-15.
> > > + minItems: 1
> > > + maxItems: 2
> > > + items:
> > > + maximum: 15
> > > +
> > > + required:
> > > + - reg
> > > + - tach-ch
> > > +
> > > +required:
> > > + - compatible
> > > + - reg
> > > + - clocks
> > > + - resets
> > > + - interrupts
> > > +
> > > +additionalProperties: false
> > > +
> > > +examples:
> > > + - |
> > > + fan-controller@11be0000 {
> > > + compatible = "starfive,jhb100-fan-tach";
> > > + reg = <0x11be0000 0x400>;
> > > + interrupts = <128>;
> > > + clocks = <&per2crg 33>;
> > > + resets = <&per2crg 5>;
> > > + #address-cells = <1>;
> > > + #size-cells = <0>;
> > > +
> > > + fan@0 {
> > > + reg = <0x0>;
> > > + tach-ch = /bits/ 8 <0x0 0x8>;
> > > + pulses-per-revolution = <2>;
> > > + };
> > > + fan@1 {
> > > + reg = <0x1>;
> > > + tach-ch = /bits/ 8 <0x1>;
> > > + pulses-per-revolution = <2>;
> > > + };
> > > + };
> > > --
> > > 2.25.1
> > >
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach
2026-09-01 10:14 ` Conor Dooley
@ 2026-09-01 15:52 ` Guenter Roeck
0 siblings, 0 replies; 11+ messages in thread
From: Guenter Roeck @ 2026-09-01 15:52 UTC (permalink / raw)
To: Conor Dooley, Changhuang Liang
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel@vger.kernel.org, linux-hwmon@vger.kernel.org,
devicetree@vger.kernel.org
On 9/1/26 03:14, Conor Dooley wrote:
> On Tue, Sep 01, 2026 at 01:24:39AM +0000, Changhuang Liang wrote:
>>> On Sat, Aug 29, 2026 at 06:19:40PM -0700, Changhuang Liang wrote:
>>>> +patternProperties:
>>>> + "^fan@[0-9a-f]+$":
>>>> + $ref: fan-common.yaml#
>>>> + unevaluatedProperties: false
>>>> +
>>>> + properties:
>>>> + reg:
>>>> + description:
>>>> + PWM channel index. The driver allows two fans to share the
>>> same
>>>> + PWM channel, or each fan to use a dedicated channel.
>>>
>>> Doesn't matter what the driver can do, the description should describe what
>>> the hardware supports.
>>> pw-bot: changes-requested
>>> Does this fan-tach controller provide the PWMs?
>>> If so (although Guenter may correct me), I think the fan-tach controller needs
>>> to be.
>>>
>>> If you don't do that, I think you're going to run into problems with having
>>> multiple nodes with the same unit address when two fans share a pwm?
>>>
>>> I think what you're supposed to do is drop "reg" and replace it with "pwms",
>>> but once again Guenter may correct me there.
>>> e.g. aspeed,g6-pwm-tach.yaml
>>>
>>
>> Perhaps I can refer to aspeed,g6-pwm-tach.yaml and change "^fan@[0-9a-f]+$" to
>> "^fan-[0-9]+$", which would remove the reg property. In fact, the driver does not
>> use reg either.
>>
>> Our fan-tach controller does not include PWM. The JHB100 SoC will have a separate
>> PWM controller. (This controller uses the same IP as the JH7110 SoC, but there are
>> some differences in driver implementation.)
>>
>> The JHB100 has 8 PWM channels and 16 fan tach channels.
>>
>> So currently we expect the Device Tree to be configured like this:
>>
>> pwm0: pwm {
>> compatible = "starfive,jhb100-pwm";
>> };
>>
>
>>
>> fan0: pwm-fan0 {
>> compatible = "pwm-fan";
>> pwms = <&pwm0 0 40000 0>;
>> };
>
>>
>> fan-controller {
>> compatible = "starfive,jhb100-fan-tach";
>>
>> fan@0 {
>> tach-ch = <0x0>, <0x8>;
>> };
>
> Truncating this for readability, but it looks wrong to me. How does the
> feedback loop work here when there's no way to determine which fan is
> connected to a tach channel? The unit address of the child nodes has no
> dt enforced guarantee to line up with node names of the fans or pwm
> indices.
Normally (for other fan controllers) the fan would have a target speed.
The controller measures the speed and adjusts pwm output values until
the fan speed matches the expected value. The controller needs to know
the association between tachometer input and pwm output for this to work.
Typically (for classic fan controllers) that association is static.
In the Aspeed G6 fan controller it is dynamic/configurable.
I thought this is the case here as well, but I have no idea if that is
correct (or if there is a chip-internal feedback loop to start with).
Guenter
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-09-01 15:52 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-30 1:19 [PATCH v4 0/2] Add JHB100 Fan-Tach support Changhuang Liang
2026-08-30 1:19 ` [PATCH v4 1/2] dt-bindings: hwmon: Add starfive,jhb100-fan-tach Changhuang Liang
2026-08-30 3:56 ` sashiko-bot
2026-08-31 16:32 ` Conor Dooley
2026-08-31 17:54 ` Guenter Roeck
2026-09-01 10:17 ` Conor Dooley
2026-09-01 1:24 ` Changhuang Liang
2026-09-01 10:14 ` Conor Dooley
2026-09-01 15:52 ` Guenter Roeck
2026-08-30 1:19 ` [PATCH v4 2/2] hwmon: (starfive-fan-tach) Add fan tach driver for StarFive JHB100 Changhuang Liang
2026-08-30 3:58 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox