Re: [PATCH v7 2/2] iio: adc: ti-ads112c04: Add support for TI ADS112C04
Andy Shevchenko <[email protected]>
| Newsgroups | org.kernel.vger.linux-iio,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Organization | Intel Finland Oy - BIC 0357606-4 - c/o Alberga Business Park, 6 krs, Bertel Jungin Aukio 5, 02600 Espoo |
| Message-ID | <[email protected]> |
On Mon, Aug 24, 2026 at 04:49:39PM +0800, Kyle Hsieh wrote: > Add IIO driver support for the Texas Instruments ADS112C04 (16-bit) > delta-sigma ADCs. > > The driver implements: > - Single-shot conversions using the IIO raw read interface. > - Dynamic parsing of single-ended and differential channels from > device tree child nodes. > - Hardware interrupt support via the DRDY pin, falling back to > software polling if no IRQ is provided. > - Per-channel reference source selection (internal 2.048V, external > REFP/REFN, or AVDD) via the reference-sources device tree property. > refn-supply is not yet supported. > - Hardware reset via the reset controller framework, falling back to > the RESET command when no reset controller is present. FWIW, Reviewed-by: Andy Shevchenko <[email protected]> ... > +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; > + > + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); > + if (!indio_dev) > + return -ENOMEM; > + > + st = iio_priv(indio_dev); > + st->client = client; > + > + ret = devm_mutex_init(dev, &st->lock); > + if (ret) > + return ret; > + > + init_completion(&st->completion); > + > + indio_dev->name = "ads112c04"; > + indio_dev->modes = INDIO_DIRECT_MODE; > + indio_dev->info = &ads112c04_info; > + > + /* Forward compatibility checks for unimplemented DT properties */ > + if (device_property_present(dev, "refn-supply") || > + device_property_present(dev, "ti,refp-refn-resistor-ohms")) > + return dev_err_probe(dev, -EOPNOTSUPP, > + "refn-supply and external resistors are not supported yet\n"); > + > + ret = ads112c04_parse_channels(indio_dev, &need_avdd_ref, &need_ext_ref); > + if (ret) > + return ret; > + > + if (need_avdd_ref) { > + ret = devm_regulator_get_enable_read_voltage(dev, "avdd"); > + if (ret < 0) > + return dev_err_probe(dev, ret, "failed to get avdd voltage\n"); > + > + st->avdd_mV = ret / (MICRO / MILLI); > + } else { > + ret = devm_regulator_get_enable(dev, "avdd"); > + if (ret) > + return dev_err_probe(dev, ret, "failed to get avdd regulator\n"); > + } > + > + ret = devm_regulator_get_enable(dev, "dvdd"); > + if (ret) > + return dev_err_probe(dev, ret, "failed to get dvdd regulator\n"); > + > + if (device_property_present(dev, "refp-supply")) { > + ret = devm_regulator_get_enable_read_voltage(dev, "refp"); > + if (ret < 0) > + return dev_err_probe(dev, ret, "failed to get refp voltage\n"); > + > + st->ext_ref_mV = ret / (MICRO / MILLI); > + } > + > + if (need_ext_ref && !st->ext_ref_mV) > + return dev_err_probe(dev, -EINVAL, > + "external reference measurements require refp-supply\n"); > + > + /* 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) { > + /* Datasheet: tw(RSL), the RESET low pulse, is 250ns minimum */ > + fsleep(1); > + > + ret = reset_control_deassert(reset); > + if (ret) > + return dev_err_probe(dev, ret, "failed to deassert reset\n"); > + } else { > + ret = ads112c04_write_cmd(client, ADS112C04_CMD_RESET); > + if (ret < 0) > + return ret; > + } > + > + /* Datasheet: td(RSSTA) is 100ns minimum after the RESET rising edge */ > + fsleep(1); Perhaps simply ndelay(100) ? > + /* > + * Initialize CONFIG0 with all fields explicit: gain of 1 with the PGA > + * bypassed, which allows full-scale single-ended measurements. The MUX > + * field is updated per channel before each conversion. > + */ > + st->config0 = FIELD_PREP(ADS112C04_CONF0_MUX, > + ADS112C04_CONF0_MUX_AIN0_AIN1) | > + FIELD_PREP(ADS112C04_CONF0_GAIN, > + ADS112C04_CONF0_GAIN_X1) | > + ADS112C04_CONF0_PGA_BYPASS; > + > + ret = ads112c04_write_reg(client, ADS112C04_REG_CONFIG0, st->config0); > + if (ret) > + return ret; > + > + st->config1 = FIELD_PREP(ADS112C04_CONF1_DR, > + ADS112C04_CONF1_DR_20SPS) | > + FIELD_PREP(ADS112C04_CONF1_MODE, > + ADS112C04_CONF1_MODE_NORMAL) | > + FIELD_PREP(ADS112C04_CONF1_CM, > + ADS112C04_CONF1_CM_SINGLE_SHOT) | > + FIELD_PREP(ADS112C04_CONF1_VREF, > + ADS112C04_CONF1_VREF_INTERNAL) | > + FIELD_PREP(ADS112C04_CONF1_TS, > + ADS112C04_CONF1_TS_DISABLED); > + > + ret = ads112c04_write_reg(client, ADS112C04_REG_CONFIG1, st->config1); > + if (ret) > + return ret; > + > + if (client->irq > 0) { > + ret = devm_request_irq(dev, client->irq, ads112c04_irq_handler, 0, > + indio_dev->name, indio_dev); > + if (ret) > + return ret; > + } > + > + return devm_iio_device_register(dev, indio_dev); > +} -- With Best Regards, Andy Shevchenko