Re: [PATCH v6 2/2] iio: adc: ti-ads112c04: Add support for TI ADS112C04

Kyle Hsieh <[email protected]>
Newsgroups org.kernel.vger.linux-iio,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel
Message-ID <CAF7HswMT-e87oapWSw11-Qhj570wLDiayKeSP5vuYo9Fm9AbxQ@mail.gmail.com>
On Sun, Aug 23, 2026 at 8:06 AM David Lechner <[email protected]> wrote:
>
> On 8/20/26 2:51 AM, Kyle Hsieh wrote:
> > Add IIO driver support for the Texas Instruments ADS112C04 (16-bit)
> > delta-sigma ADCs.
> >
>
> ...
>
> > +static int ads112c04_parse_channels(struct iio_dev *indio_dev,
> > +                                 bool *need_avdd_ref, bool *need_ext_ref)
> > +{
> > +     struct device *dev = indio_dev->dev.parent;
> > +     struct ads112c04_state *st = iio_priv(indio_dev);
> > +     struct iio_chan_spec *channels;
> > +     u32 num_channels, pair[2], channel;
> > +     unsigned int i;
> > +     int ret;
> > +
> > +     num_channels = device_get_named_child_node_count(dev, "channel");
> > +     if (!num_channels)
> > +             return dev_err_probe(dev, -EINVAL, "no channel subnodes found\n");
> > +
> > +     if (num_channels > ADS112C04_MAX_CHANNELS)
> > +             return dev_err_probe(dev, -EINVAL,
> > +                                  "num of channel nodes exceeds %d\n",
> > +                                  ADS112C04_MAX_CHANNELS);
> > +
> > +     channels = devm_kcalloc(dev, num_channels, sizeof(*channels), GFP_KERNEL);
> > +     if (!channels)
> > +             return -ENOMEM;
> > +
> > +     st->vref_source = devm_kcalloc(dev, num_channels,
> > +                                    sizeof(*st->vref_source), GFP_KERNEL);
> > +     if (!st->vref_source)
> > +             return -ENOMEM;
> > +
> > +     i = 0;
> > +     device_for_each_named_child_node_scoped(dev, child, "channel") {
> > +             const char *sp = "single-channel", *dp = "diff-channels";
>
> What does the "p" mean? I would make the names the same as the string,
> e.g. sc, dc, or s_chan, d_chan since they are used quite far from here.

Renamed to s_chan and d_chan in v7.
>
> > +             struct iio_chan_spec *spec = &channels[i];
> > +
> > +             if (fwnode_property_present(child, "excitation-channels"))
> > +                     return dev_err_probe(dev, -EOPNOTSUPP,
> > +                                          "excitation-channels is not supported yet\n");
> > +
> > +             st->vref_source[i] = ADS112C04_VREF_SOURCE_INTERNAL;
> > +
> > +             if (fwnode_property_present(child, "reference-sources")) {
>
> ads112c04_parse_vref_source() already calls fwnode_property_present(child, "reference-sources")
> and returns ADS112C04_VREF_SOURCE_INTERNAL as default, so we are duplicating that
> logic here. Either drop the helper or drop the extra code here.

Dropped the extra code in the loop and now call the helper directly.
>
> > +                     ret = ads112c04_parse_vref_source(child);
> > +                     if (ret < 0)
> > +                             return dev_err_probe(dev, ret,
> > +                                                  "invalid reference-sources value\n");
> > +
> > +                     st->vref_source[i] = ret;
> > +             }
> > +
> > +             if (st->vref_source[i] == ADS112C04_VREF_SOURCE_EXTERNAL)
> > +                     *need_ext_ref = true;
>
> Can just assign these directly:
>
>                 *need_ext_ref = st->vref_source[i] == ADS112C04_VREF_SOURCE_EXTERNAL;

I used |= instead of = here: the flags accumulate across all channels,
so a plain assignment would let a later channel clear what an earlier
one set. For example with channel 0 on "external" and channel 1 on
"internal", *need_ext_ref would end up false and probe would skip
reading the refp voltage.
>
> > +             if (st->vref_source[i] == ADS112C04_VREF_SOURCE_AVDD)
> > +                     *need_avdd_ref = true;
> > +
>
> ...
>
> > +
> > +             i++;
> > +     }
> > +
> > +     indio_dev->channels = channels;
> > +     indio_dev->num_channels = i;
> > +
> > +     return 0;
> > +}
> > +
> > +static int ads112c04_probe(struct i2c_client *client)
> > +{
> > +     struct device *dev = &client->dev;
> > +     struct iio_dev *indio_dev;
> > +     struct ads112c04_state *st;
> > +     struct reset_control *reset;
> > +     bool need_avdd_ref = false, need_ext_ref = false;
> > +     int ret;
> > +
>
> ...
>
> > +     /* Datasheet: POR releases ~500us after supplies are stable */
> > +     fsleep(500);
> > +
> > +     reset = devm_reset_control_get_optional_exclusive(dev, NULL);
> > +     if (IS_ERR(reset))
> > +             return dev_err_probe(dev, PTR_ERR(reset), "failed to get reset\n");
> > +
> > +     if (reset) {
>
> I'm pretty sure devm_reset_control_get_optional_exclusive() already asserts
> the reset. So the way this is usally implemented is that we get (assert)
> the rest, then wait chip-specific time (usually a few microsonds) then
> reset_control_deassert().
>
> I don't see any other IIO drivers that are using reset_control_reset().
> (And I think a lot might be calling reset_control_assert() unnecissaraly.)
>

You're right - reset-gpio requests the GPIO with GPIOD_OUT_HIGH, so the
reset is already asserted by the time we get the control. Changed to
waiting tw(RSL) and then calling reset_control_deassert(). That also
makes the pulse width explicit, rather than relying on the assert and
deassert inside reset_control_reset() happening to be far enough apart.
> > +             ret = reset_control_reset(reset);
> > +             if (ret)
> > +                     return dev_err_probe(dev, ret, "failed to reset device\n");
> > +     } else {
> > +             ret = ads112c04_write_cmd(client, ADS112C04_CMD_RESET);
> > +             if (ret < 0)
> > +                     return ret;
> > +     }
> > +
>
> If it wasn't for the duplicate code, I might have said good enough. :-)

Thanks,
Kyle
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.