From: Piyush Patle <piyushpatle228@gmail.com>
To: Jonathan Cameron <jic23@kernel.org>, Andreas Klinger <ak@it-klinger.de>
Cc: "David Lechner" <dlechner@baylibre.com>,
"Nuno Sá" <nuno.sa@analog.com>,
"Andy Shevchenko" <andy@kernel.org>,
"Andy Shevchenko" <andriy.shevchenko@intel.com>,
"Rob Herring" <robh@kernel.org>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH v3 3/3] iio: adc: hx711: add support for HX710B
Date: Wed, 22 Apr 2026 23:29:10 +0530 [thread overview]
Message-ID: <20260422175910.1258579-4-piyushpatle228@gmail.com> (raw)
In-Reply-To: <20260422175910.1258579-1-piyushpatle228@gmail.com>
Add support for the AVIA HX710B ADC, which shares the HX711 GPIO
interface but has a fixed gain of 128 and uses trailing PD_SCK pulses
to select between the differential input and the DVDD-AVDD supply
monitor.
Model the HX710B with its own channel specification and iio_info.
Store the HX710B trailing pulse counts in chan->address and add
fixed-gain handling so the HX711 selectable-gain path remains
separate from the HX710B fixed-gain path.
The HX710B datasheet documents a single fixed PGA gain of 128 and
does not provide configurable gain selection like the HX711.
Order hx711_chip_info as pointers first, then unsigned int fields, then
bool. pahole then reports no internal holes in the structure; the
remaining padding is tail padding from 8-byte alignment.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
---
Changes in v3:
- Add HX710B support on top of the separate hx711_chip_info refactor.
- Update channel_set only after hx711_read() and hx711_wait_for_ready()
both succeed.
- Keep a single HX710B fixed-gain scale based on the datasheet's fixed
PGA gain of 128; do not apply the HX711 channel-B gain of 32 to the
HX710B supply monitor path.
- Use unsigned int for channel state and fixed-gain scale storage.
- Keep HX710B trailing pulse counts in chan->address.
- Describe HX710B channel 0 as a differential IIO channel.
- Reorder hx711_chip_info fields based on pahole output so the
structure has no internal holes.
Changes in v2:
- Fix pulse count bug: HX710B values were {25, 26} total SCK cycles;
corrected to {1, 2} trailing pulses because hx711_read() already
clocks the 24 data bits.
- Add .differential = 1 and .channel2 = 1 to HX710B channel 0.
- Move trailing pulse counts from a separate array to chan->address.
- Replace chan_pulse_count tests with a dedicated fixed_gain flag.
- Add fixed_gain_val to hx711_chip_info.
- Add the iio_info pointer to hx711_chip_info and assign
indio_dev->info from chip_info.
- Remove the NULL check after device_get_match_data().
- Remove reset_channel from hx711_chip_info.
- Change hx711_reset_read() and hx710b_set_channel() to take
const struct iio_chan_spec *.
- Revert unrelated hx711_data struct member alignment noise.
- Sort of_device_id entries alphabetically.
- Expand the commit message to explain HX711 versus HX710B trailing
pulse behaviour.
- Restore the file header to mention weight sensor modules.
drivers/iio/adc/Kconfig | 1 +
drivers/iio/adc/hx711.c | 134 +++++++++++++++++++++++++++++++++++-----
2 files changed, 120 insertions(+), 15 deletions(-)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index f18692aea795..09a1b29fbd9c 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -790,6 +790,7 @@ config HX711
select IIO_TRIGGERED_BUFFER
help
If you say Y here you get support for the following AVIA ADCs:
+ - HX710B
- HX711
which are used for bridge sensors such as weigh cells.
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index a444a2872257..d7050bec53b4 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -82,14 +82,18 @@ static int hx711_get_scale_to_gain(int scale)
* struct hx711_chip_info - per-variant static configuration
* @name: IIO device name
* @channels: channel specification
- * @num_channels: number of channels
* @iio_info: IIO info ops for this variant
+ * @num_channels: number of channels
+ * @fixed_gain: true if the variant has a fixed ADC gain (e.g. HX710B)
+ * @fixed_gain_val: the fixed gain value used to compute scale (when fixed_gain)
*/
struct hx711_chip_info {
const char *name;
const struct iio_chan_spec *channels;
- unsigned int num_channels;
const struct iio_info *iio_info;
+ unsigned int num_channels;
+ unsigned int fixed_gain_val;
+ bool fixed_gain;
};
struct hx711_data {
@@ -98,6 +102,8 @@ struct hx711_data {
struct gpio_desc *gpiod_dout;
int gain_set; /* gain set on device */
int gain_chan_a; /* gain for channel A */
+ unsigned int channel_set; /* HX710B current channel */
+ unsigned int scale; /* HX710B fixed scale */
const struct hx711_chip_info *chip_info;
struct mutex lock;
/*
@@ -206,6 +212,7 @@ static int hx711_wait_for_ready(struct hx711_data *hx711_data)
static int hx711_reset(struct hx711_data *hx711_data)
{
+ const struct hx711_chip_info *info = hx711_data->chip_info;
int val = hx711_wait_for_ready(hx711_data);
if (val) {
@@ -224,8 +231,11 @@ static int hx711_reset(struct hx711_data *hx711_data)
val = hx711_wait_for_ready(hx711_data);
- /* after a reset the gain is 128 */
- hx711_data->gain_set = HX711_RESET_GAIN;
+ /* Restore variant default after reset. */
+ if (info->fixed_gain)
+ hx711_data->channel_set = 0;
+ else
+ hx711_data->gain_set = HX711_RESET_GAIN;
}
return val;
@@ -267,9 +277,32 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
return 0;
}
+/* Select HX710B channel for the next conversion. */
+static int hx710b_set_channel(struct hx711_data *hx711_data,
+ const struct iio_chan_spec *chan)
+{
+ int ret;
+
+ if (hx711_data->channel_set == (unsigned int)chan->channel)
+ return 0;
+
+ ret = hx711_read(hx711_data, chan->address);
+ if (ret < 0)
+ return ret;
+
+ ret = hx711_wait_for_ready(hx711_data);
+ if (ret)
+ return ret;
+
+ hx711_data->channel_set = chan->channel;
+
+ return 0;
+}
+
static int hx711_reset_read(struct hx711_data *hx711_data,
const struct iio_chan_spec *chan)
{
+ const struct hx711_chip_info *info = hx711_data->chip_info;
unsigned int trailing_pulses;
int ret;
@@ -279,11 +312,18 @@ static int hx711_reset_read(struct hx711_data *hx711_data,
return -EIO;
}
- ret = hx711_set_gain_for_channel(hx711_data, chan->channel);
- if (ret < 0)
- return ret;
+ if (info->fixed_gain) {
+ ret = hx710b_set_channel(hx711_data, chan);
+ if (ret < 0)
+ return ret;
+ trailing_pulses = chan->address;
+ } else {
+ ret = hx711_set_gain_for_channel(hx711_data, chan->channel);
+ if (ret < 0)
+ return ret;
+ trailing_pulses = hx711_get_gain_to_pulse(hx711_data->gain_set);
+ }
- trailing_pulses = hx711_get_gain_to_pulse(hx711_data->gain_set);
return hx711_read(hx711_data, trailing_pulses);
}
@@ -292,6 +332,7 @@ static int hx711_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct hx711_data *hx711_data = iio_priv(indio_dev);
+ const struct hx711_chip_info *info = hx711_data->chip_info;
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -308,7 +349,10 @@ static int hx711_read_raw(struct iio_dev *indio_dev,
*val = 0;
mutex_lock(&hx711_data->lock);
- *val2 = hx711_get_gain_to_scale(hx711_data->gain_set);
+ if (info->fixed_gain)
+ *val2 = hx711_data->scale;
+ else
+ *val2 = hx711_get_gain_to_scale(hx711_data->gain_set);
mutex_unlock(&hx711_data->lock);
@@ -442,6 +486,10 @@ static const struct iio_info hx711_iio_info = {
.attrs = &hx711_attribute_group,
};
+static const struct iio_info hx710b_iio_info = {
+ .read_raw = hx711_read_raw,
+};
+
static const struct iio_chan_spec hx711_chan_spec[] = {
{
.type = IIO_VOLTAGE,
@@ -474,6 +522,48 @@ static const struct iio_chan_spec hx711_chan_spec[] = {
IIO_CHAN_SOFT_TIMESTAMP(2),
};
+/*
+ * HX710B channels.
+ * Channel 0: differential input (IN+ vs IN-), 10 SPS, 1 trailing pulse.
+ * Channel 1: DVDD-AVDD supply monitor, 40 SPS, 2 trailing pulses.
+ * .address holds the trailing pulse count used by hx710b_set_channel().
+ */
+static const struct iio_chan_spec hx710b_chan_spec[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .differential = 1,
+ .channel = 0,
+ .channel2 = 1,
+ .indexed = 1,
+ .address = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 24,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .channel = 1,
+ .indexed = 1,
+ .address = 2,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 24,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
static const struct hx711_chip_info hx711_chip = {
.name = "hx711",
.channels = hx711_chan_spec,
@@ -481,6 +571,15 @@ static const struct hx711_chip_info hx711_chip = {
.iio_info = &hx711_iio_info,
};
+static const struct hx711_chip_info hx710b_chip = {
+ .name = "hx710b",
+ .channels = hx710b_chan_spec,
+ .num_channels = ARRAY_SIZE(hx710b_chan_spec),
+ .iio_info = &hx710b_iio_info,
+ .fixed_gain = true,
+ .fixed_gain_val = 128,
+};
+
static int hx711_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -540,12 +639,16 @@ static int hx711_probe(struct platform_device *pdev)
/* we need 10^-9 mV */
ret *= 100;
- for (i = 0; i < HX711_GAIN_MAX; i++)
- hx711_gain_to_scale[i].scale =
- ret / hx711_gain_to_scale[i].gain / 1678;
+ if (chip_info->fixed_gain) {
+ hx711_data->scale = ret / chip_info->fixed_gain_val / 1678;
+ } else {
+ for (i = 0; i < HX711_GAIN_MAX; i++)
+ hx711_gain_to_scale[i].scale =
+ ret / hx711_gain_to_scale[i].gain / 1678;
- hx711_data->gain_set = 128;
- hx711_data->gain_chan_a = 128;
+ hx711_data->gain_set = 128;
+ hx711_data->gain_chan_a = 128;
+ }
indio_dev->info = chip_info->iio_info;
@@ -585,7 +688,8 @@ static int hx711_probe(struct platform_device *pdev)
}
static const struct of_device_id of_hx711_match[] = {
- { .compatible = "avia,hx711", .data = &hx711_chip },
+ { .compatible = "avia,hx710b", .data = &hx710b_chip },
+ { .compatible = "avia,hx711", .data = &hx711_chip },
{ }
};
--
2.43.0
next prev parent reply other threads:[~2026-04-22 17:59 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-22 17:59 [PATCH v3 0/3] iio: adc: hx711: add HX710B support Piyush Patle
2026-04-22 17:59 ` [PATCH v3 1/3] dt-bindings: iio: adc: avia-hx711: add avia,hx710b compatible Piyush Patle
2026-04-23 8:05 ` Krzysztof Kozlowski
2026-04-24 12:00 ` Jonathan Cameron
2026-04-26 16:28 ` David Lechner
2026-04-26 16:43 ` Piyush Patle
2026-04-22 17:59 ` [PATCH v3 2/3] iio: adc: hx711: refactor to per-chip hx711_chip_info structure Piyush Patle
2026-04-22 20:16 ` Andy Shevchenko
2026-04-24 11:53 ` Jonathan Cameron
2026-04-24 12:14 ` Jonathan Cameron
2026-04-22 17:59 ` Piyush Patle [this message]
2026-04-22 20:20 ` [PATCH v3 3/3] iio: adc: hx711: add support for HX710B Andy Shevchenko
2026-04-24 12:19 ` Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260422175910.1258579-4-piyushpatle228@gmail.com \
--to=piyushpatle228@gmail.com \
--cc=ak@it-klinger.de \
--cc=andriy.shevchenko@intel.com \
--cc=andy@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dlechner@baylibre.com \
--cc=jic23@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=nuno.sa@analog.com \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox