From nobody Fri Jul 24 21:30:26 2026 Received: from mail-ot1-f43.google.com (mail-ot1-f43.google.com [209.85.210.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 62C17438013 for ; Fri, 24 Jul 2026 15:55:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784908534; cv=none; b=HC6AwumMcFYit62PaakR29/wqErtPxNbFlloTa1l21SpK+q1YwDRaS/w7Nf1raWzTk//VwedCzLzGIO5vEQeuPeupgpGUiUM8SGza3xC/7uq5o1HczTCIoTTmV0VJ46S7YraebFVa0xWtIgolOe6u/sXKp6SGGyO8RPEIYUg83c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784908534; c=relaxed/simple; bh=dcCEzrZwMSfx3DWIcC8GUj8ZmcNyvugLuhei4vuJGKk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=sNQmCpmHlSHS5mMlAAiggOq5yKWPSjIqwxshm5EIAqrIoqWJyTTCtflbtvo6IpMKfPdy98NcDdN7gMW29dkI+SHjuktXR4MjcZm+0XcsaaUlhfGPQd7DemdSzAOvPW72z7wFw9P+QOQWVGyNvozdzy5N5BzFztsbeSpFNrTSmOM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b=QImXs0++; arc=none smtp.client-ip=209.85.210.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b="QImXs0++" Received: by mail-ot1-f43.google.com with SMTP id 46e09a7af769-7e9ecb1e13bso216797a34.2 for ; Fri, 24 Jul 2026 08:55:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre.com; s=google; t=1784908531; x=1785513331; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=gFZUN3bOyJenYTXOz12PesK/e4uk1yrjbC3h5hckLZE=; b=QImXs0++KH8UsCvffHYMUEy63WrfiyHtL39swTNQGs1uEoSROvs/hUrILtUGPL5CCS TMGZ95oE6KhZhlg/6yY/HBSxCImGvMDyaRHYvYnc9yRpJ0aXdarGXwstwk27m1q/mtij FlWDdkEj2XSMa8ldle6TlnaYdjHNswb3M0d10nKqXeWOoZuVuQaZbMZ3hYkVQ9DtbEkZ nKu08v+g68ldUYK6EDVO2LHsR20m29CVPIZ5T9COamqjPRRz4hNLNRmTCWx1vnpGopyB JZoogvyoNBOP2PEByB47eoyr9MNTcyBEPc3G6lr2dPbUUE5JLz7hH/DcdFk+dlRZe6J/ 9BBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784908531; x=1785513331; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=gFZUN3bOyJenYTXOz12PesK/e4uk1yrjbC3h5hckLZE=; b=cYOhreUC8MlOzcVlRUl/eyhPHGEFTnVXOW2sUiKFOv7ReG4vRRl60TkMYuX0IXDGlE qu1uFJpOK/Q/AvR+fRX0XzakHpYohVQW+6LM7cxVIEJY1W0wgTu6W3VDy14QQL2UOiUD jyzN4kA/kZb9QJjxSRQoiHOdwOb+g8WhBmYqOT4AqTuBwtcOuyfWewsiM++AKfpOUeR9 UG8/ow2HbCJuVxw5pm9EOyvI9HhAhB9RzFFvH1tGEE+JQjZFPDKoWdEEZiHUFr3SQlyO QJr5M7SCKRhygQsqdWZYA6uiu9IPACkoOUH4znL+b8thZg8GbwID6sjRlQjditYgqhOr yfSA== X-Forwarded-Encrypted: i=1; AHgh+RpuzJWlFfV+1+9Sn2vBSoRtAszsdC8la+RiFG41DxB2OOX3Ob9aB+IukqYwwh+L6c3dIJPB+foi2WWitL4=@vger.kernel.org X-Gm-Message-State: AOJu0YwMNtfH9Pq9OkwBWW/lMzvb8TTICGwqOMYukhEgh9aaia7/VIyJ NetbufUhsJ4xrrnCa7BqI9gcY5YZwxpWUG+YLNpZrgaz/oDaXfFv02pCzz2v2oQV7vQ= X-Gm-Gg: AR+sD11uyPMrVJrTaA4ZmNWTTQMmhXjfcHSXLnrjhWC0AajcL5XkWjz90WXxVlSVOh9 7sUQQz1poUsmxol69RtSDlep6P3/Eeh/+iy5M25RN1RT3APHgu3oJEN1+RW9oOq6UUndijm96V5 8E1R6P2EZa96FxYq/apGonAfIUogm9igC60YCKWJkxxKdTL9NgtXta/wi8RWTK1qbEqPd4020Tc zbaYGjDBiKtgHfumJdWJFjqL1Q+22YcuixdwjG+j6HYc93zbWsAGSH837YJd3mdiY/uv81w/4kv l3PaoxS4K5e3JTf8OuCTZckHfHQ4Sbq/ySuTc8pvojfi0j015bs3LVVdC4DByKqbmjZV8DIDyR4 7MZer3GHSeg8a8vhcBGCpVZL7pda5yFvCYrl0fy4dN/Bmgj6O+BYSI6/eXdf6CF4yHrsASgJKuE 2j+BWULQ== X-Received: by 2002:a05:6830:3811:b0:7e9:eaf2:ee22 with SMTP id 46e09a7af769-7ee441c4af7mr5475162a34.22.1784908531240; Fri, 24 Jul 2026 08:55:31 -0700 (PDT) Received: from [127.0.1.1] ([2600:8803:e7e4:500:b635:d463:c98:cc75]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7ee2a03eba8sm6160911a34.17.2026.07.24.08.55.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 24 Jul 2026 08:55:30 -0700 (PDT) From: "David Lechner (TI)" Date: Fri, 24 Jul 2026 10:55:06 -0500 Subject: [PATCH v2 1/2] iio: adc: ti-ads112c14: add support for I2C CRC8 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260724-iio-adc-ti-ads112c14-buffered-read-v2-1-98b06f3d47d9@baylibre.com> References: <20260724-iio-adc-ti-ads112c14-buffered-read-v2-0-98b06f3d47d9@baylibre.com> In-Reply-To: <20260724-iio-adc-ti-ads112c14-buffered-read-v2-0-98b06f3d47d9@baylibre.com> To: Jonathan Cameron , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko Cc: Chris Hall , Patrick Edwards , Kurt Borja , Nguyen Minh Tien , linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, "David Lechner (TI)" X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=7707; i=dlechner@baylibre.com; h=from:subject:message-id; bh=dcCEzrZwMSfx3DWIcC8GUj8ZmcNyvugLuhei4vuJGKk=; b=owEBbQGS/pANAwAKAcLMIAH/AY/AAcsmYgBqY4rkVJt4VzKE77SqF2dL5N9xI6w+tQ3kfdTUr tz7ezIuh0SJATMEAAEKAB0WIQTsGNmeYg6D1pzYaJjCzCAB/wGPwAUCamOK5AAKCRDCzCAB/wGP wOvRB/4v8Ixu5X85dDcdk5PfYz9euxJpR9lG2rB0iL+ytfCQFwVZOWFJRo1owdsOUnuBmbGPLYz 2KyUpEFDJ7joQJ3xzfaKmYhgipprHsy9bDgzEXT2tJjuSfRTrmOvQ5gMf/hXD8YE9AWsHAzouTZ 4OoUBW/Ih3sZMnLngF0KZ/4JaTcr5EV6Mvh1vx85lCklk1J/XPh9AwbBUj5fPCp59vCHAOzWKix N63mtKCH5n4GPnpixiwFqwHovhoPBsWnJs3HiFSM9OOGm/pe/qxsxOva1whbj3BC+RRh92Hfil8 SbKxAs5mPiZnZs8fjangv0RGXb33ky9WxfLr3iXl7AL1Zl5v X-Developer-Key: i=dlechner@baylibre.com; a=openpgp; fpr=8A73D82A6A1F509907F373881F8AF88C82F77C03 Add support for I2C CRC8 to the TI ADS112C14 ADC driver. This verifies data integrity of all I2C transactions with the device. For now, it is always enabled, but it could be made optional in the future if needed (e.g. for higher-speed data acquisition). Signed-off-by: David Lechner (TI) --- v2 changes: * Rebased on iio/testing. --- drivers/iio/adc/Kconfig | 1 - drivers/iio/adc/ti-ads112c14.c | 149 +++++++++++++++++++++++++++++++++++++= +--- 2 files changed, 140 insertions(+), 10 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 642c42b1fae7..4ed6f01386bf 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1802,7 +1802,6 @@ config TI_ADS112C14 tristate "Texas Instruments ADS112C14/ADS122C14" depends on I2C select REGMAP - select REGMAP_I2C help If you say yes here you get support for Texas Instruments ADS112C14, ADS122C14 ADC chips. diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c index 3035d45b64b0..80d712049d15 100644 --- a/drivers/iio/adc/ti-ads112c14.c +++ b/drivers/iio/adc/ti-ads112c14.c @@ -10,6 +10,7 @@ =20 #include #include +#include #include #include #include @@ -156,6 +157,9 @@ static const u32 ads112c14_pga_gains_x10[] =3D { 200, 320, 500, 640, 1000, 1280, 2000, 2560, /* 8 - 15 */ }; =20 +#define ADS112C14_I2C_CRC8_POLYNOMIAL 0x07 +DECLARE_CRC8_TABLE(ads112c14_crc8_table); + struct ads112c14_chip_info { const char *name; u8 device_id; @@ -241,6 +245,7 @@ struct ads112c14_data { struct regmap *regmap; /* Synchronizes access to register value fields. */ struct mutex lock; + bool i2c_crc_enabled; u32 avdd_uV; u32 ext_ref_uV; bool refp_is_avdd; @@ -289,6 +294,120 @@ static const struct reg_default ads112c14_reg_default= s[] =3D { { ADS112C14_REG_IDAC_MUX_CFG, FIELD_PREP_CONST(ADS112C14_IDAC_MUX_CFG_I2M= UX, 1) }, }; =20 +/** + * ads112c14_i2c_read_bytes() - Read bytes from the device over I2C + * @client: I2C client for the device + * @cmd: Command to send to the device before reading + * @buf: Buffer to store the read bytes + * @len: Number of bytes to read + * @use_crc: Whether to use CRC8 for data integrity check + * + * If I2C_CRC is enabled, @use_crc may be set to true to perform a CRC8 ch= eck + * on the received data. + */ +static int ads112c14_i2c_read_bytes(struct i2c_client *client, u8 cmd, + u8 *buf, u8 len, bool use_crc) +{ + u8 rx_buf[4]; /* Up to 3 data bytes + 1 CRC byte. */ + u8 rx_len; + int ret; + + rx_len =3D len + (use_crc ? 1 : 0); + + if (rx_len > sizeof(rx_buf)) + return -EINVAL; + + ret =3D i2c_smbus_read_i2c_block_data(client, cmd, rx_len, rx_buf); + if (ret < 0) + return ret; + + if (use_crc) { + u8 crc =3D crc8(ads112c14_crc8_table, rx_buf, len, CRC8_INIT_VALUE); + + if (crc !=3D rx_buf[len]) + return -EBADMSG; + } + + memcpy(buf, rx_buf, len); + + return 0; +} + +/** + * ads112c14_regmap_bus_read() - Read a register from the device + * @context: Pointer to the device context + * @reg_buf: Register address to read + * @reg_size: Size of the register address (should be 1) + * @val_buf: Buffer to store the read value + * @val_size: Size of the value to read + * + * Custom regmap read function that also does CRC check when enabled. + */ +static int ads112c14_regmap_bus_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, + size_t val_size) +{ + struct ads112c14_data *data =3D context; + struct device *dev =3D regmap_get_device(data->regmap); + struct i2c_client *client =3D to_i2c_client(dev); + const u8 *cmd =3D reg_buf; + + if (reg_size !=3D 1) + return -EINVAL; + + return ads112c14_i2c_read_bytes(client, cmd[0], val_buf, val_size, + data->i2c_crc_enabled); +} + +/** + * ads112c14_regmap_bus_write() - Write a register to the device + * @context: Pointer to the device context + * @data_buf: Buffer containing the register address and value to write + * @count: Number of bytes to write + * + * Custom regmap write function that also does readback with CRC check of + * nonvolatile registers when CRC is enabled. + */ +static int ads112c14_regmap_bus_write(void *context, const void *data_buf, + size_t count) +{ + struct ads112c14_data *data =3D context; + struct device *dev =3D regmap_get_device(data->regmap); + struct i2c_client *client =3D to_i2c_client(dev); + const u8 *tx =3D data_buf; + u8 reg, readback; + int ret; + + if (count !=3D 2) + return -EINVAL; + + ret =3D i2c_smbus_write_byte_data(client, tx[0], tx[1]); + if (ret) + return ret; + + reg =3D tx[0] & ~ADS112C14_CMD_WREG; + + if (!data->i2c_crc_enabled || ads112c14_volatile_reg(dev, reg)) + return 0; + + ret =3D ads112c14_i2c_read_bytes(client, reg | ADS112C14_CMD_RREG, + &readback, sizeof(readback), true); + if (ret) + return ret; + + if (readback !=3D tx[1]) + return -EIO; + + return 0; +} + +static const struct regmap_bus ads112c14_regmap_bus =3D { + .read =3D ads112c14_regmap_bus_read, + .write =3D ads112c14_regmap_bus_write, + .reg_format_endian_default =3D REGMAP_ENDIAN_BIG, + .val_format_endian_default =3D REGMAP_ENDIAN_BIG, +}; + static const struct regmap_config ads112c14_regmap_config =3D { .reg_bits =3D 8, .val_bits =3D 8, @@ -486,13 +605,9 @@ static int ads112c14_single_conversion(struct ads112c1= 4_data *data, if (ret) return ret; =20 - ret =3D i2c_smbus_read_i2c_block_data(client, ADS112C14_CMD_RDATA, - BITS_TO_BYTES(data->chip_info->resolution_bits), - buf); - if (ret < 0) - return ret; - - return 0; + return ads112c14_i2c_read_bytes(client, ADS112C14_CMD_RDATA, buf, + BITS_TO_BYTES(data->chip_info->resolution_bits), + data->i2c_crc_enabled); } =20 static int ads112c14_read_raw(struct iio_dev *indio_dev, @@ -1121,7 +1236,8 @@ static int ads112c14_probe(struct i2c_client *client) /* It takes some time for the internal reference to stabilize. */ fsleep(10 * USEC_PER_MSEC); =20 - data->regmap =3D devm_regmap_init_i2c(client, &ads112c14_regmap_config); + data->regmap =3D devm_regmap_init(dev, &ads112c14_regmap_bus, data, + &ads112c14_regmap_config); if (IS_ERR(data->regmap)) return dev_err_probe(dev, PTR_ERR(data->regmap), "failed to init regmap\n"); @@ -1158,6 +1274,14 @@ static int ads112c14_probe(struct i2c_client *client) if (ret) return ret; =20 + ret =3D regmap_update_bits(data->regmap, ADS112C14_REG_DIGITAL_CFG, + ADS112C14_DIGITAL_CFG_I2C_CRC_EN, + ADS112C14_DIGITAL_CFG_I2C_CRC_EN); + if (ret) + return ret; + + data->i2c_crc_enabled =3D true; + ret =3D regmap_read(data->regmap, ADS112C14_REG_DEVICE_ID, ®_val); if (ret) return ret; @@ -1209,6 +1333,13 @@ static const struct i2c_device_id ads112c14_id[] =3D= { }; MODULE_DEVICE_TABLE(i2c, ads112c14_id); =20 +static int ads112c14_i2c_add_driver(struct i2c_driver *driver) +{ + crc8_populate_msb(ads112c14_crc8_table, ADS112C14_I2C_CRC8_POLYNOMIAL); + + return i2c_add_driver(driver); +} + static struct i2c_driver ads112c14_driver =3D { .driver =3D { .name =3D "ads112c14", @@ -1217,7 +1348,7 @@ static struct i2c_driver ads112c14_driver =3D { .probe =3D ads112c14_probe, .id_table =3D ads112c14_id, }; -module_i2c_driver(ads112c14_driver); +module_driver(ads112c14_driver, ads112c14_i2c_add_driver, i2c_del_driver); =20 MODULE_AUTHOR("David Lechner (TI) "); MODULE_DESCRIPTION("TI ADS112C14 I2C ADC driver"); --=20 2.43.0 From nobody Fri Jul 24 21:30:26 2026 Received: from mail-ot1-f49.google.com (mail-ot1-f49.google.com [209.85.210.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4843C435ED7 for ; Fri, 24 Jul 2026 15:55:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784908535; cv=none; b=d4rTmZqK9GjEhmXud6H7pOtl9RNsk+l414TozIbivXY0d2tGkBALfAJfeaXnEjnlw3VsllKpJTeav7Is1ONQJzCIWJ6tbPSBuaVuBTMdjj9c7FdywiUujlecimAHFQnaC4gnqbPZ4HC0l5Sqpfe65JA/zl00PZf4uiDdl+EBaFY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784908535; c=relaxed/simple; bh=ZaWOvelJv5bYIAvvNRBNpGwUfXwkW2TNg4nkmRV6Zts=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fej4Quv6DjHUOgXs/DvxGoWQWwh4vZl91fddssshu2RZmCbLYyFaPPVtfsvHaCYoS+9OnDWuq1sM1Tk4olrE9UG4wpC4BwbX/n952xn54BVt1M5BFHX/hoGbjm1e7f64W87E0UdEOr3X+S4BhflrggyrL+prn/c+K5g2BfPQfww= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b=SQUjovIg; arc=none smtp.client-ip=209.85.210.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b="SQUjovIg" Received: by mail-ot1-f49.google.com with SMTP id 46e09a7af769-7eb5bdb50fcso290692a34.1 for ; Fri, 24 Jul 2026 08:55:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre.com; s=google; t=1784908532; x=1785513332; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=qSEN+009lnU4b5a7hshNtk0fuwqcDxCxvgsAK1D6mJo=; b=SQUjovIggJwdxmUtYu/Hz0I8pX/MqwY+vYPHqIJGBRAruLd/4z8/VWAU9zEsnR9Zh7 jxCZ52L1tjDCYgZxjChlwLfh2g8ML5GnJb97pq/Oc2oH8SYSFRDj6qou3uJnNVGM3ao7 YkcyHWOmN1wGzvU80BCWMRz5Cb1DOYmPbFOnO40TGPJzm41naeQq8KoggnanSLjF0QLs Ij7FjetrAuTLayWAfwSYliyg5ISalzqHkdRb72TRVI8BTmzRr4XW/+sc3LREzx0XSktW Q69NQLVZHlalXxidn/X9mARA94YmRxSb34GJeVX284+EfkoJZUmaMkSGs+JJyXmKMHHI gBUw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784908532; x=1785513332; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=qSEN+009lnU4b5a7hshNtk0fuwqcDxCxvgsAK1D6mJo=; b=dIFDPBc7zPF+5u3qbtIM+gw5LVpI3/k5o5bCcyOgdXXY+P3mjG389zvx4tGySJYQVz 8gIAEbr+Eo/aM0mPQoC0iD/uQclwo7ps9tZk59QndxG9YLZU438vmLGP1GHl2Ov6lP7r AIVteByyfrDEW+INI6AZTQA1f/UWgXn308nl6xPu3fHrrtak4yoatsOE4KvGn16vvGIz A6h2d3nQf/ejVPOpP5xbsSOHm5ELZSohMODfqkTOJbucZJ4FTK6QMDAgLAS6A4VqHJiJ crL0GTlMCWAZA7AEv+aZbcH60i7MTv2o9vMGv5sXM48E5bYXO/QW8jPFqDh5pIERpYrR rIbQ== X-Forwarded-Encrypted: i=1; AHgh+RoXGjlKb/MFHmO3tdQLDkeUlKwVgPVOkANhV+uAtUOJVU8JQF4CBsBcQdiZjSMcXx8MkLY5DMW4JeThb74=@vger.kernel.org X-Gm-Message-State: AOJu0YwISd78DI28ky2QyF0UA959xocZOIwg0C/1Wssz8e+KFqgruAzT 3jY3H6nS5HM6oI+1VssVorSsvY6KXcCEIyoBAgIzhShqU7PI5Fk25HeWWrmh0YTLjS0= X-Gm-Gg: AR+sD12g4o/w44vfU/gHhu04OokVcjoWwQPC5naYKsFqCrnzVvF/UfK7mVlmBiJpNjp xrtYcZWZ+Q8ft4xfcTpZYv3Gx/Q6ERZ3yMCVPDR5lgfLKFq5pV4Fg/6ls9ojhMYsvdUUfMv6zcg jkApEjbPJbS03RfNJbaEUZK3UKgzN1pHwuxWw9KkawWF+52Pwa+5oIiPGr/nK2lXNcYnjcaeDbq DTe/CXD+4uoiJMjAdnxqsxkjlAjVhgjbuaaW7TBfRBr5zIrsrdp9ZcyGW4MXReszJz8jqpsWP+g 437gHmyCqysd3NHdestJ8RfQqjQw+Q7vU9IW5qs6NTVkuhF1A1TwzBl70hmKPV983m6te7cb8Ht Y9vky8se+rLaTHSmNcYyVVSEnRB1n+Y0SGH+CgQhCCHeduTXgAffURzP7kYrluaKo0nnfm4zfic PLx0IWJg== X-Received: by 2002:a05:6830:83b8:b0:7ec:6749:f38f with SMTP id 46e09a7af769-7ee43e1a6f0mr5421714a34.22.1784908532150; Fri, 24 Jul 2026 08:55:32 -0700 (PDT) Received: from [127.0.1.1] ([2600:8803:e7e4:500:b635:d463:c98:cc75]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7ee2a03eba8sm6160911a34.17.2026.07.24.08.55.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 24 Jul 2026 08:55:31 -0700 (PDT) From: "David Lechner (TI)" Date: Fri, 24 Jul 2026 10:55:07 -0500 Subject: [PATCH v2 2/2] iio: adc: ti-ads112c14: add support for buffered read Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260724-iio-adc-ti-ads112c14-buffered-read-v2-2-98b06f3d47d9@baylibre.com> References: <20260724-iio-adc-ti-ads112c14-buffered-read-v2-0-98b06f3d47d9@baylibre.com> In-Reply-To: <20260724-iio-adc-ti-ads112c14-buffered-read-v2-0-98b06f3d47d9@baylibre.com> To: Jonathan Cameron , =?utf-8?q?Nuno_S=C3=A1?= , Andy Shevchenko Cc: Chris Hall , Patrick Edwards , Kurt Borja , Nguyen Minh Tien , linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, "David Lechner (TI)" X-Mailer: b4 0.16-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=7619; i=dlechner@baylibre.com; h=from:subject:message-id; bh=ZaWOvelJv5bYIAvvNRBNpGwUfXwkW2TNg4nkmRV6Zts=; b=owEBbQGS/pANAwAKAcLMIAH/AY/AAcsmYgBqY4rrIcPOilJ37loqyM6K7h9FH+UzfYFA5d3lK KGq2roh33iJATMEAAEKAB0WIQTsGNmeYg6D1pzYaJjCzCAB/wGPwAUCamOK6wAKCRDCzCAB/wGP wB7TB/9sK9+m7wlX7cZe6LJTvssePDqKx4AUmBjtVgCnWBuORlY4F+b9VVX445a6WgAIajcUb3l fjqThSUmxllJvYne5zjEE2xvoz2p/cHGh3TZiMUsPoPH1i6uc0+quHe9kC8AdJWLPVt2ARkbt/j 7dvDq1tiaVXv6TcI7oKOhUjuEwDzLNPV9uhugi5B/wvW3fSThXLCHISnbLdugyQg07hfHIaRyr9 KVw8ttCjOi5SKDz+C9blEEqZ60srhaQPnaI/RU8Cg2S8GptE0mKuCt5w5mM3Tn1IxI/7Yzzb5nM 2RZKp3EwCnM3Qei8BdainDKMCXpBL4VuWjtppywCfeIqI2Y7 X-Developer-Key: i=dlechner@baylibre.com; a=openpgp; fpr=8A73D82A6A1F509907F373881F8AF88C82F77C03 Add support for buffered reads using a triggered buffer. The device has a continuous conversion mode, but that can only be used with one channel at a time since there is nothing like a sequencer to support that in hardware. Instead, we use single-shot reads like we do for direct reads to be able to read multiple channels. Since CRC is always enabled, buffered reads include the CRC byte along with the raw data without verifying it. This allows userspace to perform it's own CRC verification per-sample and drop bad samples rather than failing the entire buffered read for one bad sample. Support for continuous conversion mode could be added in the future if needed. Signed-off-by: David Lechner (TI) --- v2 changes: * Rebased on iio/testing. * Don't say how to implement continuous conversion mode in the commit message. * Explain CRC usage in buffered reads in the commit message. * Added comment on updating the template for system monitor channels with dynamic values. * Refactored total channel count to always use i++. --- drivers/iio/adc/ti-ads112c14.c | 108 +++++++++++++++++++++++++++++++++++++= ++-- 1 file changed, 104 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c index 80d712049d15..8ad8caee0ff7 100644 --- a/drivers/iio/adc/ti-ads112c14.c +++ b/drivers/iio/adc/ti-ads112c14.c @@ -15,7 +15,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -29,6 +32,9 @@ #include #include =20 +/* Arbitrary limit since channels are dynamic. */ +#define ADS112C14_MAX_MEASUREMENT_CHANNELS 16 + /* Datasheet t_d(RST) - time to wait after reset before next I2C use. */ #define ADS112C14_DELAY_RESET_US 500 =20 @@ -255,6 +261,8 @@ struct ads112c14_data { u32 num_measurements; u8 sys_mon_chan_short_gain_val; int sys_mon_chan_short_scale_available[ARRAY_SIZE(ads112c14_pga_gains_x10= )][2]; + IIO_DECLARE_BUFFER_WITH_TS(__be32, scan, ADS112C14_MAX_MEASUREMENT_CHANNE= LS + + ARRAY_SIZE(ads112c14_sys_mon_channels)); }; =20 static bool ads112c14_writeable_reg(struct device *dev, unsigned int reg) @@ -575,7 +583,7 @@ static int ads112c14_prepare_sys_mon_channel(struct ads= 112c14_data *data, =20 static int ads112c14_single_conversion(struct ads112c14_data *data, const struct iio_chan_spec *chan, - u8 *buf) + u8 *buf, bool for_scan) { struct i2c_client *client =3D to_i2c_client(regmap_get_device(data->regma= p)); u32 reg_val; @@ -605,6 +613,24 @@ static int ads112c14_single_conversion(struct ads112c1= 4_data *data, if (ret) return ret; =20 + /* + * When doing buffered read, we don't check the CRC, but rather pass it + * along with the raw data. This way, we don't silently drop samples + * with CRC errors, but rather leave it to userspace to decide what to + * do. + */ + if (for_scan) { + u8 len =3D BITS_TO_BYTES(data->chip_info->resolution_bits) + + (data->i2c_crc_enabled ? 1 : 0); + + ret =3D i2c_smbus_read_i2c_block_data(client, ADS112C14_CMD_RDATA, + len, buf); + if (ret < 0) + return ret; + + return 0; + } + return ads112c14_i2c_read_bytes(client, ADS112C14_CMD_RDATA, buf, BITS_TO_BYTES(data->chip_info->resolution_bits), data->i2c_crc_enabled); @@ -639,7 +665,7 @@ static int ads112c14_read_raw(struct iio_dev *indio_dev, if (IIO_DEV_ACQUIRE_FAILED(claim)) return -EBUSY; =20 - ret =3D ads112c14_single_conversion(data, chan, buf); + ret =3D ads112c14_single_conversion(data, chan, buf, false); if (ret) return ret; =20 @@ -765,6 +791,10 @@ static int ads112c14_write_raw(struct iio_dev *indio_d= ev, const int (*scale_avail)[2]; u8 *gain_val; =20 + IIO_DEV_ACQUIRE_DIRECT_MODE(indio_dev, claim); + if (IIO_DEV_ACQUIRE_FAILED(claim)) + return -EBUSY; + switch (mask) { case IIO_CHAN_INFO_SCALE: { guard(mutex)(&data->lock); @@ -863,6 +893,37 @@ static int ads112c14_read_label(struct iio_dev *indio_= dev, return sysfs_emit(label, "%s\n", label_source); } =20 +static irqreturn_t ads112c14_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf =3D private; + struct iio_dev *indio_dev =3D pf->indio_dev; + struct ads112c14_data *data =3D iio_priv(indio_dev); + u32 offset =3D 0; + u32 i; + int ret; + + iio_for_each_active_channel(indio_dev, i) { + const struct iio_chan_spec *chan =3D &indio_dev->channels[i]; + + ret =3D ads112c14_single_conversion(data, chan, + (u8 *)&data->scan[offset++], + true); + if (ret) { + dev_err_once(indio_dev->dev.parent, + "failed to read channel %d: %pe; additional errors will be suppre= ssed\n", + chan->channel, ERR_PTR(ret)); + goto out; + } + } + + iio_push_to_buffers_with_ts(indio_dev, data->scan, + sizeof(data->scan), pf->timestamp); +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + static const struct iio_info ads112c14_info =3D { .read_raw =3D ads112c14_read_raw, .read_avail =3D ads112c14_read_avail, @@ -908,7 +969,7 @@ static int ads112c14_parse_channels(struct iio_dev *ind= io_dev, return -ENOMEM; =20 channels =3D devm_kcalloc(dev, num_child_nodes + - ARRAY_SIZE(ads112c14_sys_mon_channels), + ARRAY_SIZE(ads112c14_sys_mon_channels) + 1, sizeof(*channels), GFP_KERNEL); if (!channels) return -ENOMEM; @@ -1069,14 +1130,47 @@ static int ads112c14_parse_channels(struct iio_dev = *indio_dev, if (spec->type =3D=3D IIO_RESISTANCE) spec->differential =3D 0; =20 + spec->scan_type =3D (struct iio_scan_type){ + .format =3D measurement->bipolar ? + IIO_SCAN_FORMAT_SIGNED_INT : + IIO_SCAN_FORMAT_UNSIGNED_INT, + .realbits =3D data->chip_info->resolution_bits, + .storagebits =3D 32, + .shift =3D 32 - data->chip_info->resolution_bits, + .endianness =3D IIO_BE, + }; + i++; } =20 data->num_measurements =3D i; + if (data->num_measurements >=3D ADS112C14_MAX_MEASUREMENT_CHANNELS) + return dev_err_probe(dev, -EINVAL, + "too many measurement channels defined\n"); + memcpy(channels + i, ads112c14_sys_mon_channels, sizeof(ads112c14_sys_mon= _channels)); =20 + for (u32 j =3D 0; j < ARRAY_SIZE(ads112c14_sys_mon_channels); j++) { + struct iio_chan_spec *spec =3D &channels[i]; + + /* Update the template that was already copied with dynamic values. */ + spec->scan_index =3D i; + spec->scan_type =3D (struct iio_scan_type){ + .format =3D IIO_SCAN_FORMAT_SIGNED_INT, + .realbits =3D data->chip_info->resolution_bits, + .storagebits =3D 32, + .shift =3D 32 - data->chip_info->resolution_bits, + .endianness =3D IIO_BE, + }; + + i++; + } + + channels[i] =3D IIO_CHAN_SOFT_TIMESTAMP(i); + i++; + indio_dev->channels =3D channels; - indio_dev->num_channels =3D i + ARRAY_SIZE(ads112c14_sys_mon_channels); + indio_dev->num_channels =3D i; =20 return 0; } @@ -1304,6 +1398,12 @@ static int ads112c14_probe(struct i2c_client *client) indio_dev->modes =3D INDIO_DIRECT_MODE; indio_dev->info =3D &ads112c14_info; =20 + ret =3D devm_iio_triggered_buffer_setup(dev, indio_dev, + iio_pollfunc_store_time, + ads112c14_trigger_handler, NULL); + if (ret) + return ret; + return devm_iio_device_register(dev, indio_dev); } =20 --=20 2.43.0