Add trivial PWM driver for Argon40 Fan HAT, which is a RaspberryPi blower fan hat which can be controlled over I2C. Model this device as a PWM, so the pwm-fan can be attached to it and handle thermal zones and RPM management in a generic manner. Signed-off-by: Marek Vasut <marek.vasut+renesas@xxxxxxxxxxx> --- Cc: "Uwe Kleine-König" <ukleinek@xxxxxxxxxx> Cc: Conor Dooley <conor+dt@xxxxxxxxxx> Cc: Krzysztof Kozlowski <krzk+dt@xxxxxxxxxx> Cc: Rob Herring <robh@xxxxxxxxxx> Cc: devicetree@xxxxxxxxxxxxxxx Cc: linux-pwm@xxxxxxxxxxxxxxx Cc: linux-renesas-soc@xxxxxxxxxxxxxxx --- drivers/pwm/Kconfig | 9 +++++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-argon-fan-hat.c | 64 +++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 drivers/pwm/pwm-argon-fan-hat.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index d9bcd1e8413e..02f1a52ea29e 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -66,6 +66,15 @@ config PWM_APPLE To compile this driver as a module, choose M here: the module will be called pwm-apple. +config PWM_ARGON_FAN_HAT + tristate "Argon40 Fan HAT support" + depends on I2C && OF + help + Generic PWM framework driver for Argon40 Fan HAT. + + To compile this driver as a module, choose M here: the module + will be called pwm-argon-fan-hat. + config PWM_ATMEL tristate "Atmel PWM support" depends on ARCH_AT91 || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 96160f4257fc..ff4f47e5fb7a 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o obj-$(CONFIG_PWM_ADP5585) += pwm-adp5585.o obj-$(CONFIG_PWM_APPLE) += pwm-apple.o +obj-$(CONFIG_PWM_ARGON_FAN_HAT) += pwm-argon-fan-hat.o obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o 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 + */ + +#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) +{ + struct i2c_client *i2c = pwmchip_get_drvdata(chip); + u8 tx[2] = { 0x80, state->enabled ? pwm_get_relative_duty_cycle(state, 100) : 0 }; + 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, +}; + +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); +} + +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, +}; + +module_i2c_driver(argon_fan_hat_driver); + +MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@xxxxxxxxxxx>"); +MODULE_DESCRIPTION("Argon40 Fan HAT"); +MODULE_LICENSE("GPL"); -- 2.47.2