Hello Marek, I wonder how this device works in rpios, I didn't find a matching driver (but I also didn't try more than two minutes). On Wed, Jun 11, 2025 at 12:07:27AM +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..3d04abdbd349 > --- /dev/null > +++ b/drivers/pwm/pwm-argon-fan-hat.c > @@ -0,0 +1,64 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2025 Marek Vasut > + */ * Limitations: * - fixed period (which?) * - no support for offset/polarity If you can find out if it completes a period when reconfigured that would also be nice to document. This device is really trivial, but for completeness' sake: If there is a data sheet publicly available, please add a link here. > +#include <linux/err.h> > +#include <linux/i2c.h> > +#include <linux/module.h> > +#include <linux/pwm.h> > + > +static int argon_fan_hat_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, > + const struct pwm_state *state) Can you please implement the new-style callbacks? > +{ > + struct i2c_client *i2c = pwmchip_get_drvdata(chip); > + u8 tx[2] = { 0x80, state->enabled ? pwm_get_relative_duty_cycle(state, 100) : 0 }; This is too simple. I won't go into details about the right algorithm for .apply() as I want you to implement .round_waveform_tohw() + .round_waveform_fromhw() + .read_waveform() + .write_waveform() anyhow. For .round_waveform_tohw() you have to know the actual period length and then use something like: duty = wf->duty_length_ns; if (duty > ARGON_FAN_HAT_PERIOD) duty = ARGON_FAN_HAT_PERIOD; duty_percent = 100 * duty / ARGON_FAN_HAT_PERIOD; > + struct i2c_msg msg = { > + .addr = i2c->addr, > + .len = 2, > + .buf = tx, > + }; > + > + if (state->polarity != PWM_POLARITY_NORMAL) > + return -EINVAL; > + > + return (i2c_transfer(i2c->adapter, &msg, 1) == 1) ? 0 : -EINVAL; > +} > + > +static const struct pwm_ops argon_fan_hat_pwm_ops = { > + .apply = argon_fan_hat_pwm_apply, Can you read back the configuration? If yes then please implement .read_waveform(). > +}; > + > +static int argon_fan_hat_i2c_probe(struct i2c_client *i2c) > +{ > + struct pwm_chip *pc = devm_pwmchip_alloc(&i2c->dev, 1, 0); > + > + if (IS_ERR(pc)) > + return PTR_ERR(pc); > + > + pc->ops = &argon_fan_hat_pwm_ops; > + pwmchip_set_drvdata(pc, i2c); > + > + return devm_pwmchip_add(&i2c->dev, pc); Error message on failure please. (-> dev_err_probe()) > +} > + > +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, > +}; TIL about PROBE_PREFER_ASYNCHRONOUS. Best regards Uwe
Attachment:
signature.asc
Description: PGP signature