Re: [PATCH v2 3/3] pwm: argon-fan-hat: Add Argon40 Fan HAT support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello Marek,

On Tue, Jun 17, 2025 at 02:28:02AM +0200, Marek Vasut wrote:
> diff --git a/drivers/pwm/pwm-argon-fan-hat.c b/drivers/pwm/pwm-argon-fan-hat.c
> new file mode 100644
> index 000000000000..a26b58ee7f29
> --- /dev/null
> +++ b/drivers/pwm/pwm-argon-fan-hat.c
> @@ -0,0 +1,115 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2025 Marek Vasut
> + *
> + * Limitations:
> + * - no support for offset/polarity
> + * - fixed duty cycle, period changes from 0Hz..120kHz

A link to the product page would be great.

> + */
> +
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/pwm.h>
> +
> +static int argon_fan_hat_round_waveform_tohw(struct pwm_chip *chip,
> +					     struct pwm_device *pwm,
> +					     const struct pwm_waveform *wf,
> +					     void *_wfhw)
> +{
> +	u8 *wfhw = _wfhw;
> +
> +	*wfhw = DIV_ROUND_CLOSEST_ULL(wf->duty_length_ns * 100, wf->period_length_ns);
> +
> +	return 0;
> +}
> +
> +static int argon_fan_hat_round_waveform_fromhw(struct pwm_chip *chip,
> +					       struct pwm_device *pwm,
> +					       const void *_wfhw,
> +					       struct pwm_waveform *wf)
> +{
> +	const u8 *wfhw = _wfhw;
> +
> +	/* 1 step of this hardware is cca. 1200 Hz increase in frequency */
> +	wf->period_length_ns = DIV64_U64_ROUND_UP(NSEC_PER_SEC, *wfhw * 1200);
> +	wf->duty_length_ns = wf->period_length_ns / 10;
> +	wf->duty_offset_ns = 0;

How extraordinary, so the relative duty cycle is always 10%? In the
binding patch you claimed duty cycle was constant?

Please enable PWM_DEBUG while testing.

> +	return 0;
> +}
> +
> +static int argon_fan_hat_write_waveform(struct pwm_chip *chip,
> +					struct pwm_device *pwm,
> +					const void *_wfhw)
> +{
> +	struct i2c_client *i2c = pwmchip_get_drvdata(chip);
> +	const u8 *wfhw = _wfhw;
> +	u8 tx[2] = { 0x80, *wfhw };
> +	struct i2c_msg msg = {
> +		.addr = i2c->addr,
> +		.len = 2,
> +		.buf = tx,
> +	};
> +
> +	return (i2c_transfer(i2c->adapter, &msg, 1) == 1) ? 0 : -EINVAL;
> +}
> +
> +static const struct pwm_ops argon_fan_hat_pwm_ops = {
> +	.sizeof_wfhw		= sizeof(u8),
> +	.round_waveform_fromhw	= argon_fan_hat_round_waveform_fromhw,
> +	.round_waveform_tohw	= argon_fan_hat_round_waveform_tohw,
> +	.write_waveform		= argon_fan_hat_write_waveform,

Please add a comment about why there is no .read_waveform().

> +};
> +
> +static int argon_fan_hat_i2c_probe(struct i2c_client *i2c)
> +{
> +	struct pwm_chip *pc = devm_pwmchip_alloc(&i2c->dev, 1, 0);
> +	int ret;
> +
> +	if (IS_ERR(pc))
> +		return PTR_ERR(pc);
> +
> +	pc->ops = &argon_fan_hat_pwm_ops;
> +	pwmchip_set_drvdata(pc, i2c);
> +
> +	ret = devm_pwmchip_add(&i2c->dev, pc);
> +	if (ret)
> +		return dev_err_probe(&i2c->dev, ret, "Could not add PWM chip\n");
> +
> +	return 0;
> +}
> +
> +static void argon_fan_hat_i2c_shutdown(struct i2c_client *i2c)
> +{
> +	u8 tx[2] = { 0x80, 0x64 };
> +	struct i2c_msg msg = {
> +		.addr = i2c->addr,
> +		.len = 2,
> +		.buf = tx,
> +	};
> +
> +	i2c_transfer(i2c->adapter, &msg, 1);
> +}

This is argon_fan_hat_write_waveform(..., _wfhw=100). Looks like an
opportunity to consolidate these functions.

> +static const struct of_device_id argon_fan_hat_dt_ids[] = {
> +	{ .compatible = "argon40,fan-hat" },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, argon_fan_hat_dt_ids);
> +
> +static struct i2c_driver argon_fan_hat_driver = {
> +	.driver = {
> +		.name = "argon-fan-hat",
> +		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> +		.of_match_table = argon_fan_hat_dt_ids,
> +	},
> +	.probe = argon_fan_hat_i2c_probe,
> +	.shutdown = argon_fan_hat_i2c_shutdown,
> +};
> +
> +module_i2c_driver(argon_fan_hat_driver);
> +
> +MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@xxxxxxxxxxx>");
> +MODULE_DESCRIPTION("Argon40 Fan HAT");
> +MODULE_LICENSE("GPL");

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux