RE: [PATCH v2 5/5] drivers: iio: adc: Add MAX77541 ADC Support

From: Sahin, Okan
Date: Sun Jan 15 2023 - 08:03:56 EST


Hi Jonathan,

Thank you for your feedback and efforts. I apologize for some missing points of v2 patch. I will be more careful to fix all feedback before sending new patch so I want to ask something before sending v3 patch.

On Fri, 30 Dec 2022 8:50 PM
Jonathan Cameron <jic23@xxxxxxxxxx> wrote:

> On Tue, 27 Dec 2022 01:38:39 +0300
> Okan Sahin <okan.sahin@xxxxxxxxxx> wrote:
>
> > The MAX77541 has an 8-bit Successive Approximation Register (SAR) ADC
> > with four multiplexers for supporting the telemetry feature
> >
> > Signed-off-by: Okan Sahin <okan.sahin@xxxxxxxxxx>
>
> If there is a v3 please send the whole series to everyone who is cc'd on any of
> the patches in this version. For a driver like this, it's much better to let people
> pick and choose which bits they are interested in than to only send part of it to
> each list / reviewer.
>
> I took a closer look at the offsets / scales this time. They don't appear to
> comply with the ABI. Whilst 'most' IIO units are SI units, a few have units
> borrowed from hwmon including temperature and voltage - this brings some
> multiplication factors that need to be taken into account.
>
> Jonathan
>
> > ---
> > MAINTAINERS | 1 +
> > drivers/iio/adc/Kconfig | 11 ++
> > drivers/iio/adc/Makefile | 1 +
> > drivers/iio/adc/max77541-adc.c | 199
> > +++++++++++++++++++++++++++++++++
> > 4 files changed, 212 insertions(+)
> > create mode 100644 drivers/iio/adc/max77541-adc.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS index
> > 8e5572b28a8c..18ce4644cc75 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -12503,6 +12503,7 @@ L: linux-kernel@xxxxxxxxxxxxxxx
> > S: Maintained
> > F: Documentation/devicetree/bindings/mfd/adi,max77541.yaml
> > F: Documentation/devicetree/bindings/regulator/adi,max77541.yaml
> > +F: drivers/iio/adc/max77541-adc.c
> > F: drivers/mfd/max77541.c
> > F: drivers/regulator/max77541-regulator.c
> > F: include/linux/mfd/max77541.h
> > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index
> > 791612ca6012..9716225b50da 100644
> > --- a/drivers/iio/adc/Kconfig
> > +++ b/drivers/iio/adc/Kconfig
> > @@ -696,6 +696,17 @@ config MAX1363
> > To compile this driver as a module, choose M here: the module will be
> > called max1363.
> >
> > +config MAX77541_ADC
> > + tristate "Analog Devices MAX77541 ADC driver"
> > + depends on MFD_MAX77541
> > + help
> > + This driver controls a Analog Devices MAX77541 ADC
> > + via I2C bus. This device has one adc. Say yes here to build
> > + support for Analog Devices MAX77541 ADC interface.
> > +
> > + To compile this driver as a module, choose M here:
> > + the module will be called max77541-adc.
> > +
> > config MAX9611
> > tristate "Maxim max9611/max9612 ADC driver"
> > depends on I2C
> > diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index
> > 46caba7a010c..03774cccbb4b 100644
> > --- a/drivers/iio/adc/Makefile
> > +++ b/drivers/iio/adc/Makefile
> > @@ -64,6 +64,7 @@ obj-$(CONFIG_MAX1118) += max1118.o
> > obj-$(CONFIG_MAX11205) += max11205.o
> > obj-$(CONFIG_MAX1241) += max1241.o
> > obj-$(CONFIG_MAX1363) += max1363.o
> > +obj-$(CONFIG_MAX77541_ADC) += max77541-adc.o
> > obj-$(CONFIG_MAX9611) += max9611.o
> > obj-$(CONFIG_MCP320X) += mcp320x.o
> > obj-$(CONFIG_MCP3422) += mcp3422.o
> > diff --git a/drivers/iio/adc/max77541-adc.c
> > b/drivers/iio/adc/max77541-adc.c new file mode 100644 index
> > 000000000000..29adcdbd96ae
> > --- /dev/null
> > +++ b/drivers/iio/adc/max77541-adc.c
> > @@ -0,0 +1,199 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Copyright (c) 2022 Analog Devices, Inc.
> > + * ADI MAX77541 ADC Driver with IIO interface */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/iio/iio.h>
> > +#include <linux/mfd/max77541.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/driver.h>
> > +#include <linux/regulator/of_regulator.h> #include <linux/units.h>
> > +
> > +#define MAX77541_ADC_CHANNEL(_channel, _name, _type, _reg) \
> > + { \
> > + .type = _type, \
> > + .indexed = 1, \
> > + .channel = _channel, \
> > + .address = _reg, \
> > + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> > + BIT(IIO_CHAN_INFO_SCALE) |\
> > + BIT(IIO_CHAN_INFO_OFFSET),\
> > + .datasheet_name = _name, \
> > + }
>
> Move this macro down to just above where it is used. Given the purpose of this
> is to reduce boilerplate repetition we want to review what it does based on the
> values provided. That's much easier if we don't have to go look for the macro.
>
> > +
> > +enum max77541_adc_range {
> > + LOW_RANGE,
> > + MID_RANGE,
> > + HIGH_RANGE,
> > +};
> > +
> > +struct max77541_adc_iio {
> > + struct regmap *regmap;
> > +};
> > +
> > +enum max77541_adc_channel {
> > + MAX77541_ADC_VSYS_V = 0,
> > + MAX77541_ADC_VOUT1_V,
> > + MAX77541_ADC_VOUT2_V,
> > + MAX77541_ADC_TEMP,
> > +};
> > +
> > +static int max77541_adc_offset(struct iio_dev *indio_dev,
> > + struct iio_chan_spec const *chan,
> > + int *val, int *val2)
> > +{
> > + switch (chan->channel) {
> > + case MAX77541_ADC_VSYS_V:
> > + case MAX77541_ADC_VOUT1_V:
> > + case MAX77541_ADC_VOUT2_V:
> > + *val = 0;
> > + *val2 = 0;
> > + return IIO_VAL_INT_PLUS_MICRO;
>
> I thought I mentioned this before. For cases where the offset is 0 don't set the
> bit in info_mask_seperate and don't provide an implementation to read it.
>
> > + case MAX77541_ADC_TEMP:
> > + *val = DIV_ROUND_CLOSEST(ABSOLUTE_ZERO_MILLICELSIUS,
> > + MILLIDEGREE_PER_DEGREE);
> > + *val2 = 0;
>
> If *val2 == 0
> then the return type should be IIO_VAL_INT allowing any code using this to
> handle it as an integer, not a fixed point number.
>
> I'd also like a comment here to explain the maths being done.
> Base units of temperature are mili degrees Celsius and the offset looks wrong
> anyway as it doesn't take into account that in datasheet it is applied after scale,
> whereas in IIO ABI it needs to be applied first (thus requiring it to be divided by
> scale) https://urldefense.com/v3/__https://elixir.bootlin.com/linux/v6.2-
> rc1/source/Documentation/ABI/testing/sysfs-bus-
> iio*L244__;Iw!!A3Ni8CS0y2Y!7FLhRoK07ZzeEcEw_H5bPRrK-Dpnrs-mBOV-
> mWXiEWRQQZDa3F89L6WaGw0St2sFxPgtGhIznNbdig$
>
> So what you currently have is
> 1LSB = 1.725*(raw + -273/1000)
> I think it should be - based on equation (-273 + 1.725 * ADC_DATA6) deg C 1LSB
> = 1725*(raw - 273/1725) so offset should be -273/1725 and scale should be
> 1725.
>
> Also check scaling is right for voltage channels - noting that voltage channels are
> expressed in milivolts I suspect the sale should therefore be 25 but I haven't
> checked it closely.
>
>
>
> > + return IIO_VAL_INT_PLUS_MICRO;
> > + default:
> > + return -EINVAL;
> > + }
> > +}
> > +
>
>
>
> As noted above, put the macro definition here so it is easy to see what this does.
>
> > +static const struct iio_chan_spec max77541_adc_channels[] = {
> > + MAX77541_ADC_CHANNEL(MAX77541_ADC_VSYS_V, "vsys_v",
> IIO_VOLTAGE,
> > + MAX77541_REG_ADC_DATA_CH1),
> > + MAX77541_ADC_CHANNEL(MAX77541_ADC_VOUT1_V, "vout1_v",
> IIO_VOLTAGE,
> > + MAX77541_REG_ADC_DATA_CH2),
> > + MAX77541_ADC_CHANNEL(MAX77541_ADC_VOUT2_V, "vout2_v",
> IIO_VOLTAGE,
> > + MAX77541_REG_ADC_DATA_CH3),
> > + MAX77541_ADC_CHANNEL(MAX77541_ADC_TEMP, "temp", IIO_TEMP,
> > + MAX77541_REG_ADC_DATA_CH6),
> > +};
> > +
>
> > +
> > +static int max77541_adc_probe(struct platform_device *pdev) {
> > + struct max77541_dev *max77541 = dev_get_drvdata(pdev-
> >dev.parent);
>
> I can't easily see other parts of the mfd (as not cc'd on rest of series), but from
> what is here it might be nice to set the drvdata to the regmap rather than the
> mfd driver specific structure.
>
This is my mistake, I will send whole patches to people who related them at once. As you said I just need regmap from parent mfd device. I think below is what you expect, right? I will also remove dev_get_drv_data.
struct device *dev = &pdev->dev;
struct regmap *map = dev_get_regmap(dev->parent, NULL);

> > + struct device *dev = &pdev->dev;
> > + struct max77541_adc_iio *info;
> > + struct iio_dev *indio_dev;
> > +
> > + indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
> > + if (!indio_dev)
> > + return -ENOMEM;
> > +
> > + info = iio_priv(indio_dev);
> > +
> > + info->regmap = max77541->regmap;
> > + indio_dev->modes = INDIO_DIRECT_MODE;
> > +
> > + indio_dev->name = platform_get_device_id(pdev)->name;
>
> I would prefer to see that hard coded. Also, from an IIO point of view this
> should just be the part number which is "max77541"
> without the -adc postfix.
>
> The advantage of hard coding it is I don't need to think about what indio_dev-
> >name = "max77541"; sets it to thus reducing the complexity of reviewing a
> little.
> Note that similar cases have gone wrong in the past and we've ended up stuck
> with hideous ABI for a few device names so I'm paranoid about this now.
>
>
> > + indio_dev->info = &max77541_adc_info;
> > + indio_dev->channels = max77541_adc_channels;
> > + indio_dev->num_channels = ARRAY_SIZE(max77541_adc_channels);
> > +
> > + return devm_iio_device_register(dev, indio_dev);
> > +}
> > +
> > +static const struct platform_device_id max77541_adc_platform_id[] = {
> > + { "max77541-adc", },
> > + { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(platform, max77541_adc_platform_id);
> > +
> > +static struct platform_driver max77541_adc_driver = {
> > + .driver = {
> > + .name = "max77541-adc",
> > + },
> > + .probe = max77541_adc_probe,
> > + .id_table = max77541_adc_platform_id,
> > +};
> > +module_platform_driver(max77541_adc_driver);
> > +
> > +MODULE_AUTHOR("Okan Sahin <Okan.Sahin@xxxxxxxxxx>");
> > +MODULE_DESCRIPTION("MAX77541 ADC driver");
> > +MODULE_LICENSE("GPL");