From 46b94c485ed197bc681da242440c6e2315697c57 Mon Sep 17 00:00:00 2001 From: Ban Feng Date: Tue, 22 Oct 2024 13:29:05 +0800 Subject: [PATCH 01/16] hwmon: Add driver for I2C chip Nuvoton NCT7363Y The NCT7363Y is a fan controller which provides up to 16 independent FAN input monitors. It can report each FAN input count values. The NCT7363Y also provides up to 16 independent PWM outputs. Each PWM can output specific PWM signal by manual mode to control the FAN duty outside. Signed-off-by: Ban Feng Message-ID: <20241022052905.4062682-3-kcfeng0@nuvoton.com> [groeck: Dropped unnecessary variable initialization, and , after { }] Signed-off-by: Guenter Roeck --- Documentation/hwmon/index.rst | 1 + Documentation/hwmon/nct7363.rst | 35 +++ MAINTAINERS | 2 + drivers/hwmon/Kconfig | 11 + drivers/hwmon/Makefile | 1 + drivers/hwmon/nct7363.c | 447 ++++++++++++++++++++++++++++++++ 6 files changed, 497 insertions(+) create mode 100644 Documentation/hwmon/nct7363.rst create mode 100644 drivers/hwmon/nct7363.c diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 4d15664bc41e..55f1111594b2 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -175,6 +175,7 @@ Hardware Monitoring Kernel Drivers mpq8785 nct6683 nct6775 + nct7363 nct7802 nct7904 npcm750-pwm-fan diff --git a/Documentation/hwmon/nct7363.rst b/Documentation/hwmon/nct7363.rst new file mode 100644 index 000000000000..623cb4f0c8ce --- /dev/null +++ b/Documentation/hwmon/nct7363.rst @@ -0,0 +1,35 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver nct7363 +===================== + +Supported chip: + + * Nuvoton NCT7363Y + + Prefix: nct7363 + + Addresses: I2C 0x20, 0x21, 0x22, 0x23 + +Author: Ban Feng + + +Description +----------- + +The NCT7363Y is a fan controller which provides up to 16 independent +FAN input monitors, and up to 16 independent PWM outputs with SMBus interface. + + +Sysfs entries +------------- + +Currently, the driver supports the following features: + +========== ========================================== +fanX_input provide current fan rotation value in RPM +fanX_alarm report fan low speed real status +fanX_min get or set fan count threshold + +pwmX get or set PWM fan control value. +========== ========================================== diff --git a/MAINTAINERS b/MAINTAINERS index 4f489551a193..91f7552b3609 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15955,6 +15955,8 @@ M: Ban Feng L: linux-hwmon@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/hwmon/nuvoton,nct7363.yaml +F: Documentation/hwmon/nct7363.rst +F: drivers/hwmon/nct7363.c NETCONSOLE M: Breno Leitao diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 64fefb22ecee..3ab2d02e7db3 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1681,6 +1681,17 @@ config SENSORS_NCT6775_I2C This driver can also be built as a module. If so, the module will be called nct6775-i2c. +config SENSORS_NCT7363 + tristate "Nuvoton NCT7363Y" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the Nuvoton NCT7363Y + hardware monitoring chip. + + This driver can also be built as a module. If so, the module + will be called nct7363. + config SENSORS_NCT7802 tristate "Nuvoton NCT7802Y" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 4ea6f7c95315..b827b92f2a78 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -172,6 +172,7 @@ obj-$(CONFIG_SENSORS_NCT6775_CORE) += nct6775-core.o nct6775-objs := nct6775-platform.o obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o obj-$(CONFIG_SENSORS_NCT6775_I2C) += nct6775-i2c.o +obj-$(CONFIG_SENSORS_NCT7363) += nct7363.o obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o obj-$(CONFIG_SENSORS_NCT7904) += nct7904.o obj-$(CONFIG_SENSORS_NPCM7XX) += npcm750-pwm-fan.o diff --git a/drivers/hwmon/nct7363.c b/drivers/hwmon/nct7363.c new file mode 100644 index 000000000000..be7bf32f6e68 --- /dev/null +++ b/drivers/hwmon/nct7363.c @@ -0,0 +1,447 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Nuvoton Technology corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NCT7363_REG_FUNC_CFG_BASE(x) (0x20 + (x)) +#define NCT7363_REG_LSRS(x) (0x34 + ((x) / 8)) +#define NCT7363_REG_PWMEN_BASE(x) (0x38 + (x)) +#define NCT7363_REG_FANINEN_BASE(x) (0x41 + (x)) +#define NCT7363_REG_FANINX_HVAL(x) (0x48 + ((x) * 2)) +#define NCT7363_REG_FANINX_LVAL(x) (0x49 + ((x) * 2)) +#define NCT7363_REG_FANINX_HL(x) (0x6C + ((x) * 2)) +#define NCT7363_REG_FANINX_LL(x) (0x6D + ((x) * 2)) +#define NCT7363_REG_FSCPXDUTY(x) (0x90 + ((x) * 2)) +#define NCT7363_REG_FSCPXDIV(x) (0x91 + ((x) * 2)) + +#define PWM_SEL(x) (BIT(0) << ((x) * 2)) +#define FANIN_SEL(_x) ({typeof(_x) (x) = (_x); \ + BIT(1) << (((x) < 8) ? \ + (((x) + 8) * 2) : \ + (((x) % 8) * 2)); }) +#define ALARM_SEL(x, y) ((x) & (BIT((y) % 8))) +#define VALUE_TO_REG(x, y) (((x) >> ((y) * 8)) & 0xFF) + +#define NCT7363_FANINX_LVAL_MASK GENMASK(4, 0) +#define NCT7363_FANIN_MASK GENMASK(12, 0) + +#define NCT7363_PWM_COUNT 16 + +static inline unsigned int fan_from_reg(u16 val) +{ + if (val == NCT7363_FANIN_MASK || val == 0) + return 0; + + return (1350000UL / val); +} + +static const struct of_device_id nct7363_of_match[] = { + { .compatible = "nuvoton,nct7363", }, + { .compatible = "nuvoton,nct7362", }, + { } +}; +MODULE_DEVICE_TABLE(of, nct7363_of_match); + +struct nct7363_data { + struct regmap *regmap; + + u16 fanin_mask; + u16 pwm_mask; +}; + +static int nct7363_read_fan(struct device *dev, u32 attr, int channel, + long *val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + unsigned int reg; + u8 regval[2]; + int ret; + u16 cnt; + + switch (attr) { + case hwmon_fan_input: + /* + * High-byte register should be read first to latch + * synchronous low-byte value + */ + ret = regmap_bulk_read(data->regmap, + NCT7363_REG_FANINX_HVAL(channel), + ®val, 2); + if (ret) + return ret; + + cnt = (regval[0] << 5) | (regval[1] & NCT7363_FANINX_LVAL_MASK); + *val = fan_from_reg(cnt); + return 0; + case hwmon_fan_min: + ret = regmap_bulk_read(data->regmap, + NCT7363_REG_FANINX_HL(channel), + ®val, 2); + if (ret) + return ret; + + cnt = (regval[0] << 5) | (regval[1] & NCT7363_FANINX_LVAL_MASK); + *val = fan_from_reg(cnt); + return 0; + case hwmon_fan_alarm: + ret = regmap_read(data->regmap, + NCT7363_REG_LSRS(channel), ®); + if (ret) + return ret; + + *val = (long)ALARM_SEL(reg, channel) > 0 ? 1 : 0; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int nct7363_write_fan(struct device *dev, u32 attr, int channel, + long val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + u8 regval[2]; + int ret; + + if (val <= 0) + return -EINVAL; + + switch (attr) { + case hwmon_fan_min: + val = clamp_val(DIV_ROUND_CLOSEST(1350000, val), + 1, NCT7363_FANIN_MASK); + regval[0] = val >> 5; + regval[1] = val & NCT7363_FANINX_LVAL_MASK; + + ret = regmap_bulk_write(data->regmap, + NCT7363_REG_FANINX_HL(channel), + regval, 2); + return ret; + default: + return -EOPNOTSUPP; + } +} + +static umode_t nct7363_fan_is_visible(const void *_data, u32 attr, int channel) +{ + const struct nct7363_data *data = _data; + + switch (attr) { + case hwmon_fan_input: + case hwmon_fan_alarm: + if (data->fanin_mask & BIT(channel)) + return 0444; + break; + case hwmon_fan_min: + if (data->fanin_mask & BIT(channel)) + return 0644; + break; + default: + break; + } + + return 0; +} + +static int nct7363_read_pwm(struct device *dev, u32 attr, int channel, + long *val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + unsigned int regval; + int ret; + + switch (attr) { + case hwmon_pwm_input: + ret = regmap_read(data->regmap, + NCT7363_REG_FSCPXDUTY(channel), ®val); + if (ret) + return ret; + + *val = (long)regval; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int nct7363_write_pwm(struct device *dev, u32 attr, int channel, + long val) +{ + struct nct7363_data *data = dev_get_drvdata(dev); + int ret; + + switch (attr) { + case hwmon_pwm_input: + if (val < 0 || val > 255) + return -EINVAL; + + ret = regmap_write(data->regmap, + NCT7363_REG_FSCPXDUTY(channel), val); + + return ret; + + default: + return -EOPNOTSUPP; + } +} + +static umode_t nct7363_pwm_is_visible(const void *_data, u32 attr, int channel) +{ + const struct nct7363_data *data = _data; + + switch (attr) { + case hwmon_pwm_input: + if (data->pwm_mask & BIT(channel)) + return 0644; + break; + default: + break; + } + + return 0; +} + +static int nct7363_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + switch (type) { + case hwmon_fan: + return nct7363_read_fan(dev, attr, channel, val); + case hwmon_pwm: + return nct7363_read_pwm(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int nct7363_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_fan: + return nct7363_write_fan(dev, attr, channel, val); + case hwmon_pwm: + return nct7363_write_pwm(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static umode_t nct7363_is_visible(const void *data, + enum hwmon_sensor_types type, + u32 attr, int channel) +{ + switch (type) { + case hwmon_fan: + return nct7363_fan_is_visible(data, attr, channel); + case hwmon_pwm: + return nct7363_pwm_is_visible(data, attr, channel); + default: + return 0; + } +} + +static const struct hwmon_channel_info *nct7363_info[] = { + HWMON_CHANNEL_INFO(fan, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM, + HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_ALARM), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT, + HWMON_PWM_INPUT), + NULL +}; + +static const struct hwmon_ops nct7363_hwmon_ops = { + .is_visible = nct7363_is_visible, + .read = nct7363_read, + .write = nct7363_write, +}; + +static const struct hwmon_chip_info nct7363_chip_info = { + .ops = &nct7363_hwmon_ops, + .info = nct7363_info, +}; + +static int nct7363_init_chip(struct nct7363_data *data) +{ + u32 func_config = 0; + int i, ret; + + /* Pin Function Configuration */ + for (i = 0; i < NCT7363_PWM_COUNT; i++) { + if (data->pwm_mask & BIT(i)) + func_config |= PWM_SEL(i); + if (data->fanin_mask & BIT(i)) + func_config |= FANIN_SEL(i); + } + + for (i = 0; i < 4; i++) { + ret = regmap_write(data->regmap, NCT7363_REG_FUNC_CFG_BASE(i), + VALUE_TO_REG(func_config, i)); + if (ret < 0) + return ret; + } + + /* PWM and FANIN Monitoring Enable */ + for (i = 0; i < 2; i++) { + ret = regmap_write(data->regmap, NCT7363_REG_PWMEN_BASE(i), + VALUE_TO_REG(data->pwm_mask, i)); + if (ret < 0) + return ret; + + ret = regmap_write(data->regmap, NCT7363_REG_FANINEN_BASE(i), + VALUE_TO_REG(data->fanin_mask, i)); + if (ret < 0) + return ret; + } + + return 0; +} + +static int nct7363_present_pwm_fanin(struct device *dev, + struct device_node *child, + struct nct7363_data *data) +{ + u8 fanin_ch[NCT7363_PWM_COUNT]; + struct of_phandle_args args; + int ret, fanin_cnt; + u8 ch, index; + + ret = of_parse_phandle_with_args(child, "pwms", "#pwm-cells", + 0, &args); + if (ret) + return ret; + + if (args.args[0] >= NCT7363_PWM_COUNT) + return -EINVAL; + data->pwm_mask |= BIT(args.args[0]); + + fanin_cnt = of_property_count_u8_elems(child, "tach-ch"); + if (fanin_cnt < 1 || fanin_cnt > NCT7363_PWM_COUNT) + return -EINVAL; + + ret = of_property_read_u8_array(child, "tach-ch", fanin_ch, fanin_cnt); + if (ret) + return ret; + + for (ch = 0; ch < fanin_cnt; ch++) { + index = fanin_ch[ch]; + if (index >= NCT7363_PWM_COUNT) + return -EINVAL; + data->fanin_mask |= BIT(index); + } + + return 0; +} + +static bool nct7363_regmap_is_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case NCT7363_REG_LSRS(0) ... NCT7363_REG_LSRS(15): + case NCT7363_REG_FANINX_HVAL(0) ... NCT7363_REG_FANINX_LVAL(15): + case NCT7363_REG_FANINX_HL(0) ... NCT7363_REG_FANINX_LL(15): + case NCT7363_REG_FSCPXDUTY(0) ... NCT7363_REG_FSCPXDIV(15): + return true; + default: + return false; + } +} + +static const struct regmap_config nct7363_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .use_single_read = true, + .use_single_write = true, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = nct7363_regmap_is_volatile, +}; + +static int nct7363_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct device_node *child; + struct nct7363_data *data; + struct device *hwmon_dev; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->regmap = devm_regmap_init_i2c(client, &nct7363_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + for_each_child_of_node(dev->of_node, child) { + ret = nct7363_present_pwm_fanin(dev, child, data); + if (ret) { + of_node_put(child); + return ret; + } + } + + /* Initialize the chip */ + ret = nct7363_init_chip(data); + if (ret) + return ret; + + hwmon_dev = + devm_hwmon_device_register_with_info(dev, client->name, data, + &nct7363_chip_info, NULL); + return PTR_ERR_OR_ZERO(hwmon_dev); +} + +static struct i2c_driver nct7363_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "nct7363", + .of_match_table = nct7363_of_match, + }, + .probe = nct7363_probe, +}; + +module_i2c_driver(nct7363_driver); + +MODULE_AUTHOR("CW Ho "); +MODULE_AUTHOR("Ban Feng "); +MODULE_DESCRIPTION("NCT7363 Hardware Monitoring Driver"); +MODULE_LICENSE("GPL"); -- 2.51.0 From 8b882f6ff00536a7324fc89dafdaa3c9573967ca Mon Sep 17 00:00:00 2001 From: Mariel Tinaco Date: Tue, 29 Oct 2024 09:37:32 +0800 Subject: [PATCH 02/16] dt-bindings: hwmon: ltc2978: add support for ltc7841 Add LTC7841 to supported devices of LTC2978. It has similar set of registers to LTC7880, differing only in number of output channels and some unimplemented PMBUS status and functionalities. Signed-off-by: Mariel Tinaco Acked-by: Rob Herring (Arm) Message-ID: <20241029013734.293024-2-Mariel.Tinaco@analog.com> Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml b/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml index 1f98da32f3fe..37e1dc9c7dd3 100644 --- a/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml +++ b/Documentation/devicetree/bindings/hwmon/lltc,ltc2978.yaml @@ -26,6 +26,7 @@ properties: - lltc,ltc3886 - lltc,ltc3887 - lltc,ltc3889 + - lltc,ltc7841 - lltc,ltc7880 - lltc,ltm2987 - lltc,ltm4664 @@ -50,6 +51,7 @@ properties: * ltc2977, ltc2979, ltc2980, ltm2987 : vout0 - vout7 * ltc2978 : vout0 - vout7 * ltc3880, ltc3882, ltc3884, ltc3886, ltc3887, ltc3889 : vout0 - vout1 + * ltc7841 : vout0 * ltc7880 : vout0 - vout1 * ltc3883 : vout0 * ltm4664 : vout0 - vout1 -- 2.51.0 From baf88c49a2b1cb0ca0d060486441b8ce876ec079 Mon Sep 17 00:00:00 2001 From: Mariel Tinaco Date: Tue, 29 Oct 2024 09:37:33 +0800 Subject: [PATCH 03/16] hwmon: (pmbus/ltc7841) add support for LTC7841 - docs Add LTC7841 to compatible devices of LTC2978 Signed-off-by: Mariel Tinaco Message-ID: <20241029013734.293024-3-Mariel.Tinaco@analog.com> Signed-off-by: Guenter Roeck --- Documentation/hwmon/ltc2978.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/hwmon/ltc2978.rst b/Documentation/hwmon/ltc2978.rst index edf24e5e1e11..651ca4904c66 100644 --- a/Documentation/hwmon/ltc2978.rst +++ b/Documentation/hwmon/ltc2978.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + Kernel driver ltc2978 ===================== @@ -117,6 +119,14 @@ Supported chips: Datasheet: https://www.analog.com/en/products/ltc3889 + * Linear Technology LTC7841 + + Prefix: 'ltc7841' + + Addresses scanned: - + + Datasheet: https://www.analog.com/en/products/ltc7841 + * Linear Technology LTC7880 Prefix: 'ltc7880' @@ -290,6 +300,7 @@ in[N]_label "vout[1-8]". LTC7880, LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4700: N=2-3 - LTC3883: N=2 + - LTC7841: N=2 in[N]_input Measured output voltage. @@ -420,6 +431,7 @@ curr[N]_label "iout[1-4]". LTM4664, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4700: N=2-3 - LTC3883: N=2 + - LTC7841: N=2 curr[N]_input Measured output current. -- 2.51.0 From 9c1716bc519c11615898c587b2e30398d083ddee Mon Sep 17 00:00:00 2001 From: Mariel Tinaco Date: Tue, 29 Oct 2024 09:37:34 +0800 Subject: [PATCH 04/16] hwmon: (pmbus/ltc2978) add support for ltc7841 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add support for LTC7841. The LTC7841 is a high performance PolyPhase® single output synchronous boost converter controller. Multiphase operation reduces input and output capacitor requirements and allows the use of smaller inductors than the single-phase equivalent. The relevant registers in the LTC7841 are similar to the LTC7880, only reduced by some amount. So it's just a matter of adding the chip id. The device also doesn't support polling, on top of the reduced register set, so a separate case for setting the chip info is added. Signed-off-by: Mariel Tinaco Message-ID: <20241029013734.293024-4-Mariel.Tinaco@analog.com> Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/Kconfig | 6 +++--- drivers/hwmon/pmbus/ltc2978.c | 20 ++++++++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index a4f02cad92fd..f6d352841953 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -224,9 +224,9 @@ config SENSORS_LTC2978_REGULATOR depends on SENSORS_LTC2978 && REGULATOR help If you say yes here you get regulator support for Linear Technology - LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889, LTC7880, - LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, LTM4686, - and LTM4700. + LTC3880, LTC3883, LTC3884, LTC3886, LTC3887, LTC3889, LTC7841, + LTC7880, LTM4644, LTM4675, LTM4676, LTM4677, LTM4678, LTM4680, + LTM4686, and LTM4700. config SENSORS_LTC3815 tristate "Linear Technologies LTC3815" diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c index 73a86f4d6472..a6eb4d4b5487 100644 --- a/drivers/hwmon/pmbus/ltc2978.c +++ b/drivers/hwmon/pmbus/ltc2978.c @@ -23,7 +23,8 @@ enum chips { /* Managers */ ltc2972, ltc2974, ltc2975, ltc2977, ltc2978, ltc2979, ltc2980, /* Controllers */ - ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7132, ltc7880, + ltc3880, ltc3882, ltc3883, ltc3884, ltc3886, ltc3887, ltc3889, ltc7132, + ltc7841, ltc7880, /* Modules */ ltm2987, ltm4664, ltm4675, ltm4676, ltm4677, ltm4678, ltm4680, ltm4686, ltm4700, @@ -50,7 +51,7 @@ enum chips { #define LTC3880_MFR_CLEAR_PEAKS 0xe3 #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 -/* LTC3883, LTC3884, LTC3886, LTC3889, LTC7132, LTC7880 */ +/* LTC3883, LTC3884, LTC3886, LTC3889, LTC7132, LTC7841 and LTC7880 only */ #define LTC3883_MFR_IIN_PEAK 0xe1 /* LTC2975 only */ @@ -80,6 +81,7 @@ enum chips { #define LTC3887_ID 0x4700 #define LTC3889_ID 0x4900 #define LTC7132_ID 0x4CE0 +#define LTC7841_ID 0x40D0 #define LTC7880_ID 0x49E0 #define LTM2987_ID_A 0x8010 /* A/B for two die IDs */ #define LTM2987_ID_B 0x8020 @@ -548,6 +550,7 @@ static const struct i2c_device_id ltc2978_id[] = { {"ltc3887", ltc3887}, {"ltc3889", ltc3889}, {"ltc7132", ltc7132}, + {"ltc7841", ltc7841}, {"ltc7880", ltc7880}, {"ltm2987", ltm2987}, {"ltm4664", ltm4664}, @@ -654,6 +657,8 @@ static int ltc2978_get_id(struct i2c_client *client) return ltc3889; else if (chip_id == LTC7132_ID) return ltc7132; + else if (chip_id == LTC7841_ID) + return ltc7841; else if (chip_id == LTC7880_ID) return ltc7880; else if (chip_id == LTM2987_ID_A || chip_id == LTM2987_ID_B) @@ -854,6 +859,16 @@ static int ltc2978_probe(struct i2c_client *client) | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; break; + case ltc7841: + data->features |= FEAT_CLEAR_PEAKS; + info->read_word_data = ltc3883_read_word_data; + info->pages = LTC3883_NUM_PAGES; + info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN + | PMBUS_HAVE_STATUS_INPUT + | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT + | PMBUS_HAVE_IOUT + | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; + break; default: return -ENODEV; } @@ -907,6 +922,7 @@ static const struct of_device_id ltc2978_of_match[] = { { .compatible = "lltc,ltc3887" }, { .compatible = "lltc,ltc3889" }, { .compatible = "lltc,ltc7132" }, + { .compatible = "lltc,ltc7841" }, { .compatible = "lltc,ltc7880" }, { .compatible = "lltc,ltm2987" }, { .compatible = "lltc,ltm4664" }, -- 2.51.0 From 0196d07f0e3ba3f5639ea5a74f59af8c990b95f0 Mon Sep 17 00:00:00 2001 From: Wenliang Yan Date: Wed, 6 Nov 2024 10:05:47 -0500 Subject: [PATCH 05/16] dt-bindings: Add SY24655 to ina2xx devicetree bindings SY24655 is similar to INA226. Its supply voltage and pin definitions are therefore the same. Compared to INA226, SY24655 has two additional registers for configuring and calculating average power. Signed-off-by: Wenliang Yan Acked-by: Conor Dooley Message-ID: <20241106150547.2538-2-wenliang202407@163.com> Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml index 6ae961732e6b..05a9cb36cd82 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml @@ -20,6 +20,7 @@ description: | properties: compatible: enum: + - silergy,sy24655 - ti,ina209 - ti,ina219 - ti,ina220 -- 2.51.0 From 52172ad87a22ed6e687ca678da21d3c949bc89a1 Mon Sep 17 00:00:00 2001 From: Wenliang Yan Date: Wed, 6 Nov 2024 10:05:46 -0500 Subject: [PATCH 06/16] hwmon: (ina226) Add support for SY24655 SY24655: Support for current and voltage detection as well as power calculation. Signed-off-by: Wenliang Yan Message-ID: <20241106150547.2538-1-wenliang202407@163.com> [groeck: Changed order of compatible entries; dropped spurious extra return statement in is_visible(); fixed code problems] Signed-off-by: Guenter Roeck --- Documentation/hwmon/ina2xx.rst | 27 +++++++++- drivers/hwmon/Kconfig | 2 +- drivers/hwmon/ina2xx.c | 94 ++++++++++++++++++++++++++++++++-- 3 files changed, 116 insertions(+), 7 deletions(-) diff --git a/Documentation/hwmon/ina2xx.rst b/Documentation/hwmon/ina2xx.rst index 1ce161e6c0bf..a3860aae444c 100644 --- a/Documentation/hwmon/ina2xx.rst +++ b/Documentation/hwmon/ina2xx.rst @@ -63,6 +63,17 @@ Supported chips: https://www.ti.com/ + * Silergy SY24655 + + Prefix: 'sy24655' + + Addresses: I2C 0x40 - 0x4f + + Datasheet: Publicly available at the Silergy website + + https://us1.silergy.com/ + + Author: Lothar Felten Description @@ -85,6 +96,11 @@ bus supply voltage. INA260 is a high or low side current and power monitor with integrated shunt resistor. +The SY24655 is a high- and low-side current shunt and power monitor with an I2C +interface. The SY24655 supports both shunt drop and supply voltage, with +programmable calibration value and conversion times. The SY24655 can also +calculate average power for use in energy conversion. + The shunt value in micro-ohms can be set via platform data or device tree at compile-time or via the shunt_resistor attribute in sysfs at run-time. Please refer to the Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml for bindings @@ -108,8 +124,8 @@ power1_input Power(uW) measurement channel shunt_resistor Shunt resistance(uOhm) channel (not for ina260) ======================= =============================================== -Additional sysfs entries for ina226, ina230, ina231, and ina260 ---------------------------------------------------------------- +Additional sysfs entries for ina226, ina230, ina231, ina260, and sy24655 +------------------------------------------------------------------------ ======================= ==================================================== curr1_lcrit Critical low current @@ -130,6 +146,13 @@ update_interval data conversion time; affects number of samples used to average results for shunt and bus voltages. ======================= ==================================================== +Sysfs entries for sy24655 only +------------------------------ + +======================= ==================================================== +power1_average average power from last reading to the present. +======================= ==================================================== + .. note:: - Configure `shunt_resistor` before configure `power1_crit`, because power diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 3ab2d02e7db3..863b61330c0a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -2189,7 +2189,7 @@ config SENSORS_INA2XX select REGMAP_I2C help If you say yes here you get support for INA219, INA220, INA226, - INA230, INA231, and INA260 power monitor chips. + INA230, INA231, INA260, and SY24655 power monitor chips. The INA2xx driver is configured for the default configuration of the part as described in the datasheet. diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index cecc80a41a97..345fe7db9de9 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -51,12 +51,19 @@ #define INA226_ALERT_LIMIT 0x07 #define INA226_DIE_ID 0xFF -#define INA2XX_MAX_REGISTERS 8 +/* SY24655 register definitions */ +#define SY24655_EIN 0x0A +#define SY24655_ACCUM_CONFIG 0x0D +#define INA2XX_MAX_REGISTERS 0x0D /* settings - depend on use case */ #define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */ #define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */ #define INA260_CONFIG_DEFAULT 0x6527 /* averages=16 */ +#define SY24655_CONFIG_DEFAULT 0x4527 /* averages=16 */ + +/* (only for sy24655) */ +#define SY24655_ACCUM_CONFIG_DEFAULT 0x044C /* continuous mode, clear after read*/ /* worst case is 68.10 ms (~14.6Hz, ina219) */ #define INA2XX_CONVERSION_RATE 15 @@ -97,6 +104,7 @@ static bool ina2xx_writeable_reg(struct device *dev, unsigned int reg) case INA2XX_CALIBRATION: case INA226_MASK_ENABLE: case INA226_ALERT_LIMIT: + case SY24655_ACCUM_CONFIG: return true; default: return false; @@ -127,12 +135,13 @@ static const struct regmap_config ina2xx_regmap_config = { .writeable_reg = ina2xx_writeable_reg, }; -enum ina2xx_ids { ina219, ina226, ina260 }; +enum ina2xx_ids { ina219, ina226, ina260, sy24655 }; struct ina2xx_config { u16 config_default; bool has_alerts; /* chip supports alerts and limits */ bool has_ishunt; /* chip has internal shunt resistor */ + bool has_power_average; /* chip has internal shunt resistor */ int calibration_value; int shunt_div; int bus_voltage_shift; @@ -149,6 +158,7 @@ struct ina2xx_data { long power_lsb_uW; struct mutex config_lock; struct regmap *regmap; + struct i2c_client *client; }; static const struct ina2xx_config ina2xx_config[] = { @@ -161,6 +171,7 @@ static const struct ina2xx_config ina2xx_config[] = { .power_lsb_factor = 20, .has_alerts = false, .has_ishunt = false, + .has_power_average = false, }, [ina226] = { .config_default = INA226_CONFIG_DEFAULT, @@ -171,6 +182,7 @@ static const struct ina2xx_config ina2xx_config[] = { .power_lsb_factor = 25, .has_alerts = true, .has_ishunt = false, + .has_power_average = false, }, [ina260] = { .config_default = INA260_CONFIG_DEFAULT, @@ -180,6 +192,18 @@ static const struct ina2xx_config ina2xx_config[] = { .power_lsb_factor = 8, .has_alerts = true, .has_ishunt = true, + .has_power_average = false, + }, + [sy24655] = { + .config_default = SY24655_CONFIG_DEFAULT, + .calibration_value = 4096, + .shunt_div = 400, + .bus_voltage_shift = 0, + .bus_voltage_lsb = 1250, + .power_lsb_factor = 25, + .has_alerts = true, + .has_ishunt = false, + .has_power_average = true, }, }; @@ -485,6 +509,41 @@ static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val) return 0; } +/* + * Configuring the READ_EIN (bit 10) of the ACCUM_CONFIG register to 1 + * can clear accumulator and sample_count after reading the EIN register. + * This way, the average power between the last read and the current + * read can be obtained. By combining with accurate time data from + * outside, the energy consumption during that period can be calculated. + */ +static int sy24655_average_power_read(struct ina2xx_data *data, u8 reg, long *val) +{ + u8 template[6]; + int ret; + long accumulator_24, sample_count; + + /* 48-bit register read */ + ret = i2c_smbus_read_i2c_block_data(data->client, reg, 6, template); + if (ret < 0) + return ret; + if (ret != 6) + return -EIO; + accumulator_24 = ((template[3] << 16) | + (template[4] << 8) | + template[5]); + sample_count = ((template[0] << 16) | + (template[1] << 8) | + template[2]); + if (sample_count <= 0) { + *val = 0; + return 0; + } + + *val = DIV_ROUND_CLOSEST(accumulator_24, sample_count) * data->power_lsb_uW; + + return 0; +} + static int ina2xx_power_read(struct device *dev, u32 attr, long *val) { struct ina2xx_data *data = dev_get_drvdata(dev); @@ -492,6 +551,8 @@ static int ina2xx_power_read(struct device *dev, u32 attr, long *val) switch (attr) { case hwmon_power_input: return ina2xx_read_init(dev, INA2XX_POWER, val); + case hwmon_power_average: + return sy24655_average_power_read(data, SY24655_EIN, val); case hwmon_power_crit: return ina226_alert_limit_read(data, INA226_POWER_OVER_LIMIT_MASK, INA2XX_POWER, val); @@ -651,6 +712,7 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type { const struct ina2xx_data *data = _data; bool has_alerts = data->config->has_alerts; + bool has_power_average = data->config->has_power_average; enum ina2xx_ids chip = data->chip; switch (type) { @@ -702,6 +764,10 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type if (has_alerts) return 0444; break; + case hwmon_power_average: + if (has_power_average) + return 0444; + break; default: break; } @@ -734,7 +800,8 @@ static const struct hwmon_channel_info * const ina2xx_info[] = { HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM | HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM), HWMON_CHANNEL_INFO(power, - HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM), + HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM | + HWMON_P_AVERAGE), NULL }; @@ -839,6 +906,19 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data) INA226_ALERT_LATCH_ENABLE | FIELD_PREP(INA226_ALERT_POLARITY, active_high)); } + if (data->config->has_power_average) { + if (data->chip == sy24655) { + /* + * Initialize the power accumulation method to continuous + * mode and clear the EIN register after each read of the + * EIN register + */ + ret = regmap_write(regmap, SY24655_ACCUM_CONFIG, + SY24655_ACCUM_CONFIG_DEFAULT); + if (ret < 0) + return ret; + } + } if (data->config->has_ishunt) return 0; @@ -868,6 +948,7 @@ static int ina2xx_probe(struct i2c_client *client) return -ENOMEM; /* set the device type */ + data->client = client; data->config = &ina2xx_config[chip]; data->chip = chip; mutex_init(&data->config_lock); @@ -906,11 +987,16 @@ static const struct i2c_device_id ina2xx_id[] = { { "ina230", ina226 }, { "ina231", ina226 }, { "ina260", ina260 }, + { "sy24655", sy24655 }, { } }; MODULE_DEVICE_TABLE(i2c, ina2xx_id); static const struct of_device_id __maybe_unused ina2xx_of_match[] = { + { + .compatible = "silergy,sy24655", + .data = (void *)sy24655 + }, { .compatible = "ti,ina219", .data = (void *)ina219 @@ -935,7 +1021,7 @@ static const struct of_device_id __maybe_unused ina2xx_of_match[] = { .compatible = "ti,ina260", .data = (void *)ina260 }, - { }, + { } }; MODULE_DEVICE_TABLE(of, ina2xx_of_match); -- 2.51.0 From 544177f20be2eebc7dd2a55feaf186ac68acc22d Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 5 Nov 2024 18:58:38 +0100 Subject: [PATCH 07/16] hwmon: (pmbus) add documentation for existing flags PMBUS_NO_WRITE_PROTECT and PMBUS_USE_COEFFICIENTS_CMD flags have been added to pmbus, but the corresponding documentation was not updated. Update the documentation before adding new flags Signed-off-by: Jerome Brunet Message-ID: <20241105-tps25990-v4-1-0e312ac70b62@baylibre.com> Signed-off-by: Guenter Roeck --- Documentation/hwmon/pmbus-core.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/hwmon/pmbus-core.rst b/Documentation/hwmon/pmbus-core.rst index 1eaf2b015837..686a00265bf7 100644 --- a/Documentation/hwmon/pmbus-core.rst +++ b/Documentation/hwmon/pmbus-core.rst @@ -308,6 +308,10 @@ currently provides a flags field with four bits used:: #define PMBUS_READ_STATUS_AFTER_FAILED_CHECK BIT(3) + #define PMBUS_NO_WRITE_PROTECT BIT(4) + + #define PMBUS_USE_COEFFICIENTS_CMD BIT(5) + struct pmbus_platform_data { u32 flags; /* Device specific flags */ @@ -358,3 +362,14 @@ This can be done by reading a known register. By setting this flag the driver will try to read the STATUS register after each failed register check. This read may fail, but it will put the chip into a known state. + +PMBUS_NO_WRITE_PROTECT + +Some PMBus chips respond with invalid data when reading the WRITE_PROTECT +register. For such chips, this flag should be set so that the PMBus core +driver doesn't use the WRITE_PROTECT command to determine its behavior. + +PMBUS_USE_COEFFICIENTS_CMD + +When this flag is set the PMBus core driver will use the COEFFICIENTS +register to initialize the coefficients for the direct mode format. -- 2.51.0 From 7a750b3986b7910711a5525dde0c84b541e72746 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 5 Nov 2024 18:58:39 +0100 Subject: [PATCH 08/16] hwmon: (pmbus/core) allow drivers to override WRITE_PROTECT Use _pmbus_read_byte_data() rather than calling smbus directly to check the write protection status. This give a chance to device implementing write protection differently to report back on the actual write protection status. Signed-off-by: Jerome Brunet Message-ID: <20241105-tps25990-v4-2-0e312ac70b62@baylibre.com> [groeck: Fix page parameter of _pmbus_read_byte_data()] Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index ce7fd4ca9d89..7f88b5d08046 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -2719,9 +2719,7 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data, * limit registers need to be disabled. */ if (!(data->flags & PMBUS_NO_WRITE_PROTECT)) { - pmbus_wait(client); - ret = i2c_smbus_read_byte_data(client, PMBUS_WRITE_PROTECT); - pmbus_update_ts(client, false); + ret = _pmbus_read_byte_data(client, -1, PMBUS_WRITE_PROTECT); if (ret > 0 && (ret & PB_WP_ANY)) data->flags |= PMBUS_WRITE_PROTECTED | PMBUS_SKIP_STATUS_CHECK; -- 2.51.0 From 509c3a362675bc995771df74d545548f98e37621 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 5 Nov 2024 18:58:42 +0100 Subject: [PATCH 09/16] hwmon: (pmbus/core) clear faults after setting smbalert mask pmbus_write_smbalert_mask() ignores the errors if the chip can't set smbalert mask the standard way. It is not necessarily a problem for the irq support if the chip is otherwise properly setup but it may leave an uncleared fault behind. pmbus_core will pick the fault on the next register_check(). The register check will fails regardless of the actual register support by the chip. This leads to missing attributes or debugfs entries for chips that should provide them. We cannot rely on register_check() as PMBUS_SMBALERT_MASK may be read-only. Unconditionally clear the page fault after setting PMBUS_SMBALERT_MASK to avoid the problem. Suggested-by: Guenter Roeck Fixes: 221819ca4c36 ("hwmon: (pmbus/core) Add interrupt support") Signed-off-by: Jerome Brunet Message-ID: <20241105-tps25990-v4-5-0e312ac70b62@baylibre.com> Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus/pmbus_core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 7f88b5d08046..a0109296a994 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -3277,7 +3277,17 @@ static int pmbus_regulator_notify(struct pmbus_data *data, int page, int event) static int pmbus_write_smbalert_mask(struct i2c_client *client, u8 page, u8 reg, u8 val) { - return _pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8)); + int ret; + + ret = _pmbus_write_word_data(client, page, PMBUS_SMBALERT_MASK, reg | (val << 8)); + + /* + * Clear fault systematically in case writing PMBUS_SMBALERT_MASK + * is not supported by the chip. + */ + pmbus_clear_fault_page(client, page); + + return ret; } static irqreturn_t pmbus_fault_handler(int irq, void *pdata) -- 2.51.0 From 2fc032ec1de485c64d8561dc7fa0de3f7acf147d Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 5 Nov 2024 18:58:43 +0100 Subject: [PATCH 10/16] dt-bindings: hwmon: pmbus: add ti tps25990 support Add DT binding for the Texas Instruments TPS25990 eFuse Reviewed-by: Conor Dooley Signed-off-by: Jerome Brunet Message-ID: <20241105-tps25990-v4-6-0e312ac70b62@baylibre.com> Signed-off-by: Guenter Roeck --- .../bindings/hwmon/pmbus/ti,tps25990.yaml | 83 +++++++++++++++++++ MAINTAINERS | 6 ++ 2 files changed, 89 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml new file mode 100644 index 000000000000..f4115870e450 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/hwmon/pmbus/ti,tps25990.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TPS25990 Stackable eFuse + +maintainers: + - Jerome Brunet + +description: + The TI TPS25990 is an integrated, high-current circuit + protection and power management device with PMBUS interface + +properties: + compatible: + const: ti,tps25990 + + reg: + maxItems: 1 + + ti,rimon-micro-ohms: + description: + micro Ohms value of the resistance installed between the Imon pin + and the ground reference. + + interrupts: + description: PMBUS SMB Alert Interrupt. + maxItems: 1 + + regulators: + type: object + description: + list of regulators provided by this controller. + + properties: + vout: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + gpdac1: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + + gpdac2: + $ref: /schemas/regulator/regulator.yaml# + type: object + unevaluatedProperties: false + additionalProperties: false + +required: + - compatible + - reg + - ti,rimon-micro-ohms + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hw-monitor@46 { + compatible = "ti,tps25990"; + reg = <0x46>; + + interrupt-parent = <&gpio>; + interrupts = <42 IRQ_TYPE_LEVEL_LOW>; + ti,rimon-micro-ohms = <1370000000>; + + regulators { + cpu0_vout: vout { + regulator-name = "main_cpu0"; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 91f7552b3609..03ed02bd7e4f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22879,6 +22879,12 @@ F: include/linux/dma/k3-udma-glue.h F: include/linux/dma/ti-cppi5.h X: drivers/dma/ti/cppi41.c +TEXAS INSTRUMENTS TPS25990 HARDWARE MONITOR DRIVER +M: Jerome Brunet +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/pmbus/ti,tps25990.yaml + TEXAS INSTRUMENTS TPS23861 PoE PSE DRIVER M: Robert Marko M: Luka Perkov -- 2.51.0 From 2e5bdf8aa2f49d06200fb6e645673c819135b614 Mon Sep 17 00:00:00 2001 From: Abhinav Saxena Date: Wed, 6 Nov 2024 18:38:49 -0700 Subject: [PATCH 11/16] hwmon: (f71882fg) Fix grammar in fan speed trip points explanation Fix several grammatical issues in the fan speed trip points documentation: - Replace awkward "which % the fan should run at at" construction with clearer "that specify the percentage at which" - Fix incorrect "is chip depended" to "are chip dependent" for correct verb agreement and adjective form - Improve readability by reorganizing first sentence and separating the complex explanation into simpler parts - Add hyphen before "see" to improve readability - Remove redundant "at" in temperature description No functional changes, documentation only. Signed-off-by: Abhinav Saxena Message-ID: <20241107013849.47833-1-xandfury@gmail.com> Signed-off-by: Guenter Roeck --- Documentation/hwmon/f71882fg.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Documentation/hwmon/f71882fg.rst b/Documentation/hwmon/f71882fg.rst index 38e30fbd4806..53d32bf06b70 100644 --- a/Documentation/hwmon/f71882fg.rst +++ b/Documentation/hwmon/f71882fg.rst @@ -178,10 +178,11 @@ Writing an unsupported mode will result in an invalid parameter error. available on the F71858FG / F8000 if the fan channel is in RPM mode. * 2: Normal auto mode - You can define a number of temperature/fan speed trip points, which % the - fan should run at at this temp and which temp a fan should follow using the - standard sysfs interface. The number and type of trip points is chip - depended, see which files are available in sysfs. + You can define a number of temperature/fan speed trip points that specify + the percentage at which the fan should run at each temperature, and which + temperature sensor a fan should follow, using the standard sysfs interface. + The number and type of trip points are chip dependent - see the available + files in sysfs. Fan/PWM channel 3 of the F8000 is always in this mode! * 3: Thermostat mode (Only available on the F8000 when in duty cycle mode) -- 2.51.0 From c412d7af010154ce9273dbc0296ae9327a605256 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 8 Nov 2024 14:43:48 +0200 Subject: [PATCH 12/16] hwmon: (jc42) Drop of_match_ptr() protection This prevents use of this driver with ACPI via PRP0001 and is an example of an anti pattern I'm trying to remove from the kernel. Hence drop from this driver. Also switch of.h for mod_devicetable.h include given use of struct of_device_id which is defined in that header. Reported-by: Konstantin Aladyshev Closes: https://lore.kernel.org/r/CACSj6VW7WKv5tiAkLCvSujENJvXq1Mc7_7vtkQsRSz3JGY0i3Q@mail.gmail.com Signed-off-by: Andy Shevchenko Message-ID: <20241108124348.1392473-1-andriy.shevchenko@linux.intel.com> Signed-off-by: Guenter Roeck --- drivers/hwmon/jc42.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index c459dce496a6..06f0ab2f52fa 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include /* Addresses to scan */ @@ -595,20 +595,18 @@ static const struct i2c_device_id jc42_id[] = { }; MODULE_DEVICE_TABLE(i2c, jc42_id); -#ifdef CONFIG_OF static const struct of_device_id jc42_of_ids[] = { { .compatible = "jedec,jc-42.4-temp", }, { } }; MODULE_DEVICE_TABLE(of, jc42_of_ids); -#endif static struct i2c_driver jc42_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = "jc42", .pm = JC42_DEV_PM_OPS, - .of_match_table = of_match_ptr(jc42_of_ids), + .of_match_table = jc42_of_ids, }, .probe = jc42_probe, .remove = jc42_remove, -- 2.51.0 From 1f22c0725705d2100b0a63dd77130c30d90fd6ad Mon Sep 17 00:00:00 2001 From: Abhinav Saxena Date: Fri, 8 Nov 2024 14:22:01 -0700 Subject: [PATCH 13/16] hwmon: (sch5627, max31827) Fix typos in driver documentation Fix some typos in hwmon/sch5627 and hwmon/max31827 reported by checkpatch.pl. These changes are purely documentation cleanup with no functional modifications. Signed-off-by: Abhinav Saxena Acked-by: Randy Dunlap Reviewed-by: Bagas Sanjaya Message-ID: <20241108212201.144482-1-xandfury@gmail.com> [groeck: Updated subject] Signed-off-by: Guenter Roeck --- Documentation/hwmon/sch5627.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/hwmon/sch5627.rst b/Documentation/hwmon/sch5627.rst index 8639dff234fc..5f521c6e90ab 100644 --- a/Documentation/hwmon/sch5627.rst +++ b/Documentation/hwmon/sch5627.rst @@ -39,7 +39,7 @@ Controlling fan speed --------------------- The SCH5627 allows for partially controlling the fan speed. If a temperature -channel excedes tempX_max, all fans are forced to maximum speed. The same is not +channel exceeds tempX_max, all fans are forced to maximum speed. The same is not true for tempX_crit, presumably some other measures to cool down the system are take in this case. In which way the value of fanX_min affects the fan speed is currently unknown. -- 2.51.0 From 4585580781d69d8627e15f027873e46282ea3787 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 11 Nov 2024 12:31:58 -0500 Subject: [PATCH 14/16] dt-bindings: hwmon: ti,tmp108: Add nxp,p3t1085 compatible string The register layout of P3T1085 is the same as ti,tmp108. Add compatible string nxp,p3t1085 for it. The difference of P3T1085 is support I3C. Acked-by: Krzysztof Kozlowski Signed-off-by: Frank Li Message-ID: <20241111-p3t1085-v3-1-bff511550aad@nxp.com> Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml b/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml index 0ad10d43fac0..a6f9319e068d 100644 --- a/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml +++ b/Documentation/devicetree/bindings/hwmon/ti,tmp108.yaml @@ -4,22 +4,26 @@ $id: http://devicetree.org/schemas/hwmon/ti,tmp108.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: TMP108 temperature sensor +title: TMP108/P3T1085(NXP) temperature sensor maintainers: - Krzysztof Kozlowski description: | - The TMP108 is a digital-output temperature sensor with a + The TMP108/P3T1085(NXP) is a digital-output temperature sensor with a dynamically-programmable limit window, and under- and overtemperature alert functions. + P3T1085(NXP) support I3C. + Datasheets: https://www.ti.com/product/TMP108 + https://www.nxp.com/docs/en/data-sheet/P3T1085UK.pdf properties: compatible: enum: + - nxp,p3t1085 - ti,tmp108 interrupts: -- 2.51.0 From 11d35624d7696a64724160199fc94587010d7cb2 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Mon, 11 Nov 2024 12:31:59 -0500 Subject: [PATCH 15/16] hwmon: (tmp108) Add NXP p3t1085 support Add compatible string 'nxp,p3t1085' since p3t1085's register layout is the same as tmp108. The p3t1085 supports I3C interface. Update document tmp108.rst and Kconfig's help context. Signed-off-by: Frank Li Message-ID: <20241111-p3t1085-v3-2-bff511550aad@nxp.com> Signed-off-by: Guenter Roeck --- Documentation/hwmon/tmp108.rst | 8 ++++++++ drivers/hwmon/Kconfig | 2 +- drivers/hwmon/tmp108.c | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/hwmon/tmp108.rst b/Documentation/hwmon/tmp108.rst index 6df7cf1b42f4..bc4941d98268 100644 --- a/Documentation/hwmon/tmp108.rst +++ b/Documentation/hwmon/tmp108.rst @@ -3,6 +3,14 @@ Kernel driver tmp108 Supported chips: + * NXP P3T1085 + + Prefix: 'p3t1085' + + Addresses scanned: none + + Datasheet: https://www.nxp.com/docs/en/data-sheet/P3T1085UK.pdf + * Texas Instruments TMP108 Prefix: 'tmp108' diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 863b61330c0a..7b9b52fa731c 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -2300,7 +2300,7 @@ config SENSORS_TMP108 select REGMAP_I2C help If you say yes here you get support for Texas Instruments TMP108 - sensor chips. + sensor chips and NXP P3T1085. This driver can also be built as a module. If so, the module will be called tmp108. diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index a82bbc959eb1..b561b452d8d3 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -420,6 +420,7 @@ MODULE_DEVICE_TABLE(i2c, tmp108_i2c_ids); #ifdef CONFIG_OF static const struct of_device_id tmp108_of_ids[] = { + { .compatible = "nxp,p3t1085", }, { .compatible = "ti,tmp108", }, {} }; -- 2.51.0 From 80bc64201e78f18248343c8986a55fe342a19e17 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 6 Nov 2024 19:59:04 +0100 Subject: [PATCH 16/16] dt-bindings: hwmon: pwm-fan: Document start from stopped state properties Delta AFC0612DB-F00 fan has to be set to at least 30% PWM duty cycle to spin up from a stopped state, and can be afterward throttled down to lower PWM duty cycle. Introduce support for operating such fans which need to start at higher PWM duty cycle first and can slow down next. Document two new DT properties, "fan-stop-to-start-percent" and "fan-stop-to-start-usec". The former describes the minimum percent of fan RPM at which it will surely spin up from stopped state. This value can be found in the fan datasheet and can be converted to PWM duty cycle easily. The "fan-stop-to-start-usec" describes the minimum time in microseconds for which the fan has to be set to stopped state start RPM for the fan to surely spin up. Signed-off-by: Marek Vasut Acked-by: Conor Dooley Message-ID: <20241106185925.223736-1-marex@denx.de> Signed-off-by: Guenter Roeck --- Documentation/devicetree/bindings/hwmon/pwm-fan.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml b/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml index 4e5abf7580cc..8b4ed5ee962f 100644 --- a/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml +++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.yaml @@ -31,6 +31,16 @@ properties: it must be self resetting edge interrupts. maxItems: 1 + fan-stop-to-start-percent: + description: + Minimum fan RPM in percent to start when stopped. + minimum: 0 + maximum: 100 + + fan-stop-to-start-us: + description: + Time to wait in microseconds after start when stopped. + pulses-per-revolution: description: Define the number of pulses per fan revolution for each tachometer -- 2.51.0