Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] hwmon: add Axiado AX3000 and AX3005 PWM fan support
@ 2026-08-06  9:01 Petar Stepanovic
  2026-08-06  9:01 ` [PATCH 1/2] dt-bindings: hwmon: add Axiado AX3000 and AX3005 PWM fan controller Petar Stepanovic
  2026-08-06  9:01 ` [PATCH 2/2] hwmon: add Axiado AX3000 and AX3005 PWM fan controller driver Petar Stepanovic
  0 siblings, 2 replies; 7+ messages in thread
From: Petar Stepanovic @ 2026-08-06  9:01 UTC (permalink / raw)
  To: Petar Stepanovic, Akhila Kavi, Prasad Bolisetty, Guenter Roeck,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Harshit Shah,
	Uwe Kleine-König, Tzu-Hao Wei, Karthikeyan Mitran,
	Jonathan Corbet, Shuah Khan
  Cc: linux-hwmon, devicetree, linux-arm-kernel, linux-kernel,
	linux-pwm, linux-doc

This series adds support for the fan controller found on the Axiado
AX3000 and AX3005 SoCs.

The controller provides a hardware tachometer block for measuring the
rotational speed of one fan. Fan speed is controlled through a PWM
signal supplied by an external PWM controller.

The tachometer counts fan pulses in hardware and reports the accumulated
count through an MMIO register when the measurement interval expires.
The generic pwm-fan driver counts tachometer interrupts in software and
therefore cannot directly operate this hardware counter block.

The driver registers with the hwmon subsystem and provides the
following standard sysfs attributes:

  - fan1_input for the measured fan speed in RPM
  - pwm1 for fan-speed control in the range 0 to 255

The number of tachometer pulses generated per fan revolution can be
configured using the pulses-per-revolution devicetree property. If the
property is not specified, the driver uses two pulses per revolution.

The series includes:

  - Devicetree binding documentation
  - Axiado PWM fan hwmon driver
  - hwmon driver documentation
  - MAINTAINERS entry

The driver was tested on AX3000 and AX3005 platforms.

Signed-off-by: Petar Stepanovic <pstepanovic@axiado.com>
---
Petar Stepanovic (2):
      dt-bindings: hwmon: add Axiado AX3000 and AX3005 PWM fan controller
      hwmon: add Axiado AX3000 and AX3005 PWM fan controller driver

 .../bindings/hwmon/axiado,ax3000-pwm-fan.yaml      |  68 ++++
 Documentation/hwmon/axiado-pwm-fan.rst             |  38 ++
 Documentation/hwmon/index.rst                      |   1 +
 MAINTAINERS                                        |  10 +
 drivers/hwmon/Kconfig                              |  12 +
 drivers/hwmon/Makefile                             |   1 +
 drivers/hwmon/axiado-pwm-fan.c                     | 389 +++++++++++++++++++++
 7 files changed, 519 insertions(+)
---
base-commit: 28807a684f870463e059fbc8cb22f5b780b94fe4
change-id: 20260520-axiado-ax3000-pwm-fan-36a89de6db61

Best regards,
-- 
Petar Stepanovic <pstepanovic@axiado.com>



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

* [PATCH 1/2] dt-bindings: hwmon: add Axiado AX3000 and AX3005 PWM fan controller
  2026-08-06  9:01 [PATCH 0/2] hwmon: add Axiado AX3000 and AX3005 PWM fan support Petar Stepanovic
@ 2026-08-06  9:01 ` Petar Stepanovic
  2026-08-06 10:41   ` Rob Herring (Arm)
  2026-08-06 13:16   ` Rob Herring
  2026-08-06  9:01 ` [PATCH 2/2] hwmon: add Axiado AX3000 and AX3005 PWM fan controller driver Petar Stepanovic
  1 sibling, 2 replies; 7+ messages in thread
From: Petar Stepanovic @ 2026-08-06  9:01 UTC (permalink / raw)
  To: Petar Stepanovic, Akhila Kavi, Prasad Bolisetty, Guenter Roeck,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Harshit Shah,
	Uwe Kleine-König, Tzu-Hao Wei, Karthikeyan Mitran,
	Jonathan Corbet, Shuah Khan
  Cc: linux-hwmon, devicetree, linux-arm-kernel, linux-kernel,
	linux-pwm, linux-doc

Add a Devicetree binding for the PWM fan controller found on the
Axiado AX3000 and AX3005 SoCs.

The controller measures fan speed using a hardware tachometer block.
Fan speed is controlled through a PWM signal supplied by an external
PWM controller.

Add a MAINTAINERS entry for the binding.

Signed-off-by: Petar Stepanovic <pstepanovic@axiado.com>
---
 .../bindings/hwmon/axiado,ax3000-pwm-fan.yaml      | 68 ++++++++++++++++++++++
 MAINTAINERS                                        |  8 +++
 2 files changed, 76 insertions(+)

diff --git a/Documentation/devicetree/bindings/hwmon/axiado,ax3000-pwm-fan.yaml b/Documentation/devicetree/bindings/hwmon/axiado,ax3000-pwm-fan.yaml
new file mode 100644
index 000000000000..a985f49bbdcd
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/axiado,ax3000-pwm-fan.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/hwmon/axiado,ax3000-pwm-fan.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Axiado AX3000 and AX3005 PWM Fan Controller
+
+maintainers:
+  - Petar Stepanovic <pstepanovic@axiado.com>
+  - Akhila Kavi <akavi@axiado.com>
+  - Prasad Bolisetty <pbolisetty@axiado.com>
+
+description:
+  The Axiado AX3000 and AX3005 fan controllers use a hardware tachometer
+  block to measure fan speed. Fan speed is controlled through a PWM signal
+  supplied by an external PWM controller.
+
+properties:
+  compatible:
+    oneOf:
+      - const: axiado,ax3000-pwm-fan
+      - items:
+          - const: axiado,ax3005-pwm-fan
+          - const: axiado,ax3000-pwm-fan
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  pwms:
+    maxItems: 1
+    description:
+      PWM specifier used to control fan speed.
+
+  pulses-per-revolution:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 1
+    default: 2
+    description:
+      Number of tachometer pulses generated per fan revolution.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - pwms
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    fan@33001400 {
+        compatible = "axiado,ax3000-pwm-fan";
+        reg = <0x0 0x33001400 0x0 0x400>;
+        interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clk>;
+        pwms = <&pwm0 0 400>;
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index a674e36529f7..f528b1a42e0f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4457,6 +4457,14 @@ W:	https://ez.analog.com/linux-software-drivers
 F:	Documentation/devicetree/bindings/pwm/adi,axi-pwmgen.yaml
 F:	drivers/pwm/pwm-axi-pwmgen.c
 
+AXIADO PWM FAN CONTROLLER DRIVER
+M:	Petar Stepanovic <pstepanovic@axiado.com>
+M:	Akhila Kavi <akavi@axiado.com>
+M:	Prasad Bolisetty <pbolisetty@axiado.com>
+L:	linux-hwmon@vger.kernel.org
+S:	Supported
+F:	Documentation/devicetree/bindings/hwmon/axiado,ax3000-pwm-fan.yaml
+
 AXIADO SPI DB DRIVER
 M:	Vladimir Moravcevic <vmoravcevic@axiado.com>
 M:	Tzu-Hao Wei <twei@axiado.com>

-- 
2.34.1



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

* [PATCH 2/2] hwmon: add Axiado AX3000 and AX3005 PWM fan controller driver
  2026-08-06  9:01 [PATCH 0/2] hwmon: add Axiado AX3000 and AX3005 PWM fan support Petar Stepanovic
  2026-08-06  9:01 ` [PATCH 1/2] dt-bindings: hwmon: add Axiado AX3000 and AX3005 PWM fan controller Petar Stepanovic
@ 2026-08-06  9:01 ` Petar Stepanovic
  2026-08-06 10:04   ` Uwe Kleine-König
  1 sibling, 1 reply; 7+ messages in thread
From: Petar Stepanovic @ 2026-08-06  9:01 UTC (permalink / raw)
  To: Petar Stepanovic, Akhila Kavi, Prasad Bolisetty, Guenter Roeck,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Harshit Shah,
	Uwe Kleine-König, Tzu-Hao Wei, Karthikeyan Mitran,
	Jonathan Corbet, Shuah Khan
  Cc: linux-hwmon, devicetree, linux-arm-kernel, linux-kernel,
	linux-pwm, linux-doc

Add support for the PWM fan controller found on the Axiado AX3000 and
AX3005 SoCs.

The controller uses a hardware tachometer block and interrupt to measure
fan speed. Fan speed is controlled through a PWM signal supplied by an
external PWM controller.

Register the controller with the hwmon subsystem and expose the standard
fan1_input and pwm1 attributes. The number of tachometer pulses generated
per fan revolution can be configured using the pulses-per-revolution
Devicetree property.

The driver was tested on AX3000 and AX3005 boards.

Signed-off-by: Petar Stepanovic <pstepanovic@axiado.com>
---
 Documentation/hwmon/axiado-pwm-fan.rst |  38 ++++
 Documentation/hwmon/index.rst          |   1 +
 MAINTAINERS                            |   2 +
 drivers/hwmon/Kconfig                  |  12 +
 drivers/hwmon/Makefile                 |   1 +
 drivers/hwmon/axiado-pwm-fan.c         | 389 +++++++++++++++++++++++++++++++++
 6 files changed, 443 insertions(+)

diff --git a/Documentation/hwmon/axiado-pwm-fan.rst b/Documentation/hwmon/axiado-pwm-fan.rst
new file mode 100644
index 000000000000..d110e170b0df
--- /dev/null
+++ b/Documentation/hwmon/axiado-pwm-fan.rst
@@ -0,0 +1,38 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver axiado-pwm-fan
+============================
+
+Supported chips:
+
+  * Axiado AX3000
+  * Axiado AX3005
+
+    Datasheet: Not publicly available
+
+Author:
+
+  * Petar Stepanovic <pstepanovic@axiado.com>
+
+Description
+-----------
+
+The Axiado AX3000 and AX3005 PWM fan controllers measure the rotational
+speed of one fan using a hardware tachometer block. Fan speed is controlled
+through a PWM signal supplied by an external PWM controller.
+
+The number of tachometer pulses generated per fan revolution is configured
+through the ``pulses-per-revolution`` devicetree property. If the property
+is not specified, the driver uses two pulses per revolution.
+
+Sysfs attributes
+----------------
+
+The driver provides the following standard hwmon attributes:
+
+=============== ====== =====================================================
+fan1_input      RO     Fan speed in revolutions per minute (RPM).
+
+pwm1            RW     Relative PWM control value from 0 to 255. A value of
+                       255 selects the maximum PWM duty cycle.
+=============== ====== =====================================================
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 29130df44d12..857924205861 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -51,6 +51,7 @@ Hardware Monitoring Kernel Drivers
    asus_ec_sensors
    asus_rog_ryujin
    asus_wmi_sensors
+   axiado-pwm-fan
    bcm54140
    bel-pfe
    bpa-rs600
diff --git a/MAINTAINERS b/MAINTAINERS
index f528b1a42e0f..61e7a0939002 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4464,6 +4464,8 @@ M:	Prasad Bolisetty <pbolisetty@axiado.com>
 L:	linux-hwmon@vger.kernel.org
 S:	Supported
 F:	Documentation/devicetree/bindings/hwmon/axiado,ax3000-pwm-fan.yaml
+F:	Documentation/hwmon/axiado-pwm-fan.rst
+F:	drivers/hwmon/axiado-pwm-fan.c
 
 AXIADO SPI DB DRIVER
 M:	Vladimir Moravcevic <vmoravcevic@axiado.com>
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 2bfbcc033d59..161054ba7312 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -469,6 +469,18 @@ config SENSORS_ATXP1
 	  This driver can also be built as a module. If so, the module
 	  will be called atxp1.
 
+config SENSORS_AXIADO_PWM_FAN
+	tristate "Axiado PWM fan controller"
+	depends on ARCH_AXIADO || COMPILE_TEST
+	depends on PWM
+	help
+	  This driver supports the Axiado PWM fan controller. It uses a PWM
+	  output to control fan speed and a tachometer interrupt to report fan
+	  speed as RPM through the hardware monitoring sysfs interface.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called axiado-pwm-fan.
+
 config SENSORS_CGBC
 	tristate "Congatec Board Controller Sensors"
 	depends on MFD_CGBC
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 63effc0ab8d1..78fcb22a1777 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_SENSORS_ASPEED)	+= aspeed-pwm-tacho.o
 obj-$(CONFIG_SENSORS_ASPEED_G6) += aspeed-g6-pwm-tach.o
 obj-$(CONFIG_SENSORS_ASUS_ROG_RYUJIN)	+= asus_rog_ryujin.o
 obj-$(CONFIG_SENSORS_ATXP1)	+= atxp1.o
+obj-$(CONFIG_SENSORS_AXIADO_PWM_FAN) += axiado-pwm-fan.o
 obj-$(CONFIG_SENSORS_AXI_FAN_CONTROL) += axi-fan-control.o
 obj-$(CONFIG_SENSORS_CGBC)	+= cgbc-hwmon.o
 obj-$(CONFIG_SENSORS_CHIPCAP2) += chipcap2.o
diff --git a/drivers/hwmon/axiado-pwm-fan.c b/drivers/hwmon/axiado-pwm-fan.c
new file mode 100644
index 000000000000..b15bd3513d5e
--- /dev/null
+++ b/drivers/hwmon/axiado-pwm-fan.c
@@ -0,0 +1,389 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2021-2026 Axiado Corporation.
+ */
+
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/hwmon.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define PWM_MAX	255
+
+/* TACH Register offsets */
+#define AX_TACH_CTRL_REG	0x00
+#define AX_TACH_TIMER_COUNT_REG	0x04
+#define AX_TACH_COUNT_REG	0x08
+#define AX_TACH_INT_STATUS_REG	0x0c
+
+#define AX_TACH_CTRL_ENABLE		BIT(0)
+#define AX_TACH_CTRL_INT_ENABLE		BIT(1)
+
+#define AX_TACH_INT_PENDING             BIT(0)
+
+struct axiado_pwm_fan_tach {
+	int irq;
+	u32 pulses_per_revolution;
+	u32 timer_count;
+	u32 count;
+};
+
+struct axiado_pwm_fan_ctx {
+	/* Protects PWM state and cached PWM value. */
+	struct mutex pwm_lock;
+	/* Protects tachometer count updated from interrupt context. */
+	spinlock_t tach_lock;
+	struct pwm_device *pwm;
+	struct pwm_state pwm_state;
+	void __iomem *tach_base;
+	struct axiado_pwm_fan_tach tach;
+	unsigned int pwm_value;
+};
+
+static const struct hwmon_channel_info * const pwm_fan_info[] = {
+	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT),
+	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
+	NULL
+};
+
+static irqreturn_t axiado_tach_irq_handler(int irq, void *dev)
+{
+	struct axiado_pwm_fan_ctx *ctx = dev;
+	u32 status;
+
+	status = ioread32(ctx->tach_base + AX_TACH_INT_STATUS_REG);
+
+	if (!status)
+		return IRQ_NONE;
+
+	scoped_guard(spinlock_irqsave, &ctx->tach_lock) {
+		ctx->tach.count = ioread32(ctx->tach_base + AX_TACH_COUNT_REG);
+	}
+
+	iowrite32(AX_TACH_INT_PENDING, ctx->tach_base + AX_TACH_INT_STATUS_REG);
+
+	return IRQ_HANDLED;
+}
+
+static int axiado_set_pwm(struct axiado_pwm_fan_ctx *ctx, unsigned int pwm)
+{
+	struct pwm_state state;
+	int ret;
+
+	guard(mutex)(&ctx->pwm_lock);
+
+	if (ctx->pwm_value == pwm)
+		return 0;
+
+	state = ctx->pwm_state;
+	state.duty_cycle = DIV_ROUND_UP_ULL((u64)pwm * state.period, PWM_MAX);
+	state.enabled = pwm > 0;
+
+	ret = pwm_apply_might_sleep(ctx->pwm, &state);
+	if (ret)
+		return ret;
+
+	ctx->pwm_state = state;
+	ctx->pwm_value = pwm;
+
+	return 0;
+}
+
+static int axiado_pwm_fan_write(struct device *dev,
+				enum hwmon_sensor_types type, u32 attr,
+				int channel, long val)
+{
+	struct axiado_pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+
+	if (type != hwmon_pwm || attr != hwmon_pwm_input)
+		return -EOPNOTSUPP;
+
+	if (val < 0 || val > PWM_MAX)
+		return -EINVAL;
+
+	return axiado_set_pwm(ctx, val);
+}
+
+static unsigned int axiado_tach_get_rpm(struct axiado_pwm_fan_ctx *ctx)
+{
+	u32 pulses_per_revolution = ctx->tach.pulses_per_revolution;
+	u64 pulses, rpm;
+
+	scoped_guard(spinlock_irqsave, &ctx->tach_lock)
+		pulses = ctx->tach.count;
+
+	if (!pulses_per_revolution)
+		return 0;
+
+	rpm = pulses * 60;
+	do_div(rpm, pulses_per_revolution);
+
+	return rpm;
+}
+
+static int axiado_pwm_fan_read(struct device *dev, enum hwmon_sensor_types type,
+			       u32 attr, int channel, long *val)
+{
+	struct axiado_pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+
+	switch (type) {
+	case hwmon_pwm:
+		if (attr != hwmon_pwm_input)
+			return -EOPNOTSUPP;
+
+		scoped_guard(mutex, &ctx->pwm_lock)
+			*val = ctx->pwm_value;
+
+		return 0;
+
+	case hwmon_fan:
+		if (attr != hwmon_fan_input)
+			return -EOPNOTSUPP;
+
+		*val = axiado_tach_get_rpm(ctx);
+
+		return 0;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static umode_t axiado_pwm_fan_is_visible(const void *data,
+					 enum hwmon_sensor_types type, u32 attr,
+					 int channel)
+{
+	if (type == hwmon_fan && attr == hwmon_fan_input)
+		return 0444;
+
+	if (type == hwmon_pwm && attr == hwmon_pwm_input)
+		return 0644;
+
+	return 0;
+}
+
+static const struct hwmon_ops pwm_fan_hwmon_ops = {
+	.is_visible = axiado_pwm_fan_is_visible,
+	.read = axiado_pwm_fan_read,
+	.write = axiado_pwm_fan_write,
+};
+
+static const struct hwmon_chip_info pwm_fan_chip_info = {
+	.ops = &pwm_fan_hwmon_ops,
+	.info = pwm_fan_info,
+};
+
+static int axiado_pwm_apply_disabled(struct axiado_pwm_fan_ctx *ctx)
+{
+	struct pwm_state state;
+
+	guard(mutex)(&ctx->pwm_lock);
+
+	if (!ctx->pwm_value)
+		return 0;
+
+	state = ctx->pwm_state;
+	state.duty_cycle = 0;
+	state.enabled = false;
+
+	return pwm_apply_might_sleep(ctx->pwm, &state);
+}
+
+static void axiado_pwm_disable(void *data)
+{
+	struct axiado_pwm_fan_ctx *ctx = data;
+
+	axiado_pwm_apply_disabled(ctx);
+}
+
+static void axiado_tach_enable(struct axiado_pwm_fan_ctx *ctx)
+{
+	iowrite32(AX_TACH_INT_PENDING,
+		  ctx->tach_base + AX_TACH_INT_STATUS_REG);
+	iowrite32(ctx->tach.timer_count,
+		  ctx->tach_base + AX_TACH_TIMER_COUNT_REG);
+	iowrite32(AX_TACH_CTRL_ENABLE | AX_TACH_CTRL_INT_ENABLE,
+		  ctx->tach_base + AX_TACH_CTRL_REG);
+}
+
+static void axiado_tach_disable(void *data)
+{
+	struct axiado_pwm_fan_ctx *ctx = data;
+
+	iowrite32(0, ctx->tach_base + AX_TACH_CTRL_REG);
+	iowrite32(AX_TACH_INT_PENDING,
+		  ctx->tach_base + AX_TACH_INT_STATUS_REG);
+}
+
+static int axiado_pwm_fan_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct axiado_pwm_fan_ctx *ctx;
+	unsigned long tach_clk_rate;
+	struct device *hwmon;
+	struct clk *tach_clk;
+	int ret;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	mutex_init(&ctx->pwm_lock);
+	spin_lock_init(&ctx->tach_lock);
+
+	ctx->tach_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(ctx->tach_base))
+		return PTR_ERR(ctx->tach_base);
+
+	ctx->pwm = devm_pwm_get(dev, NULL);
+	if (IS_ERR(ctx->pwm))
+		return dev_err_probe(dev, PTR_ERR(ctx->pwm),
+				     "Could not get PWM\n");
+
+	platform_set_drvdata(pdev, ctx);
+
+	pwm_init_state(ctx->pwm, &ctx->pwm_state);
+
+	if (!ctx->pwm_state.period)
+		return dev_err_probe(dev, -EINVAL, "PWM period is zero\n");
+
+	tach_clk = devm_clk_get_enabled(dev, NULL);
+	if (IS_ERR(tach_clk))
+		return dev_err_probe(dev, PTR_ERR(tach_clk),
+				     "Failed to get tachometer clock\n");
+
+	tach_clk_rate = clk_get_rate(tach_clk);
+	if (!tach_clk_rate || tach_clk_rate > U32_MAX)
+		return dev_err_probe(dev, -EINVAL,
+				     "Invalid tachometer clock rate: %lu\n",
+				     tach_clk_rate);
+
+	ctx->tach.timer_count = tach_clk_rate;
+	ctx->tach.pulses_per_revolution = 2;
+	device_property_read_u32(dev, "pulses-per-revolution",
+				 &ctx->tach.pulses_per_revolution);
+
+	if (!ctx->tach.pulses_per_revolution)
+		return dev_err_probe(dev, -EINVAL,
+				     "pulses-per-revolution cannot be zero\n");
+
+	ctx->tach.irq = platform_get_irq(pdev, 0);
+	if (ctx->tach.irq < 0)
+		return dev_err_probe(dev, ctx->tach.irq,
+				     "Failed to get tachometer IRQ\n");
+
+	ret = devm_request_irq(dev, ctx->tach.irq, axiado_tach_irq_handler, 0,
+			       dev_name(dev), ctx);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to request tach IRQ\n");
+
+	ret = devm_add_action_or_reset(dev, axiado_tach_disable, ctx);
+	if (ret)
+		return ret;
+
+	dev_dbg(dev, "Fan tachometer: irq=%d, pulses_per_revolution=%u\n",
+		ctx->tach.irq, ctx->tach.pulses_per_revolution);
+
+	axiado_tach_enable(ctx);
+
+	ret = axiado_set_pwm(ctx, PWM_MAX);
+
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to configure PWM\n");
+
+	ret = devm_add_action_or_reset(dev, axiado_pwm_disable, ctx);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to add PWM disable action\n");
+
+	hwmon = devm_hwmon_device_register_with_info(dev, "axpwmfan", ctx,
+						     &pwm_fan_chip_info, NULL);
+	if (IS_ERR(hwmon))
+		return dev_err_probe(dev, PTR_ERR(hwmon),
+				     "Failed to register hwmon device\n");
+
+	return 0;
+}
+
+static int axiado_pwm_fan_disable(struct device *dev)
+{
+	struct axiado_pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+	int ret;
+
+	ret = axiado_pwm_apply_disabled(ctx);
+	if (ret)
+		return ret;
+
+	axiado_tach_disable(ctx);
+	synchronize_irq(ctx->tach.irq);
+
+	return 0;
+}
+
+static void axiado_pwm_fan_shutdown(struct platform_device *pdev)
+{
+	struct axiado_pwm_fan_ctx *ctx = platform_get_drvdata(pdev);
+
+	/* Best effort during shutdown. */
+	axiado_pwm_apply_disabled(ctx);
+
+	axiado_tach_disable(ctx);
+	synchronize_irq(ctx->tach.irq);
+}
+
+static int axiado_pwm_fan_suspend(struct device *dev)
+{
+	return axiado_pwm_fan_disable(dev);
+}
+
+static int axiado_pwm_fan_resume(struct device *dev)
+{
+	struct axiado_pwm_fan_ctx *ctx = dev_get_drvdata(dev);
+	int ret;
+
+	axiado_tach_enable(ctx);
+
+	scoped_guard(mutex, &ctx->pwm_lock)
+		ret = pwm_apply_might_sleep(ctx->pwm, &ctx->pwm_state);
+
+	if (ret)
+		axiado_tach_disable(ctx);
+
+	return ret;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(axiado_pwm_fan_pm,
+				axiado_pwm_fan_suspend,
+				axiado_pwm_fan_resume);
+
+static const struct of_device_id axiado_pwm_fan_match[] = {
+	{ .compatible = "axiado,ax3000-pwm-fan" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, axiado_pwm_fan_match);
+
+static struct platform_driver axiado_pwm_fan_driver = {
+	.probe		= axiado_pwm_fan_probe,
+	.shutdown	= axiado_pwm_fan_shutdown,
+	.driver	= {
+		.name		= "axiado-pwm-fan",
+		.pm		= pm_sleep_ptr(&axiado_pwm_fan_pm),
+		.of_match_table	= axiado_pwm_fan_match,
+	},
+};
+
+module_platform_driver(axiado_pwm_fan_driver);
+MODULE_AUTHOR("Axiado Corporation");
+MODULE_DESCRIPTION("Axiado PWM fan controller driver");
+MODULE_LICENSE("GPL");
+

-- 
2.34.1



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

* Re: [PATCH 2/2] hwmon: add Axiado AX3000 and AX3005 PWM fan controller driver
  2026-08-06  9:01 ` [PATCH 2/2] hwmon: add Axiado AX3000 and AX3005 PWM fan controller driver Petar Stepanovic
@ 2026-08-06 10:04   ` Uwe Kleine-König
  2026-08-06 15:34     ` Guenter Roeck
  0 siblings, 1 reply; 7+ messages in thread
From: Uwe Kleine-König @ 2026-08-06 10:04 UTC (permalink / raw)
  To: Petar Stepanovic
  Cc: Akhila Kavi, Prasad Bolisetty, Guenter Roeck, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Harshit Shah, Tzu-Hao Wei,
	Karthikeyan Mitran, Jonathan Corbet, Shuah Khan, linux-hwmon,
	devicetree, linux-arm-kernel, linux-kernel, linux-pwm, linux-doc

[-- Attachment #1: Type: text/plain, Size: 1671 bytes --]

On Thu, Aug 06, 2026 at 02:01:30AM -0700, Petar Stepanovic wrote:
> +#define PWM_MAX	255

That define has a name that looks much more generic than it actually is.
Please call it AX_TACH_PWM_VAL_MAX or something similar.

> [...]
> +static int axiado_pwm_fan_read(struct device *dev, enum hwmon_sensor_types type,
> +			       u32 attr, int channel, long *val)
> +{
> +	struct axiado_pwm_fan_ctx *ctx = dev_get_drvdata(dev);
> +
> +	switch (type) {
> +	case hwmon_pwm:
> +		if (attr != hwmon_pwm_input)
> +			return -EOPNOTSUPP;
> +
> +		scoped_guard(mutex, &ctx->pwm_lock)
> +			*val = ctx->pwm_value;

If there is a hwmon lock that serializes calls to hwmon_ops::read and
hwmon_ops::write, .pwm_lock isn't needed. (Unless I miss something,
please double check. Also I'm unsure if there is such a hwmon
serialization.)

> [...]
> +static const struct of_device_id axiado_pwm_fan_match[] = {
> +	{ .compatible = "axiado,ax3000-pwm-fan" },
> +	{ },

No trailing , after the list terminator please.

> +};
> +MODULE_DEVICE_TABLE(of, axiado_pwm_fan_match);
> +
> +static struct platform_driver axiado_pwm_fan_driver = {
> +	.probe		= axiado_pwm_fan_probe,
> +	.shutdown	= axiado_pwm_fan_shutdown,
> +	.driver	= {
> +		.name		= "axiado-pwm-fan",
> +		.pm		= pm_sleep_ptr(&axiado_pwm_fan_pm),
> +		.of_match_table	= axiado_pwm_fan_match,
> +	},
> +};
> +
> +module_platform_driver(axiado_pwm_fan_driver);

Typically `module_platform_driver` follows the struct platform_driver
without a newline.

> +MODULE_AUTHOR("Axiado Corporation");
> +MODULE_DESCRIPTION("Axiado PWM fan controller driver");
> +MODULE_LICENSE("GPL");
> +

Trailing newline at end of file.

Best regards
Uwe

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 1/2] dt-bindings: hwmon: add Axiado AX3000 and AX3005 PWM fan controller
  2026-08-06  9:01 ` [PATCH 1/2] dt-bindings: hwmon: add Axiado AX3000 and AX3005 PWM fan controller Petar Stepanovic
@ 2026-08-06 10:41   ` Rob Herring (Arm)
  2026-08-06 13:16   ` Rob Herring
  1 sibling, 0 replies; 7+ messages in thread
From: Rob Herring (Arm) @ 2026-08-06 10:41 UTC (permalink / raw)
  To: Petar Stepanovic
  Cc: devicetree, Uwe Kleine-König, linux-pwm, Harshit Shah,
	linux-kernel, linux-hwmon, Krzysztof Kozlowski, Jonathan Corbet,
	Prasad Bolisetty, Shuah Khan, linux-doc, linux-arm-kernel,
	Conor Dooley, Guenter Roeck, Karthikeyan Mitran, Tzu-Hao Wei,
	Akhila Kavi


On Thu, 06 Aug 2026 02:01:29 -0700, Petar Stepanovic wrote:
> Add a Devicetree binding for the PWM fan controller found on the
> Axiado AX3000 and AX3005 SoCs.
> 
> The controller measures fan speed using a hardware tachometer block.
> Fan speed is controlled through a PWM signal supplied by an external
> PWM controller.
> 
> Add a MAINTAINERS entry for the binding.
> 
> Signed-off-by: Petar Stepanovic <pstepanovic@axiado.com>
> ---
>  .../bindings/hwmon/axiado,ax3000-pwm-fan.yaml      | 68 ++++++++++++++++++++++
>  MAINTAINERS                                        |  8 +++
>  2 files changed, 76 insertions(+)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/hwmon/axiado,ax3000-pwm-fan.example.dtb: fan@33001400 (axiado,ax3000-pwm-fan): reg: [[0, 855643136], [0, 1024]] is too long
	from schema $id: http://devicetree.org/schemas/hwmon/axiado,ax3000-pwm-fan.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.kernel.org/project/devicetree/patch/20260806-axiado-ax3000-pwm-fan-v1-1-f6db4cf2166b@axiado.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.



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

* Re: [PATCH 1/2] dt-bindings: hwmon: add Axiado AX3000 and AX3005 PWM fan controller
  2026-08-06  9:01 ` [PATCH 1/2] dt-bindings: hwmon: add Axiado AX3000 and AX3005 PWM fan controller Petar Stepanovic
  2026-08-06 10:41   ` Rob Herring (Arm)
@ 2026-08-06 13:16   ` Rob Herring
  1 sibling, 0 replies; 7+ messages in thread
From: Rob Herring @ 2026-08-06 13:16 UTC (permalink / raw)
  To: Petar Stepanovic
  Cc: Akhila Kavi, Prasad Bolisetty, Guenter Roeck, Krzysztof Kozlowski,
	Conor Dooley, Harshit Shah, Uwe Kleine-König, Tzu-Hao Wei,
	Karthikeyan Mitran, Jonathan Corbet, Shuah Khan, linux-hwmon,
	devicetree, linux-arm-kernel, linux-kernel, linux-pwm, linux-doc

On Thu, Aug 06, 2026 at 02:01:29AM -0700, Petar Stepanovic wrote:
> Add a Devicetree binding for the PWM fan controller found on the
> Axiado AX3000 and AX3005 SoCs.
> 
> The controller measures fan speed using a hardware tachometer block.
> Fan speed is controlled through a PWM signal supplied by an external
> PWM controller.
> 
> Add a MAINTAINERS entry for the binding.
> 
> Signed-off-by: Petar Stepanovic <pstepanovic@axiado.com>
> ---
>  .../bindings/hwmon/axiado,ax3000-pwm-fan.yaml      | 68 ++++++++++++++++++++++
>  MAINTAINERS                                        |  8 +++
>  2 files changed, 76 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/axiado,ax3000-pwm-fan.yaml b/Documentation/devicetree/bindings/hwmon/axiado,ax3000-pwm-fan.yaml
> new file mode 100644
> index 000000000000..a985f49bbdcd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/axiado,ax3000-pwm-fan.yaml
> @@ -0,0 +1,68 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/hwmon/axiado,ax3000-pwm-fan.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Axiado AX3000 and AX3005 PWM Fan Controller
> +
> +maintainers:
> +  - Petar Stepanovic <pstepanovic@axiado.com>
> +  - Akhila Kavi <akavi@axiado.com>
> +  - Prasad Bolisetty <pbolisetty@axiado.com>
> +
> +description:
> +  The Axiado AX3000 and AX3005 fan controllers use a hardware tachometer
> +  block to measure fan speed. Fan speed is controlled through a PWM signal
> +  supplied by an external PWM controller.
> +
> +properties:
> +  compatible:
> +    oneOf:
> +      - const: axiado,ax3000-pwm-fan
> +      - items:
> +          - const: axiado,ax3005-pwm-fan
> +          - const: axiado,ax3000-pwm-fan
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  pwms:
> +    maxItems: 1
> +    description:
> +      PWM specifier used to control fan speed.
> +
> +  pulses-per-revolution:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    minimum: 1
> +    default: 2
> +    description:
> +      Number of tachometer pulses generated per fan revolution.

This is a property of a fan, not the fan controller. The fan(s) should 
be represented as child node(s) under this device. Use the common fan 
binding, fan-common.yaml. See other bindings using it.

Rob


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

* Re: [PATCH 2/2] hwmon: add Axiado AX3000 and AX3005 PWM fan controller driver
  2026-08-06 10:04   ` Uwe Kleine-König
@ 2026-08-06 15:34     ` Guenter Roeck
  0 siblings, 0 replies; 7+ messages in thread
From: Guenter Roeck @ 2026-08-06 15:34 UTC (permalink / raw)
  To: Uwe Kleine-König, Petar Stepanovic
  Cc: Akhila Kavi, Prasad Bolisetty, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Harshit Shah, Tzu-Hao Wei, Karthikeyan Mitran,
	Jonathan Corbet, Shuah Khan, linux-hwmon, devicetree,
	linux-arm-kernel, linux-kernel, linux-pwm, linux-doc

On 8/6/26 03:04, Uwe Kleine-König wrote:

> If there is a hwmon lock that serializes calls to hwmon_ops::read and
> hwmon_ops::write, .pwm_lock isn't needed. (Unless I miss something,
> please double check. Also I'm unsure if there is such a hwmon
> serialization.)
> 

In hwmon_attr_show(), hwmon_attr_show_string(), and hwmon_attr_store():

	guard(mutex)(&hwdev->lock);

Guenter



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

end of thread, other threads:[~2026-08-06 15:35 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-06  9:01 [PATCH 0/2] hwmon: add Axiado AX3000 and AX3005 PWM fan support Petar Stepanovic
2026-08-06  9:01 ` [PATCH 1/2] dt-bindings: hwmon: add Axiado AX3000 and AX3005 PWM fan controller Petar Stepanovic
2026-08-06 10:41   ` Rob Herring (Arm)
2026-08-06 13:16   ` Rob Herring
2026-08-06  9:01 ` [PATCH 2/2] hwmon: add Axiado AX3000 and AX3005 PWM fan controller driver Petar Stepanovic
2026-08-06 10:04   ` Uwe Kleine-König
2026-08-06 15:34     ` Guenter Roeck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox