* [PATCH v6 0/2] iio: adc: add Nuvoton NCT7201 ADC driver @ 2025-04-16 8:17 Eason Yang 2025-04-16 8:17 ` [PATCH v6 1/2] dt-bindings: iio: adc: add NCT7201 ADCs Eason Yang 2025-04-16 8:17 ` [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 Eason Yang 0 siblings, 2 replies; 9+ messages in thread From: Eason Yang @ 2025-04-16 8:17 UTC (permalink / raw) To: jic23, lars, robh, krzk+dt, conor+dt, dlechner, nuno.sa, javier.carrasco.cruz, gstols, alisadariana, tgamblin, olivier.moysan, antoniu.miclaus, eblanc, andriy.shevchenko, joao.goncalves, tobias.sperling, marcelo.schmitt, angelogioacchino.delregno, thomas.bonnefille, herve.codina, chanh, KWLIU, yhyang2 Cc: linux-iio, devicetree, linux-kernel, Eason Yang Change since version 6: - Fix comments - Add use_single_read in regmap_config - Remove unused definitions - Do not shadow the return code by -EIO and let regmap API caller to decide - Use simple English in all error messages - Use a local variable for the struct device pointers. This increases code readability with shortened lines. - Use `fsleep` instead of `mdelay` - Use 16 bits type __le16 instead of u8 data[2] Change since version 5: - Fix comments - Add NUVOTON NCT7201 IIO DRIVER section in MAINTAINERS - Add vdd-supply and vref-supply to the DT example - Remove mutex since the regmap should already have an internal lock - Remove redundant assigning values - Check errors on regmap_write Change since version 4: - Fix comments - Add interrupts and reset-gpios to the DT example - Use the FIELD_PREP and FIELD_GET - Add use_single_write in regmap_config - Use regmap_access_table Change since version 3: - Fix comments - Don't put nct720"x" in the name, just call it nct7201 - Remove differential inputs until conversions are finished - Add NCT7201_ prefix in all macros and avoid the tables - Correct event threshold values in raw units - Add with and without interrupt callback function to have the event config part and one that doesn't - Remove print an error message if regmap_wirte failed case Change since version 2: - Remvoe read-vin-data-size property, default use read word vin data - Use regmap instead of i2c smbus API - IIO should be IIO_CHAN_INFO_RAW and _SCALE not _PROCESSED - Use dev_xxx_probe in probe function and dev_xxx in other functions - Use devm_iio_device_register replace of iio_device_register - Use guard(mutex) replace of mutex_lock - Use get_unaligned_le16 conversion API Changes since version 1: - Add new property in iio:adc binding document - Add new driver for Nuvoton NCT720x driver Eason Yang (2): dt-bindings: iio: adc: add NCT7201 ADCs iio: adc: add support for Nuvoton NCT7201 .../bindings/iio/adc/nuvoton,nct7201.yaml | 70 +++ MAINTAINERS | 7 + drivers/iio/adc/Kconfig | 11 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/nct7201.c | 471 ++++++++++++++++++ 5 files changed, 560 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml create mode 100644 drivers/iio/adc/nct7201.c -- 2.34.1 ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v6 1/2] dt-bindings: iio: adc: add NCT7201 ADCs 2025-04-16 8:17 [PATCH v6 0/2] iio: adc: add Nuvoton NCT7201 ADC driver Eason Yang @ 2025-04-16 8:17 ` Eason Yang 2025-04-17 6:20 ` Krzysztof Kozlowski 2025-04-16 8:17 ` [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 Eason Yang 1 sibling, 1 reply; 9+ messages in thread From: Eason Yang @ 2025-04-16 8:17 UTC (permalink / raw) To: jic23, lars, robh, krzk+dt, conor+dt, dlechner, nuno.sa, javier.carrasco.cruz, gstols, alisadariana, tgamblin, olivier.moysan, antoniu.miclaus, eblanc, andriy.shevchenko, joao.goncalves, tobias.sperling, marcelo.schmitt, angelogioacchino.delregno, thomas.bonnefille, herve.codina, chanh, KWLIU, yhyang2 Cc: linux-iio, devicetree, linux-kernel, Eason Yang Add a binding specification for the Nuvoton NCT7201/NCT7202 up to 12-bit ADCs with I2C interface. Signed-off-by: Eason Yang <j2anfernee@gmail.com> --- .../bindings/iio/adc/nuvoton,nct7201.yaml | 70 +++++++++++++++++++ MAINTAINERS | 6 ++ 2 files changed, 76 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml diff --git a/Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml b/Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml new file mode 100644 index 000000000000..8ce7d415d956 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/nuvoton,nct7201.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton nct7201 and similar ADCs + +maintainers: + - Eason Yang <j2anfernee@gmail.com> + +description: | + The NCT7201/NCT7202 is a Nuvoton Hardware Monitor IC, contains up to 12 + voltage monitoring channels, with SMBus interface, and up to 4 sets SMBus + address selection by ADDR connection. It also provides ALERT# signal for + event notification and reset input RSTIN# to recover it from a fault + condition. + + NCT7201 contains 8 voltage monitor inputs (VIN1~VIN8). + NCT7202 contains 12 voltage monitor inputs (VIN1~VIN12). + +properties: + compatible: + enum: + - nuvoton,nct7201 + - nuvoton,nct7202 + + reg: + maxItems: 1 + + vdd-supply: + description: + A 3.3V to supply that powers the chip. + + vref-supply: + description: + The regulator supply for the ADC reference voltage. + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@1d { + compatible = "nuvoton,nct7202"; + reg = <0x1d>; + vdd-supply = <&vdd>; + vref-supply = <&vref>; + interrupt-parent = <&gpio3>; + interrupts = <30 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio3 28 GPIO_ACTIVE_LOW>; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index c59316109e3f..cc0dd650c447 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17304,6 +17304,12 @@ F: drivers/nubus/ F: include/linux/nubus.h F: include/uapi/linux/nubus.h +NUVOTON NCT7201 IIO DRIVER +M: Eason Yang <j2anfernee@gmail.com> +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml + NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER M: Antonino Daplas <adaplas@gmail.com> L: linux-fbdev@vger.kernel.org -- 2.34.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v6 1/2] dt-bindings: iio: adc: add NCT7201 ADCs 2025-04-16 8:17 ` [PATCH v6 1/2] dt-bindings: iio: adc: add NCT7201 ADCs Eason Yang @ 2025-04-17 6:20 ` Krzysztof Kozlowski 0 siblings, 0 replies; 9+ messages in thread From: Krzysztof Kozlowski @ 2025-04-17 6:20 UTC (permalink / raw) To: Eason Yang Cc: jic23, lars, robh, krzk+dt, conor+dt, dlechner, nuno.sa, javier.carrasco.cruz, gstols, alisadariana, tgamblin, olivier.moysan, antoniu.miclaus, eblanc, andriy.shevchenko, joao.goncalves, tobias.sperling, marcelo.schmitt, angelogioacchino.delregno, thomas.bonnefille, herve.codina, chanh, KWLIU, yhyang2, linux-iio, devicetree, linux-kernel On Wed, Apr 16, 2025 at 04:17:33PM GMT, Eason Yang wrote: > Add a binding specification for the Nuvoton NCT7201/NCT7202 up to 12-bit > ADCs with I2C interface. > > Signed-off-by: Eason Yang <j2anfernee@gmail.com> Did you read the message you got from me last time? <form letter> This is a friendly reminder during the review process. It looks like you received a tag and forgot to add it. If you do not know the process, here is a short explanation: Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions of patchset, under or above your Signed-off-by tag, unless patch changed significantly (e.g. new properties added to the DT bindings). Tag is "received", when provided in a message replied to you on the mailing list. Tools like b4 can help here. However, there's no need to repost patches *only* to add the tags. The upstream maintainer will do that for tags received on the version they apply. Please read: https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577 If a tag was not added on purpose, please state why and what changed. </form letter> Best regards, Krzysztof ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 2025-04-16 8:17 [PATCH v6 0/2] iio: adc: add Nuvoton NCT7201 ADC driver Eason Yang 2025-04-16 8:17 ` [PATCH v6 1/2] dt-bindings: iio: adc: add NCT7201 ADCs Eason Yang @ 2025-04-16 8:17 ` Eason Yang 2025-04-16 9:34 ` Andy Shevchenko 2025-04-18 16:13 ` Jonathan Cameron 1 sibling, 2 replies; 9+ messages in thread From: Eason Yang @ 2025-04-16 8:17 UTC (permalink / raw) To: jic23, lars, robh, krzk+dt, conor+dt, dlechner, nuno.sa, javier.carrasco.cruz, gstols, alisadariana, tgamblin, olivier.moysan, antoniu.miclaus, eblanc, andriy.shevchenko, joao.goncalves, tobias.sperling, marcelo.schmitt, angelogioacchino.delregno, thomas.bonnefille, herve.codina, chanh, KWLIU, yhyang2 Cc: linux-iio, devicetree, linux-kernel, Eason Yang Add Nuvoton NCT7201/NCT7202 system voltage monitor 12-bit ADC driver NCT7201/NCT7202 supports up to 12 analog voltage monitor inputs and up to 4 SMBus addresses by ADDR pin. Meanwhile, ALERT# hardware event pins for independent alarm signals, and all the threshold values could be set for system protection without any timing delay. It also supports reset input RSTIN# to recover system from a fault condition. Currently, only single-edge mode conversion and threshold events are supported. Signed-off-by: Eason Yang <j2anfernee@gmail.com> --- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 11 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/nct7201.c | 471 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 484 insertions(+) create mode 100644 drivers/iio/adc/nct7201.c diff --git a/MAINTAINERS b/MAINTAINERS index cc0dd650c447..ae242fb15ef5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17309,6 +17309,7 @@ M: Eason Yang <j2anfernee@gmail.com> L: linux-iio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/iio/adc/nuvoton,nct7201.yaml +F: drivers/iio/adc/nct7201.c NVIDIA (rivafb and nvidiafb) FRAMEBUFFER DRIVER M: Antonino Daplas <adaplas@gmail.com> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 6529df1a498c..6d6af1b51b5e 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1092,6 +1092,17 @@ config NAU7802 To compile this driver as a module, choose M here: the module will be called nau7802. +config NCT7201 + tristate "Nuvoton Instruments NCT7201 and NCT7202 Power Monitor" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the Nuvoton NCT7201 and + NCT7202 Voltage Monitor. + + This driver can also be built as a module. If so, the module + will be called nct7201. + config NPCM_ADC tristate "Nuvoton NPCM ADC driver" depends on ARCH_NPCM || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 3e918c3eec69..54e8a7541af6 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -97,6 +97,7 @@ obj-$(CONFIG_MESON_SARADC) += meson_saradc.o obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o obj-$(CONFIG_NAU7802) += nau7802.o +obj-$(CONFIG_NCT7201) += nct7201.o obj-$(CONFIG_NPCM_ADC) += npcm_adc.o obj-$(CONFIG_PAC1921) += pac1921.o obj-$(CONFIG_PAC1934) += pac1934.o diff --git a/drivers/iio/adc/nct7201.c b/drivers/iio/adc/nct7201.c new file mode 100644 index 000000000000..e9217a664ee0 --- /dev/null +++ b/drivers/iio/adc/nct7201.c @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for Nuvoton nct7201 and nct7202 power monitor chips. + * + * Copyright (c) 2024-2025 Nuvoton Technology corporation. + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/types.h> +#include <linux/unaligned.h> + +#include <linux/iio/events.h> +#include <linux/iio/iio.h> + +#define NCT7201_REG_INTERRUPT_STATUS_1 0x0C +#define NCT7201_REG_INTERRUPT_STATUS_2 0x0D +#define NCT7201_REG_VOLT_LOW_BYTE 0x0F +#define NCT7201_REG_CONFIGURATION 0x10 +#define NCT7201_BIT_CONFIGURATION_START BIT(0) +#define NCT7201_BIT_CONFIGURATION_ALERT_MSK BIT(1) +#define NCT7201_BIT_CONFIGURATION_CONV_RATE BIT(2) +#define NCT7201_BIT_CONFIGURATION_RESET BIT(7) + +#define NCT7201_REG_ADVANCED_CONFIGURATION 0x11 +#define NCT7201_BIT_ADVANCED_CONF_MOD_ALERT BIT(0) +#define NCT7201_BIT_ADVANCED_CONF_MOD_STS BIT(1) +#define NCT7201_BIT_ADVANCED_CONF_FAULT_QUEUE BIT(2) +#define NCT7201_BIT_ADVANCED_CONF_EN_DEEP_SHUTDOWN BIT(4) +#define NCT7201_BIT_ADVANCED_CONF_EN_SMB_TIMEOUT BIT(5) +#define NCT7201_BIT_ADVANCED_CONF_MOD_RSTIN BIT(7) + +#define NCT7201_REG_CHANNEL_INPUT_MODE 0x12 +#define NCT7201_REG_CHANNEL_ENABLE_1 0x13 +#define NCT7201_REG_CHANNEL_ENABLE_MASK GENMASK(11, 0) +#define NCT7201_REG_INTERRUPT_MASK_1 0x15 +#define NCT7201_REG_INTERRUPT_MASK_2 0x16 +#define NCT7201_REG_BUSY_STATUS 0x1E +#define NCT7201_BIT_BUSY BIT(0) +#define NCT7201_BIT_PWR_UP BIT(1) +#define NCT7201_REG_ONE_SHOT 0x1F +#define NCT7201_REG_SMUS_ADDRESS 0xFC +#define NCT7201_REG_VIN_MASK GENMASK(15, 3) + +#define NCT7201_REG_VIN(i) (i) +#define NCT7201_REG_VIN_HIGH_LIMIT(i) (0x20 + (i) * 2) +#define NCT7201_REG_VIN_LOW_LIMIT(i) (0x21 + (i) * 2) +#define NCT7201_MAX_CHANNEL 12 + +static const struct regmap_range nct7201_read_reg_range[] = { + regmap_reg_range(NCT7201_REG_INTERRUPT_STATUS_1, NCT7201_REG_BUSY_STATUS), + regmap_reg_range(NCT7201_REG_SMUS_ADDRESS, NCT7201_REG_SMUS_ADDRESS), +}; + +static const struct regmap_access_table nct7201_readable_regs_tbl = { + .yes_ranges = nct7201_read_reg_range, + .n_yes_ranges = ARRAY_SIZE(nct7201_read_reg_range), +}; + +static const struct regmap_range nct7201_write_reg_range[] = { + regmap_reg_range(NCT7201_REG_CONFIGURATION, NCT7201_REG_INTERRUPT_MASK_2), + regmap_reg_range(NCT7201_REG_ONE_SHOT, NCT7201_REG_ONE_SHOT), +}; + +static const struct regmap_access_table nct7201_writeable_regs_tbl = { + .yes_ranges = nct7201_write_reg_range, + .n_yes_ranges = ARRAY_SIZE(nct7201_write_reg_range), +}; + +static const struct regmap_range nct7201_read_vin_reg_range[] = { + regmap_reg_range(NCT7201_REG_VIN(0), NCT7201_REG_VIN(NCT7201_MAX_CHANNEL - 1)), + regmap_reg_range(NCT7201_REG_VIN_HIGH_LIMIT(0), + NCT7201_REG_VIN_LOW_LIMIT(NCT7201_MAX_CHANNEL - 1)), +}; + +static const struct regmap_access_table nct7201_readable_vin_regs_tbl = { + .yes_ranges = nct7201_read_vin_reg_range, + .n_yes_ranges = ARRAY_SIZE(nct7201_read_vin_reg_range), +}; + +static const struct regmap_range nct7201_write_vin_reg_range[] = { + regmap_reg_range(NCT7201_REG_VIN_HIGH_LIMIT(0), + NCT7201_REG_VIN_LOW_LIMIT(NCT7201_MAX_CHANNEL - 1)), +}; + +static const struct regmap_access_table nct7201_writeable_vin_regs_tbl = { + .yes_ranges = nct7201_write_vin_reg_range, + .n_yes_ranges = ARRAY_SIZE(nct7201_write_vin_reg_range), +}; + +static const struct regmap_config nct7201_regmap8_config = { + .name = "vin-data-read-byte", + .reg_bits = 8, + .val_bits = 8, + .use_single_read = true, + .use_single_write = true, + .max_register = 0xff, + .rd_table = &nct7201_readable_regs_tbl, + .wr_table = &nct7201_writeable_regs_tbl, +}; + +static const struct regmap_config nct7201_regmap16_config = { + .name = "vin-data-read-word", + .reg_bits = 8, + .val_bits = 16, + .max_register = 0xff, + .rd_table = &nct7201_readable_vin_regs_tbl, + .wr_table = &nct7201_writeable_vin_regs_tbl, +}; + +struct nct7201_chip_info { + struct device *dev; + struct regmap *regmap; + struct regmap *regmap16; + int num_vin_channels; + u16 vin_mask; +}; + +struct nct7201_adc_model_data { + const char *model_name; + const struct iio_chan_spec *channels; + const int num_channels; + int num_vin_channels; +}; + +static const struct iio_event_spec nct7201_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +#define NCT7201_VOLTAGE_CHANNEL(num) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (num + 1), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .address = num, \ + .event_spec = nct7201_events, \ + .num_event_specs = ARRAY_SIZE(nct7201_events), \ + } + +static const struct iio_chan_spec nct7201_channels[] = { + NCT7201_VOLTAGE_CHANNEL(0), + NCT7201_VOLTAGE_CHANNEL(1), + NCT7201_VOLTAGE_CHANNEL(2), + NCT7201_VOLTAGE_CHANNEL(3), + NCT7201_VOLTAGE_CHANNEL(4), + NCT7201_VOLTAGE_CHANNEL(5), + NCT7201_VOLTAGE_CHANNEL(6), + NCT7201_VOLTAGE_CHANNEL(7), +}; + +static const struct iio_chan_spec nct7202_channels[] = { + NCT7201_VOLTAGE_CHANNEL(0), + NCT7201_VOLTAGE_CHANNEL(1), + NCT7201_VOLTAGE_CHANNEL(2), + NCT7201_VOLTAGE_CHANNEL(3), + NCT7201_VOLTAGE_CHANNEL(4), + NCT7201_VOLTAGE_CHANNEL(5), + NCT7201_VOLTAGE_CHANNEL(6), + NCT7201_VOLTAGE_CHANNEL(7), + NCT7201_VOLTAGE_CHANNEL(8), + NCT7201_VOLTAGE_CHANNEL(9), + NCT7201_VOLTAGE_CHANNEL(10), + NCT7201_VOLTAGE_CHANNEL(11), +}; + +static int nct7201_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct nct7201_chip_info *chip = iio_priv(indio_dev); + unsigned int value; + int err; + + if (chan->type != IIO_VOLTAGE) + return -EOPNOTSUPP; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + err = regmap_read(chip->regmap16, NCT7201_REG_VIN(chan->address), &value); + if (err) + return err; + *val = FIELD_GET(NCT7201_REG_VIN_MASK, value); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* From the datasheet, we have to multiply by 0.0004995 */ + *val = 0; + *val2 = 499500; + return IIO_VAL_INT_PLUS_NANO; + default: + return -EINVAL; + } +} + +static int nct7201_read_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct nct7201_chip_info *chip = iio_priv(indio_dev); + unsigned int value; + int err; + + if (chan->type != IIO_VOLTAGE) + return -EOPNOTSUPP; + + if (info != IIO_EV_INFO_VALUE) + return -EINVAL; + + if (dir == IIO_EV_DIR_FALLING) + err = regmap_read(chip->regmap16, NCT7201_REG_VIN_LOW_LIMIT(chan->address), + &value); + else + err = regmap_read(chip->regmap16, NCT7201_REG_VIN_HIGH_LIMIT(chan->address), + &value); + if (err) + return err; + + *val = FIELD_GET(NCT7201_REG_VIN_MASK, value); + + return IIO_VAL_INT; +} + +static int nct7201_write_event_value(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct nct7201_chip_info *chip = iio_priv(indio_dev); + int err; + + if (chan->type != IIO_VOLTAGE) + return -EOPNOTSUPP; + + if (info != IIO_EV_INFO_VALUE) + return -EOPNOTSUPP; + + if (dir == IIO_EV_DIR_FALLING) + err = regmap_write(chip->regmap16, NCT7201_REG_VIN_LOW_LIMIT(chan->address), + FIELD_PREP(NCT7201_REG_VIN_MASK, val)); + else + err = regmap_write(chip->regmap16, NCT7201_REG_VIN_HIGH_LIMIT(chan->address), + FIELD_PREP(NCT7201_REG_VIN_MASK, val)); + if (err) + return err; + + return 0; +} + +static int nct7201_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct nct7201_chip_info *chip = iio_priv(indio_dev); + + if (chan->type != IIO_VOLTAGE) + return -EOPNOTSUPP; + + return !!(chip->vin_mask & BIT(chan->address)); +} + +static int nct7201_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + bool state) +{ + struct nct7201_chip_info *chip = iio_priv(indio_dev); + unsigned int mask; + int err; + + if (chan->type != IIO_VOLTAGE) + return -EOPNOTSUPP; + + mask = BIT(chan->address); + + if (state) + chip->vin_mask |= mask; + else + chip->vin_mask &= ~mask; + + if (chip->num_vin_channels <= 8) + err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, + chip->vin_mask); + else + err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, + &chip->vin_mask, sizeof(chip->vin_mask)); + if (err) + return err; + + return 0; +} + +static const struct iio_info nct7201_info = { + .read_raw = nct7201_read_raw, + .read_event_config = nct7201_read_event_config, + .write_event_config = nct7201_write_event_config, + .read_event_value = nct7201_read_event_value, + .write_event_value = nct7201_write_event_value, +}; + +static const struct iio_info nct7201_info_no_irq = { + .read_raw = nct7201_read_raw, +}; + +static const struct nct7201_adc_model_data nct7201_model_data = { + .model_name = "nct7201", + .channels = nct7201_channels, + .num_channels = ARRAY_SIZE(nct7201_channels), + .num_vin_channels = 8, +}; + +static const struct nct7201_adc_model_data nct7202_model_data = { + .model_name = "nct7202", + .channels = nct7202_channels, + .num_channels = ARRAY_SIZE(nct7202_channels), + .num_vin_channels = 12, +}; + +static int nct7201_init_chip(struct nct7201_chip_info *chip) +{ + struct device *dev = chip->dev; + __le16 data = cpu_to_le16(NCT7201_REG_CHANNEL_ENABLE_MASK); + unsigned int value; + int err; + + err = regmap_write(chip->regmap, NCT7201_REG_CONFIGURATION, + NCT7201_BIT_CONFIGURATION_RESET); + if (err) + return dev_err_probe(dev, err, "Failed to reset chip\n"); + + /* + * After about 25 msecs, the device should be ready and then the Power + * Up bit will be set to 1. If not, wait for it. + */ + fsleep(25000); + err = regmap_read(chip->regmap, NCT7201_REG_BUSY_STATUS, &value); + if (err) + return dev_err_probe(dev, err, "Failed to read busy status\n"); + if (!(value & NCT7201_BIT_PWR_UP)) + return dev_err_probe(dev, -EIO, "Failed to power up after reset\n"); + + /* Enable Channel */ + if (chip->num_vin_channels <= 8) + err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, + NCT7201_REG_CHANNEL_ENABLE_MASK); + else + err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, + &data, sizeof(data)); + if (err) + return dev_err_probe(dev, err, "Failed to enable channel\n"); + + err = regmap_bulk_read(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, + &chip->vin_mask, sizeof(chip->vin_mask)); + if (err) + return dev_err_probe(dev, err, + "Failed to read channel enable register\n"); + + /* Start monitoring if needed */ + err = regmap_set_bits(chip->regmap, NCT7201_REG_CONFIGURATION, + NCT7201_BIT_CONFIGURATION_START); + if (err) + return dev_err_probe(dev, err, "Failed to start monitoring\n"); + + return 0; +} + +static int nct7201_probe(struct i2c_client *client) +{ + const struct nct7201_adc_model_data *model_data; + struct device *dev = &client->dev; + struct nct7201_chip_info *chip; + struct iio_dev *indio_dev; + int ret; + + model_data = i2c_get_match_data(client); + if (!model_data) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*chip)); + if (!indio_dev) + return -ENOMEM; + chip = iio_priv(indio_dev); + + chip->regmap = devm_regmap_init_i2c(client, &nct7201_regmap8_config); + if (IS_ERR(chip->regmap)) + return dev_err_probe(dev, PTR_ERR(chip->regmap), + "Failed to init regmap\n"); + + chip->regmap16 = devm_regmap_init_i2c(client, &nct7201_regmap16_config); + if (IS_ERR(chip->regmap16)) + return dev_err_probe(dev, PTR_ERR(chip->regmap16), + "Failed to init regmap16\n"); + + chip->num_vin_channels = model_data->num_vin_channels; + + chip->dev = dev; + + ret = nct7201_init_chip(chip); + if (ret < 0) + return ret; + + indio_dev->name = model_data->model_name; + indio_dev->channels = model_data->channels; + indio_dev->num_channels = model_data->num_channels; + if (client->irq) + indio_dev->info = &nct7201_info; + else + indio_dev->info = &nct7201_info_no_irq; + indio_dev->modes = INDIO_DIRECT_MODE; + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct i2c_device_id nct7201_id[] = { + { .name = "nct7201", .driver_data = (kernel_ulong_t)&nct7201_model_data }, + { .name = "nct7202", .driver_data = (kernel_ulong_t)&nct7202_model_data }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nct7201_id); + +static const struct of_device_id nct7201_of_match[] = { + { + .compatible = "nuvoton,nct7201", + .data = &nct7201_model_data, + }, + { + .compatible = "nuvoton,nct7202", + .data = &nct7202_model_data, + }, + { } +}; +MODULE_DEVICE_TABLE(of, nct7201_of_match); + +static struct i2c_driver nct7201_driver = { + .driver = { + .name = "nct7201", + .of_match_table = nct7201_of_match, + }, + .probe = nct7201_probe, + .id_table = nct7201_id, +}; +module_i2c_driver(nct7201_driver); + +MODULE_AUTHOR("Eason Yang <j2anfernee@gmail.com>"); +MODULE_DESCRIPTION("Nuvoton NCT7201 voltage monitor driver"); +MODULE_LICENSE("GPL"); -- 2.34.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 2025-04-16 8:17 ` [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 Eason Yang @ 2025-04-16 9:34 ` Andy Shevchenko 2025-04-20 13:03 ` Yu-Hsian Yang 2025-04-18 16:13 ` Jonathan Cameron 1 sibling, 1 reply; 9+ messages in thread From: Andy Shevchenko @ 2025-04-16 9:34 UTC (permalink / raw) To: Eason Yang Cc: jic23, lars, robh, krzk+dt, conor+dt, dlechner, nuno.sa, javier.carrasco.cruz, gstols, alisadariana, tgamblin, olivier.moysan, antoniu.miclaus, eblanc, joao.goncalves, tobias.sperling, marcelo.schmitt, angelogioacchino.delregno, thomas.bonnefille, herve.codina, chanh, KWLIU, yhyang2, linux-iio, devicetree, linux-kernel On Wed, Apr 16, 2025 at 04:17:34PM +0800, Eason Yang wrote: > Add Nuvoton NCT7201/NCT7202 system voltage monitor 12-bit ADC driver > > NCT7201/NCT7202 supports up to 12 analog voltage monitor inputs and up > to 4 SMBus addresses by ADDR pin. Meanwhile, ALERT# hardware event pins > for independent alarm signals, and all the threshold values could be set > for system protection without any timing delay. It also supports reset > input RSTIN# to recover system from a fault condition. > > Currently, only single-edge mode conversion and threshold events are > supported. ... > +#define NCT7201_REG_VIN(i) (i) This doesn't do anything useful. Why do you need this rather useless macro? ... > +struct nct7201_chip_info { > + struct device *dev; This can be derived from the respective regmap. No need to have it here. > + struct regmap *regmap; > + struct regmap *regmap16; > + int num_vin_channels; > + u16 vin_mask; > +}; ... > +struct nct7201_adc_model_data { > + const char *model_name; > + const struct iio_chan_spec *channels; > + const int num_channels; What is the meaning of const here? > + int num_vin_channels; > +}; ... > +#define NCT7201_VOLTAGE_CHANNEL(num) \ > + { \ > + .type = IIO_VOLTAGE, \ > + .indexed = 1, \ > + .channel = (num + 1), \ Parentheses are in a wrong place > + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ > + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ > + .address = num, \ > + .event_spec = nct7201_events, \ > + .num_event_specs = ARRAY_SIZE(nct7201_events), \ > + } ... > +static int nct7201_write_event_config(struct iio_dev *indio_dev, > + const struct iio_chan_spec *chan, > + enum iio_event_type type, > + enum iio_event_direction dir, > + bool state) > +{ > + struct nct7201_chip_info *chip = iio_priv(indio_dev); > + unsigned int mask; > + int err; > + > + if (chan->type != IIO_VOLTAGE) > + return -EOPNOTSUPP; > + mask = BIT(chan->address); Just join this with the definition above. > + if (state) > + chip->vin_mask |= mask; > + else > + chip->vin_mask &= ~mask; > + > + if (chip->num_vin_channels <= 8) > + err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, Remove _1. > + chip->vin_mask); > + else > + err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > + &chip->vin_mask, sizeof(chip->vin_mask)); > + if (err) > + return err; > + > + return 0; As simple as return err; > +} ... > +static int nct7201_init_chip(struct nct7201_chip_info *chip) > +{ > + struct device *dev = chip->dev; Derive this from chip->regmap. > + __le16 data = cpu_to_le16(NCT7201_REG_CHANNEL_ENABLE_MASK); > + unsigned int value; > + int err; > + > + err = regmap_write(chip->regmap, NCT7201_REG_CONFIGURATION, > + NCT7201_BIT_CONFIGURATION_RESET); > + if (err) > + return dev_err_probe(dev, err, "Failed to reset chip\n"); > + > + /* > + * After about 25 msecs, the device should be ready and then the Power > + * Up bit will be set to 1. If not, wait for it. "Up bit" is odd, please be more specific. > + */ > + fsleep(25000); + Blank line. > + err = regmap_read(chip->regmap, NCT7201_REG_BUSY_STATUS, &value); > + if (err) > + return dev_err_probe(dev, err, "Failed to read busy status\n"); > + if (!(value & NCT7201_BIT_PWR_UP)) > + return dev_err_probe(dev, -EIO, "Failed to power up after reset\n"); > + > + /* Enable Channel */ > + if (chip->num_vin_channels <= 8) > + err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > + NCT7201_REG_CHANNEL_ENABLE_MASK); > + else > + err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > + &data, sizeof(data)); > + if (err) > + return dev_err_probe(dev, err, "Failed to enable channel\n"); > + > + err = regmap_bulk_read(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > + &chip->vin_mask, sizeof(chip->vin_mask)); > + if (err) > + return dev_err_probe(dev, err, > + "Failed to read channel enable register\n"); > + > + /* Start monitoring if needed */ > + err = regmap_set_bits(chip->regmap, NCT7201_REG_CONFIGURATION, > + NCT7201_BIT_CONFIGURATION_START); > + if (err) > + return dev_err_probe(dev, err, "Failed to start monitoring\n"); > + > + return 0; > +} ... > + ret = nct7201_init_chip(chip); > + if (ret < 0) Why ' < 0' ? > + return ret; -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 2025-04-16 9:34 ` Andy Shevchenko @ 2025-04-20 13:03 ` Yu-Hsian Yang 2025-04-20 19:45 ` Andy Shevchenko 0 siblings, 1 reply; 9+ messages in thread From: Yu-Hsian Yang @ 2025-04-20 13:03 UTC (permalink / raw) To: Andy Shevchenko Cc: jic23, lars, robh, krzk+dt, conor+dt, dlechner, nuno.sa, javier.carrasco.cruz, gstols, alisadariana, tgamblin, olivier.moysan, antoniu.miclaus, eblanc, joao.goncalves, tobias.sperling, marcelo.schmitt, angelogioacchino.delregno, thomas.bonnefille, herve.codina, chanh, KWLIU, yhyang2, linux-iio, devicetree, linux-kernel Dear Andy, Thanks for the review and the comments. Will fix all, have a few questions (below) Andy Shevchenko <andriy.shevchenko@linux.intel.com> 於 2025年4月16日 週三 下午5:34寫道: > > On Wed, Apr 16, 2025 at 04:17:34PM +0800, Eason Yang wrote: > > Add Nuvoton NCT7201/NCT7202 system voltage monitor 12-bit ADC driver > > > > NCT7201/NCT7202 supports up to 12 analog voltage monitor inputs and up > > to 4 SMBus addresses by ADDR pin. Meanwhile, ALERT# hardware event pins > > for independent alarm signals, and all the threshold values could be set > > for system protection without any timing delay. It also supports reset > > input RSTIN# to recover system from a fault condition. > > > > Currently, only single-edge mode conversion and threshold events are > > supported. > > ... > > > +#define NCT7201_REG_VIN(i) (i) > > This doesn't do anything useful. Why do you need this rather useless macro? > Actually here we should define NCT7201_REG_VIN(i) as (0x00 + i), We simply it as (i). > ... > > > +struct nct7201_chip_info { > > + struct device *dev; > > This can be derived from the respective regmap. No need to have it here. > > > + struct regmap *regmap; > > + struct regmap *regmap16; > > + int num_vin_channels; > > + u16 vin_mask; > > +}; > Use regmap->dev is okay if use regmap API. But if we need to print message not from regmap API, how suggestions to do in this case? The code is in nct7201_init_chip(struct nct7201_chip_info *chip) ... > > + err = regmap_read(chip->regmap, NCT7201_REG_BUSY_STATUS, &value); > > + if (err) > > + return dev_err_probe(dev, err, "Failed to read busy status\n"); > > + if (!(value & NCT7201_BIT_PWR_UP)) > > + return dev_err_probe(dev, -EIO, "Failed to power up after reset\n"); > ... > > > +struct nct7201_adc_model_data { > > + const char *model_name; > > + const struct iio_chan_spec *channels; > > > + const int num_channels; > > What is the meaning of const here? > We don't need const int , just int. > > + int num_vin_channels; > > +}; > > ... > > > +#define NCT7201_VOLTAGE_CHANNEL(num) \ > > + { \ > > + .type = IIO_VOLTAGE, \ > > + .indexed = 1, \ > > + .channel = (num + 1), \ > > Parentheses are in a wrong place > We remove parentheses. > > + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ > > + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ > > + .address = num, \ > > + .event_spec = nct7201_events, \ > > + .num_event_specs = ARRAY_SIZE(nct7201_events), \ > > + } > > ... > > > +static int nct7201_write_event_config(struct iio_dev *indio_dev, > > + const struct iio_chan_spec *chan, > > + enum iio_event_type type, > > + enum iio_event_direction dir, > > + bool state) > > +{ > > + struct nct7201_chip_info *chip = iio_priv(indio_dev); > > + unsigned int mask; > > + int err; > > + > > + if (chan->type != IIO_VOLTAGE) > > + return -EOPNOTSUPP; > > > + mask = BIT(chan->address); > > Just join this with the definition above. > > okay > > + if (state) > > + chip->vin_mask |= mask; > > + else > > + chip->vin_mask &= ~mask; > > + > > + if (chip->num_vin_channels <= 8) > > + err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > > Remove _1. > > > + chip->vin_mask); > > + else > > + err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > > + &chip->vin_mask, sizeof(chip->vin_mask)); > > > + if (err) > > + return err; > > + > > + return 0; > > As simple as > > return err; > > > +} > > ... > > > +static int nct7201_init_chip(struct nct7201_chip_info *chip) > > +{ > > + struct device *dev = chip->dev; > > Derive this from chip->regmap. > > > + __le16 data = cpu_to_le16(NCT7201_REG_CHANNEL_ENABLE_MASK); > > + unsigned int value; > > + int err; > > + > > + err = regmap_write(chip->regmap, NCT7201_REG_CONFIGURATION, > > + NCT7201_BIT_CONFIGURATION_RESET); > > + if (err) > > + return dev_err_probe(dev, err, "Failed to reset chip\n"); > > + > > + /* > > + * After about 25 msecs, the device should be ready and then the Power > > + * Up bit will be set to 1. If not, wait for it. > > "Up bit" is odd, please be more specific. > > > + */ > > + fsleep(25000); > > + Blank line. > > > + err = regmap_read(chip->regmap, NCT7201_REG_BUSY_STATUS, &value); > > + if (err) > > + return dev_err_probe(dev, err, "Failed to read busy status\n"); > > + if (!(value & NCT7201_BIT_PWR_UP)) > > + return dev_err_probe(dev, -EIO, "Failed to power up after reset\n"); > > + > > + /* Enable Channel */ > > + if (chip->num_vin_channels <= 8) > > + err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > > + NCT7201_REG_CHANNEL_ENABLE_MASK); > > + else > > + err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > > + &data, sizeof(data)); > > + if (err) > > + return dev_err_probe(dev, err, "Failed to enable channel\n"); > > + > > + err = regmap_bulk_read(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > > + &chip->vin_mask, sizeof(chip->vin_mask)); > > + if (err) > > + return dev_err_probe(dev, err, > > + "Failed to read channel enable register\n"); > > + > > + /* Start monitoring if needed */ > > + err = regmap_set_bits(chip->regmap, NCT7201_REG_CONFIGURATION, > > + NCT7201_BIT_CONFIGURATION_START); > > + if (err) > > + return dev_err_probe(dev, err, "Failed to start monitoring\n"); > > + > > + return 0; > > +} > > ... > > > + ret = nct7201_init_chip(chip); > > + if (ret < 0) > > Why ' < 0' ? > > > + return ret; > > -- > With Best Regards, > Andy Shevchenko > > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 2025-04-20 13:03 ` Yu-Hsian Yang @ 2025-04-20 19:45 ` Andy Shevchenko 0 siblings, 0 replies; 9+ messages in thread From: Andy Shevchenko @ 2025-04-20 19:45 UTC (permalink / raw) To: Yu-Hsian Yang Cc: Andy Shevchenko, jic23, lars, robh, krzk+dt, conor+dt, dlechner, nuno.sa, javier.carrasco.cruz, gstols, alisadariana, tgamblin, olivier.moysan, antoniu.miclaus, eblanc, joao.goncalves, tobias.sperling, marcelo.schmitt, angelogioacchino.delregno, thomas.bonnefille, herve.codina, chanh, KWLIU, yhyang2, linux-iio, devicetree, linux-kernel Sun, Apr 20, 2025 at 09:03:05PM +0800, Yu-Hsian Yang kirjoitti: > Andy Shevchenko <andriy.shevchenko@linux.intel.com> 於 2025年4月16日 週三 下午5:34寫道: > > On Wed, Apr 16, 2025 at 04:17:34PM +0800, Eason Yang wrote: ... > > > +#define NCT7201_REG_VIN(i) (i) > > > > This doesn't do anything useful. Why do you need this rather useless macro? > > > > Actually here we should define NCT7201_REG_VIN(i) as (0x00 + i), > We simply it as (i). Please, don't. Use the full form which makes a big difference to the perception of this macro. ... > > > +struct nct7201_chip_info { > > > + struct device *dev; > > > > This can be derived from the respective regmap. No need to have it here. > > > > > + struct regmap *regmap; > > > + struct regmap *regmap16; > > > + int num_vin_channels; > > > + u16 vin_mask; > > > +}; > > Use regmap->dev is okay if use regmap API. No, you are not supposed to use regmap->dev (and you can't), you need to call a getter API and get the device pointer. > But if we need to print message not from regmap API, I don't get this. What do you mean? The example you showed prints a message for the device. The same device that was used to create a regmap. > how suggestions to do in this case? Use the one that you can retrieve from regmap. ... So, you have commented on some with agreement, and left uncommented a lot. Does it mean you are agree on all points? The rule of thumb do not comment on the cases you are fully agree with. Current email just makes a confusion. -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 2025-04-16 8:17 ` [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 Eason Yang 2025-04-16 9:34 ` Andy Shevchenko @ 2025-04-18 16:13 ` Jonathan Cameron 2025-04-19 15:23 ` Andy Shevchenko 1 sibling, 1 reply; 9+ messages in thread From: Jonathan Cameron @ 2025-04-18 16:13 UTC (permalink / raw) To: Eason Yang Cc: lars, robh, krzk+dt, conor+dt, dlechner, nuno.sa, javier.carrasco.cruz, gstols, alisadariana, tgamblin, olivier.moysan, antoniu.miclaus, eblanc, andriy.shevchenko, joao.goncalves, tobias.sperling, marcelo.schmitt, angelogioacchino.delregno, thomas.bonnefille, herve.codina, chanh, KWLIU, yhyang2, linux-iio, devicetree, linux-kernel On Wed, 16 Apr 2025 16:17:34 +0800 Eason Yang <j2anfernee@gmail.com> wrote: > Add Nuvoton NCT7201/NCT7202 system voltage monitor 12-bit ADC driver > > NCT7201/NCT7202 supports up to 12 analog voltage monitor inputs and up > to 4 SMBus addresses by ADDR pin. Meanwhile, ALERT# hardware event pins > for independent alarm signals, and all the threshold values could be set > for system protection without any timing delay. It also supports reset > input RSTIN# to recover system from a fault condition. > > Currently, only single-edge mode conversion and threshold events are > supported. > > Signed-off-by: Eason Yang <j2anfernee@gmail.com> Hi Eason, A few trivial things from another glance through. Thanks, Jonathan > + > +static const struct nct7201_adc_model_data nct7201_model_data = { > + .model_name = "nct7201", > + .channels = nct7201_channels, > + .num_channels = ARRAY_SIZE(nct7201_channels), > + .num_vin_channels = 8, > +}; > + > +static const struct nct7201_adc_model_data nct7202_model_data = { > + .model_name = "nct7202", > + .channels = nct7202_channels, > + .num_channels = ARRAY_SIZE(nct7202_channels), > + .num_vin_channels = 12, > +}; > + > +static int nct7201_init_chip(struct nct7201_chip_info *chip) > +{ > + struct device *dev = chip->dev; > + __le16 data = cpu_to_le16(NCT7201_REG_CHANNEL_ENABLE_MASK); Assign this value down near where it is used. That will generally help readability. > + unsigned int value; > + int err; > + > + err = regmap_write(chip->regmap, NCT7201_REG_CONFIGURATION, > + NCT7201_BIT_CONFIGURATION_RESET); > + if (err) > + return dev_err_probe(dev, err, "Failed to reset chip\n"); > + > + /* > + * After about 25 msecs, the device should be ready and then the Power > + * Up bit will be set to 1. If not, wait for it. I'd hyphenate power-up perhaps. > + */ > + fsleep(25000); > + err = regmap_read(chip->regmap, NCT7201_REG_BUSY_STATUS, &value); > + if (err) > + return dev_err_probe(dev, err, "Failed to read busy status\n"); > + if (!(value & NCT7201_BIT_PWR_UP)) > + return dev_err_probe(dev, -EIO, "Failed to power up after reset\n"); > + > + /* Enable Channel */ > + if (chip->num_vin_channels <= 8) > + err = regmap_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > + NCT7201_REG_CHANNEL_ENABLE_MASK); This is a little odd as I think you are writing an 8 bit register with a 12 bit mask. Sure it works, but confusing thing to see. If some future 6 channel device comes along this <= 8 will seem odd too. Maybe generate the mask from teh number of channels? > + else > + err = regmap_bulk_write(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > + &data, sizeof(data)); > + if (err) > + return dev_err_probe(dev, err, "Failed to enable channel\n"); > + > + err = regmap_bulk_read(chip->regmap, NCT7201_REG_CHANNEL_ENABLE_1, > + &chip->vin_mask, sizeof(chip->vin_mask)); > + if (err) > + return dev_err_probe(dev, err, > + "Failed to read channel enable register\n"); > + > + /* Start monitoring if needed */ > + err = regmap_set_bits(chip->regmap, NCT7201_REG_CONFIGURATION, > + NCT7201_BIT_CONFIGURATION_START); > + if (err) > + return dev_err_probe(dev, err, "Failed to start monitoring\n"); > + > + return 0; > +} ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 2025-04-18 16:13 ` Jonathan Cameron @ 2025-04-19 15:23 ` Andy Shevchenko 0 siblings, 0 replies; 9+ messages in thread From: Andy Shevchenko @ 2025-04-19 15:23 UTC (permalink / raw) To: Jonathan Cameron Cc: Eason Yang, lars, robh, krzk+dt, conor+dt, dlechner, nuno.sa, javier.carrasco.cruz, gstols, alisadariana, tgamblin, olivier.moysan, antoniu.miclaus, eblanc, joao.goncalves, tobias.sperling, marcelo.schmitt, angelogioacchino.delregno, thomas.bonnefille, herve.codina, chanh, KWLIU, yhyang2, linux-iio, devicetree, linux-kernel On Fri, Apr 18, 2025 at 05:13:26PM +0100, Jonathan Cameron wrote: > On Wed, 16 Apr 2025 16:17:34 +0800 > Eason Yang <j2anfernee@gmail.com> wrote: ... > > + struct device *dev = chip->dev; > > + __le16 data = cpu_to_le16(NCT7201_REG_CHANNEL_ENABLE_MASK); > > Assign this value down near where it is used. That will generally help > readability. Actually it is a good, but not a main reason, the problem with this style is long-term maintenance when some code may appear in between and become so long that one can screw up this assignment at some point. -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-04-20 19:45 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-04-16 8:17 [PATCH v6 0/2] iio: adc: add Nuvoton NCT7201 ADC driver Eason Yang 2025-04-16 8:17 ` [PATCH v6 1/2] dt-bindings: iio: adc: add NCT7201 ADCs Eason Yang 2025-04-17 6:20 ` Krzysztof Kozlowski 2025-04-16 8:17 ` [PATCH v6 2/2] iio: adc: add support for Nuvoton NCT7201 Eason Yang 2025-04-16 9:34 ` Andy Shevchenko 2025-04-20 13:03 ` Yu-Hsian Yang 2025-04-20 19:45 ` Andy Shevchenko 2025-04-18 16:13 ` Jonathan Cameron 2025-04-19 15:23 ` Andy Shevchenko
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox