mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Luiz Angelo Daros de Luca <luizluca@gmail.com>
To: "Guenter Roeck" <linux@roeck-us.net>,
	"Rob Herring" <robh@kernel.org>,
	"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Chris Packham" <chris.packham@alliedtelesis.co.nz>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Darrick J. Wong" <djwong@us.ibm.com>,
	"Uwe Kleine-König" <ukleinek@kernel.org>
Cc: linux-hwmon@vger.kernel.org, devicetree@vger.kernel.org,
	 linux-kernel@vger.kernel.org,
	 Luiz Angelo Daros de Luca <luizluca@gmail.com>,
	linux-pwm@vger.kernel.org
Subject: [PATCH v2 5/6] hwmon: (adt7470) Register as a PWM provider
Date: Fri, 17 Jul 2026 17:59:18 -0300	[thread overview]
Message-ID: <20260717-adt7470_thermalzone-v2-5-a55147958fad@gmail.com> (raw)
In-Reply-To: <20260717-adt7470_thermalzone-v2-0-a55147958fad@gmail.com>

hwmon: (adt7470) Register as a PWM provider

The ADT7470 features four PWM outputs that can be used to control fans.
Previously, these were only accessible through the legacy hwmon sysfs
interface.

Register the ADT7470 as a generic PWM provider. This enables standard
Device Tree PWM consumers, such as "pwm-fan", to use the device through
the "#pwm-cells" property.

When a PWM consumer applies a new PWM state, the driver automatically
switches the corresponding PWM channel to manual mode so that the
requested duty cycle takes effect. The duty cycle specified by the PWM
framework is internally converted to the 0-255 scale expected by the
hardware registers.

The legacy sysfs interface remains unaffected and operates in parallel.

Signed-off-by: Luiz Angelo Daros de Luca <luizluca@gmail.com>
---
 drivers/hwmon/Kconfig   |  1 +
 drivers/hwmon/adt7470.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 08c29685126a..8838b6714e60 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -224,6 +224,7 @@ config SENSORS_ADT7462
 config SENSORS_ADT7470
 	tristate "Analog Devices ADT7470"
 	depends on I2C
+	depends on PWM || PWM=n
 	select REGMAP_I2C
 	help
 	  If you say yes here you get support for the Analog Devices
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index d881609c99aa..aaae14a421cd 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -22,6 +22,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/util_macros.h>
+#include <linux/pwm.h>
 
 /* Addresses to scan */
 static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END };
@@ -864,6 +865,57 @@ static int adt7470_pwm_write(struct device *dev, u32 attr, int channel, long val
 	return err;
 }
 
+static int adt7470_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+			     const struct pwm_state *state)
+{
+	struct adt7470_data *data = pwmchip_get_drvdata(chip);
+	unsigned int pwm_auto_reg_mask;
+	int err;
+	u8 val;
+
+	if (pwm->hwpwm % 2)
+		pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK;
+	else
+		pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK;
+
+	if (state->enabled && state->period > 0)
+		val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * 255, state->period);
+	else
+		val = 0;
+
+	mutex_lock(&data->lock);
+
+	if (data->pwm[pwm->hwpwm] == val &&
+	    data->pwm_automatic[pwm->hwpwm] == 0) {
+		mutex_unlock(&data->lock);
+		return 0;
+	}
+
+	/* Put the PWM channel in manual mode before updating it. */
+	err = regmap_update_bits(data->regmap,
+				 ADT7470_REG_PWM_CFG(pwm->hwpwm),
+				 pwm_auto_reg_mask, 0);
+	if (err < 0)
+		goto out;
+
+	data->pwm_automatic[pwm->hwpwm] = 0;
+
+	err = regmap_write(data->regmap,
+			   ADT7470_REG_PWM(pwm->hwpwm), val);
+	if (err < 0)
+		goto out;
+
+	data->pwm[pwm->hwpwm] = val;
+out:
+	mutex_unlock(&data->lock);
+
+	return err;
+}
+
+static const struct pwm_ops adt7470_pwm_ops = {
+	.apply = adt7470_pwm_apply,
+};
+
 static ssize_t pwm_max_show(struct device *dev,
 			    struct device_attribute *devattr, char *buf)
 {
@@ -1299,6 +1351,21 @@ static int adt7470_probe(struct i2c_client *client)
 	if (IS_ERR(hwmon_dev))
 		return PTR_ERR(hwmon_dev);
 
+	if (IS_REACHABLE(CONFIG_PWM)) {
+		struct pwm_chip *chip;
+
+		chip = devm_pwmchip_alloc(dev, ADT7470_PWM_COUNT, 0);
+		if (IS_ERR(chip))
+			return PTR_ERR(chip);
+
+		chip->ops = &adt7470_pwm_ops;
+		pwmchip_set_drvdata(chip, data);
+
+		err = devm_pwmchip_add(dev, chip);
+		if (err)
+			return dev_warn_probe(dev, err, "failed to register PWM chip\n");
+	}
+
 	data->auto_update = kthread_run(adt7470_update_thread, client, "%s",
 					dev_name(hwmon_dev));
 	if (IS_ERR(data->auto_update))

-- 
2.55.0


  parent reply	other threads:[~2026-07-17 20:59 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-17 20:59 [PATCH v2 0/6] hwmon: (adt7470) Add thermal zone and PWM provider support Luiz Angelo Daros de Luca
2026-07-17 20:59 ` [PATCH v2 1/6] dt-bindings: hwmon: add binding for adi,adt7470 Luiz Angelo Daros de Luca
2026-07-17 20:59 ` [PATCH v2 2/6] hwmon: (adt7470) Fix fans stuck in manual mode on I2C errors Luiz Angelo Daros de Luca
2026-07-17 20:59 ` [PATCH v2 3/6] hwmon: (adt7470) Fix busy-loop and I2C flooding in update thread Luiz Angelo Daros de Luca
2026-07-17 20:59 ` [PATCH v2 4/6] hwmon: (adt7470) Add ADT7470_PWM_MAX macro Luiz Angelo Daros de Luca
2026-07-17 20:59 ` Luiz Angelo Daros de Luca [this message]
2026-07-17 20:59 ` [PATCH v2 6/6] hwmon: (adt7470) Add thermal zone sensor support Luiz Angelo Daros de Luca

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260717-adt7470_thermalzone-v2-5-a55147958fad@gmail.com \
    --to=luizluca@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=chris.packham@alliedtelesis.co.nz \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=djwong@us.ibm.com \
    --cc=krzk+dt@kernel.org \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=robh@kernel.org \
    --cc=ukleinek@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox