[PATCH RFC 1/4] pwm: rp1: Export helper to read fan tachometer RPM

From: Andrea della Porta

Date: Fri Oct 23 2026 - 06:15:53 EST


On the Raspberry Pi RP1 southbridge, the internal PWM controller hardware
block houses a register associated with fan tachometer monitoring. The
tachometer pulses are measured by firmware running on the RP1 Cortex-M
core, which periodically writes the calculated RPM values directly into
dedicated MMIO registers within the PWM block.

Because the Linux PWM framework currently does not provide an abstraction
or API to report hardware-calculated tachometer readings to consumer
drivers, a direct accessor is needed by the companion hwmon fan driver
to read these values.

Add and export rp1_pwm_read_tachometer() to allow consumer drivers to
retrieve the fan speed from the PWM MMIO registers. To prevent polluting
the global kernel symbol namespace and restrict access to intended
consumers, export the function under the 'RP1_PWM' symbol namespace.

Signed-off-by: Andrea della Porta <andrea.porta@xxxxxxxx>
---
drivers/pwm/pwm-rp1.c | 27 +++++++++++++++++++++++
include/soc/bcm2835/raspberrypi-pwm-rp1.h | 10 +++++++++
2 files changed, 37 insertions(+)
create mode 100644 include/soc/bcm2835/raspberrypi-pwm-rp1.h

diff --git a/drivers/pwm/pwm-rp1.c b/drivers/pwm/pwm-rp1.c
index d4b13fba8d236..79d65f332dd30 100644
--- a/drivers/pwm/pwm-rp1.c
+++ b/drivers/pwm/pwm-rp1.c
@@ -49,6 +49,7 @@
#include <linux/pwm.h>
#include <linux/units.h>
#include <linux/spinlock.h>
+#include <soc/bcm2835/raspberrypi-pwm-rp1.h>

#define RP1_PWM_GLB_CTRL 0x000
#define RP1_PWM_GLB_CTRL_CHANNEL_ENABLE(chan) BIT(chan)
@@ -286,6 +287,32 @@ static const struct pwm_ops rp1_pwm_ops = {
.write_waveform = rp1_pwm_write_waveform,
};

+int rp1_pwm_read_tachometer(struct device *dev)
+{
+ struct pwm_chip *chip;
+ struct rp1_pwm *rp1;
+
+ if (!dev)
+ return -EINVAL;
+
+ if (!of_device_is_compatible(dev_of_node(dev), "raspberrypi,rp1-pwm"))
+ return -EINVAL;
+
+ chip = dev_get_drvdata(dev);
+ if (!chip)
+ return -ENODEV;
+
+ rp1 = pwmchip_get_drvdata(chip);
+ if (!rp1)
+ return -ENODEV;
+
+ if (!rp1->clk_enabled)
+ return -EBUSY;
+
+ return (int)readl(rp1->base + RP1_PWM_PHASE(2));
+}
+EXPORT_SYMBOL_NS_GPL(rp1_pwm_read_tachometer, "RP1_PWM");
+
static int rp1_pwm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
diff --git a/include/soc/bcm2835/raspberrypi-pwm-rp1.h b/include/soc/bcm2835/raspberrypi-pwm-rp1.h
new file mode 100644
index 0000000000000..3be0892da667e
--- /dev/null
+++ b/include/soc/bcm2835/raspberrypi-pwm-rp1.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __SOC_RASPBERRY_PWM_RP1_H__
+#define __SOC_RASPBERRY_PWM_RP1_H__
+
+#include <linux/device.h>
+
+int rp1_pwm_read_tachometer(struct device *dev);
+
+#endif /* __SOC_RASPBERRY_PWM_RP1_H__ */
--
2.35.3