* [PATCH v2 0/2] iio: adc: hx711: add HX710B support
@ 2026-04-19 17:46 Piyush Patle
2026-04-19 17:46 ` [PATCH v2 1/2] dt-bindings: iio: adc: avia-hx711: add avia,hx710b compatible Piyush Patle
2026-04-19 17:46 ` [PATCH v2 2/2] iio: adc: hx711: add support for HX710B Piyush Patle
0 siblings, 2 replies; 5+ messages in thread
From: Piyush Patle @ 2026-04-19 17:46 UTC (permalink / raw)
To: jic23, ak
Cc: dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt, linux-iio,
devicetree, linux-kernel
Add support for the HX710B ADC, a variant of the HX711 with the same
GPIO interface but a different channel and gain model.
The first patch updates the devicetree binding to add the
`avia,hx710b` compatible, document the variant-specific behavior, and
add chip-specific properties for supplies, the RATE pin, and an allOf
constraint for HX710B nodes.
The second patch refactors the driver with per-chip configuration,
pulse counts stored in chan->address, a dedicated fixed_gain flag, and
the differential channel descriptor for the HX710B input.
Tested on PocketBeagle2 with an HX710B breakout module. The device
probed successfully and raw readings were stable.
Changes in v2:
- See individual patch changelogs for full details.
- dt-bindings: add dvdd-supply, vsup-supply, rate-gpios; allOf if/then
for HX710B; fix clock-frequency description; remove dead vendor URL;
clarify vref not needed (AVDD serves as reference on both chips)
- driver: fix pulse count bug ({25,26}→{1,2}); move counts to
chan->address; add fixed_gain flag; add .differential/.channel2;
remove NULL check; drop reset_channel; pass iio_chan_spec * directly
Piyush Patle (2):
dt-bindings: iio: adc: avia-hx711: add avia,hx710b compatible
iio: adc: hx711: add support for HX710B
.../bindings/iio/adc/avia-hx711.yaml | 61 +++++-
drivers/iio/adc/Kconfig | 9 +-
drivers/iio/adc/hx711.c | 206 ++++++++++++++----
3 files changed, 225 insertions(+), 51 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] dt-bindings: iio: adc: avia-hx711: add avia,hx710b compatible
2026-04-19 17:46 [PATCH v2 0/2] iio: adc: hx711: add HX710B support Piyush Patle
@ 2026-04-19 17:46 ` Piyush Patle
2026-04-21 8:23 ` Krzysztof Kozlowski
2026-04-19 17:46 ` [PATCH v2 2/2] iio: adc: hx711: add support for HX710B Piyush Patle
1 sibling, 1 reply; 5+ messages in thread
From: Piyush Patle @ 2026-04-19 17:46 UTC (permalink / raw)
To: jic23, ak
Cc: dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt, linux-iio,
devicetree, linux-kernel
The HX710B shares the same two-wire interface as the HX711 but differs
in its channel and gain model: gain is fixed at 128 and the number of
trailing PD_SCK pulses selects the input channel rather than the gain.
Add avia,hx710b to the compatible enum. Document the chip differences
in the description and add chip-specific supply properties (dvdd-supply,
vsup-supply) for the HX711, a rate-gpios property for the HX711 RATE
pin, and an allOf constraint that forbids HX711-only properties on
HX710B nodes. Clarify the clock-frequency description to reflect its
actual purpose: controlling the SCK bit-bang timing. Note that AVDD
serves as the voltage reference on both chips so no separate
vref-supply is needed.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
---
Changes in v2:
- Remove driver implementation details (bit-banging, channel-selection
mechanics) from the description; describe hardware behaviour only
- Drop unrelated punctuation cleanup (trailing period on PD_SCK description)
- Add dvdd-supply and vsup-supply optional properties for HX711
- Add rate-gpios optional property for the HX711 RATE pin; forbid it on
HX710B via the allOf if/then block
- Add note to avdd-supply clarifying it serves as voltage reference on
both chips (no separate vref-supply needed)
- Add allOf if/then block forbidding HX711-only properties on HX710B
- Fix clock-frequency description to reflect its true purpose (SCK
bit-bang timing control, not a crystal/external clock frequency)
- Sort compatible enum alphabetically (hx710b before hx711)
- Remove redundant example comments (compatible already identifies part)
- Update HX711 example to exercise the new rate-gpios property
.../bindings/iio/adc/avia-hx711.yaml | 61 ++++++++++++++++---
1 file changed, 51 insertions(+), 10 deletions(-)
diff --git a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
index 9c57eb13f892..35ac74a490b1 100644
--- a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
@@ -4,24 +4,24 @@
$id: http://devicetree.org/schemas/iio/adc/avia-hx711.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: AVIA HX711 ADC chip for weight cells
+title: AVIA HX711 and HX710B ADCs
maintainers:
- Andreas Klinger <ak@it-klinger.de>
description: |
- Bit-banging driver using two GPIOs:
- - sck-gpio gives a clock to the sensor with 24 cycles for data retrieval
- and up to 3 cycles for selection of the input channel and gain for the
- next measurement
- - dout-gpio is the sensor data the sensor responds to the clock
+ The HX711 is a 24-bit ADC with selectable gain (32/64/128) and two
+ differential input channels. Channel A supports gain 64 and 128;
+ channel B supports gain 32.
- Specifications about the driver can be found at:
- http://www.aviaic.com/ENProducts.aspx
+ The HX710B is a 24-bit ADC with fixed gain of 128. Channel 0 is the
+ differential input and channel 1 measures the DVDD-AVDD supply
+ voltage difference.
properties:
compatible:
enum:
+ - avia,hx710b
- avia,hx711
sck-gpios:
@@ -40,13 +40,45 @@ properties:
avdd-supply:
description:
- Definition of the regulator used as analog supply
+ Analog supply voltage (AVDD). Also serves as the voltage reference on
+ both chips; no separate vref-supply is required.
+
+ dvdd-supply:
+ description:
+ Digital supply voltage (DVDD). HX711 only.
+
+ vsup-supply:
+ description:
+ Supply voltage for the on-chip regulator (VSUP). HX711 only.
+
+ rate-gpios:
+ description:
+ GPIO connected to the RATE pin (HX711 only). When driven low the
+ output data rate is 10 SPS; when driven high it is 80 SPS. If
+ omitted the RATE pin state is determined by the board wiring.
+ maxItems: 1
clock-frequency:
+ description:
+ Controls the SCK bit-bang timing. The value is used to derive the
+ delay between SCK edges; keep the SCK high time below 60 us to
+ avoid triggering chip power-down mode. Defaults to 400 kHz if not
+ specified.
minimum: 20000
maximum: 2500000
default: 400000
+allOf:
+ - if:
+ properties:
+ compatible:
+ const: avia,hx710b
+ then:
+ properties:
+ vsup-supply: false
+ dvdd-supply: false
+ rate-gpios: false
+
required:
- compatible
- sck-gpios
@@ -58,10 +90,19 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
- weight {
+ weight0 {
compatible = "avia,hx711";
sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
+ rate-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
avdd-supply = <&avdd>;
clock-frequency = <100000>;
};
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ weight1 {
+ compatible = "avia,hx710b";
+ sck-gpios = <&gpio3 11 GPIO_ACTIVE_HIGH>;
+ dout-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
+ avdd-supply = <&avdd>;
+ };
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] iio: adc: hx711: add support for HX710B
2026-04-19 17:46 [PATCH v2 0/2] iio: adc: hx711: add HX710B support Piyush Patle
2026-04-19 17:46 ` [PATCH v2 1/2] dt-bindings: iio: adc: avia-hx711: add avia,hx710b compatible Piyush Patle
@ 2026-04-19 17:46 ` Piyush Patle
2026-04-20 9:03 ` Andy Shevchenko
1 sibling, 1 reply; 5+ messages in thread
From: Piyush Patle @ 2026-04-19 17:46 UTC (permalink / raw)
To: jic23, ak
Cc: dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt, linux-iio,
devicetree, linux-kernel
The HX711 uses trailing SCK pulses after each 24-bit conversion to
select the channel and gain for the next measurement: 1 pulse gives
channel A at gain 128, 2 pulses give channel B at gain 32, and 3 pulses
give channel A at gain 64.
The HX710B works differently: gain is fixed at 128 and the trailing
pulses select only the channel. One trailing pulse selects the
differential input (channel 0, 10 SPS) and two trailing pulses select
the DVDD-AVDD supply monitor (channel 1, 40 SPS).
Refactor the driver around a per-chip hx711_chip_info structure so both
variants can share the same core. Each chip provides its own
iio_chan_spec array and iio_info pointer. The HX710B stores per-channel
trailing pulse counts in chan->address (1 for channel 0, 2 for
channel 1) instead of a separate array. A bool fixed_gain flag and
fixed_gain_val field in hx711_chip_info distinguish the fixed-gain path
from the HX711's user-selectable gain path without conflating unrelated
properties. The HX710B differential input channel is described with
.differential=1 and .channel2=1 as required by the IIO ABI.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
---
Changes in v2:
- Fix pulse count bug: hx710b values were {25, 26} (total SCK cycles);
corrected to {1, 2} (trailing-only, hx711_read() clocks 24 data bits)
- Add .differential = 1 and .channel2 = 1 to HX710B channel 0
- Move trailing pulse counts from a separate array to chan->address
(1 for ch0, 2 for ch1); remove chan_pulse_count / num_chan_pulses
- Replace chan_pulse_count != NULL tests with dedicated bool fixed_gain
flag; add fixed_gain_val field to hx711_chip_info
- Add const struct iio_info *iio_info to hx711_chip_info; probe sets
indio_dev->info = chip_info->iio_info directly
- Remove NULL check after device_get_match_data()
- Remove reset_channel from hx711_chip_info (always 0; use literal)
- Change hx711_reset_read() and hx710b_set_channel() to take
const struct iio_chan_spec * instead of int chan
- Revert hx711_data struct member alignment noise
- Restore trailing blank line at end of file (unrelated removal reverted)
- Sort of_device_id entries alphabetically (hx710b before hx711)
- Expand commit message to explain HX711 vs HX710B trailing-pulse model
- Restore file header to mention weight sensor modules
drivers/iio/adc/Kconfig | 9 +-
drivers/iio/adc/hx711.c | 206 ++++++++++++++++++++++++++++++++--------
2 files changed, 174 insertions(+), 41 deletions(-)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 60038ae8dfc4..ddf981fa72a2 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -784,18 +784,21 @@ config HI8435
called hi8435.
config HX711
- tristate "AVIA HX711 ADC for weight cells"
+ tristate "AVIA HX711 and HX710B ADC"
depends on GPIOLIB
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
- If you say yes here you get support for AVIA HX711 ADC which is used
- for weigh cells
+ If you say yes here you get support for AVIA HX711 and HX710B ADCs
+ which are used for bridge sensors such as weigh cells.
This driver uses two GPIOs, one acts as the clock and controls the
channel selection and gain, the other one is used for the measurement
data
+ The HX710B is a variant with fixed gain and a different channel
+ selection scheme.
+
Currently the raw value is read from the chip and delivered.
To get an actual weight one needs to subtract the
zero offset and multiply by a scale factor.
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index 1db8b68a8f64..b024fb341b2e 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * HX711: analog to digital converter for weight sensor module
+ * HX711/HX710B: ADC driver for weight sensor modules
*
* Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de>
*/
@@ -76,12 +76,33 @@ static int hx711_get_scale_to_gain(int scale)
return -EINVAL;
}
+/**
+ * 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
+ * @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;
+ int num_channels;
+ const struct iio_info *iio_info;
+ bool fixed_gain;
+ int fixed_gain_val;
+};
+
struct hx711_data {
struct device *dev;
struct gpio_desc *gpiod_pd_sck;
struct gpio_desc *gpiod_dout;
int gain_set; /* gain set on device */
int gain_chan_a; /* gain for channel A */
+ int channel_set; /* HX710B current channel */
+ int scale; /* HX710B fixed scale */
+ const struct hx711_chip_info *chip_info;
struct mutex lock;
/*
* triggered buffer
@@ -92,10 +113,7 @@ struct hx711_data {
aligned_s64 timestamp;
} buffer;
/*
- * delay after a rising edge on SCK until the data is ready DOUT
- * this is dependent on the hx711 where the datasheet tells a
- * maximum value of 100 ns
- * but also on potential parasitic capacities on the wiring
+ * Delay after SCK rising edge before sampling DOUT.
*/
u32 data_ready_delay_ns;
u32 clock_frequency;
@@ -139,7 +157,11 @@ static int hx711_cycle(struct hx711_data *hx711_data)
return gpiod_get_value(hx711_data->gpiod_dout);
}
-static int hx711_read(struct hx711_data *hx711_data)
+/*
+ * Clock out 24 data bits and then send trailing pulses to select the
+ * next channel/gain state.
+ */
+static int hx711_read(struct hx711_data *hx711_data, int trailing_pulses)
{
int i, ret;
int value = 0;
@@ -158,7 +180,7 @@ static int hx711_read(struct hx711_data *hx711_data)
value ^= 0x800000;
- for (i = 0; i < hx711_get_gain_to_pulse(hx711_data->gain_set); i++)
+ for (i = 0; i < trailing_pulses; i++)
hx711_cycle(hx711_data);
return value;
@@ -188,6 +210,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) {
@@ -206,13 +229,17 @@ 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;
}
+/* Select HX711 channel/gain for the next conversion. */
static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
{
int ret;
@@ -221,7 +248,8 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
if (hx711_data->gain_set == 32) {
hx711_data->gain_set = hx711_data->gain_chan_a;
- ret = hx711_read(hx711_data);
+ ret = hx711_read(hx711_data,
+ hx711_get_gain_to_pulse(hx711_data->gain_set));
if (ret < 0)
return ret;
@@ -233,7 +261,8 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
if (hx711_data->gain_set != 32) {
hx711_data->gain_set = 32;
- ret = hx711_read(hx711_data);
+ ret = hx711_read(hx711_data,
+ hx711_get_gain_to_pulse(hx711_data->gain_set));
if (ret < 0)
return ret;
@@ -246,27 +275,50 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
return 0;
}
-static int hx711_reset_read(struct hx711_data *hx711_data, int chan)
+/* 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;
- int val;
- /*
- * hx711_reset() must be called from here
- * because it could be calling hx711_read() by itself
- */
+ if (hx711_data->channel_set == chan->channel)
+ return 0;
+
+ hx711_data->channel_set = chan->channel;
+
+ ret = hx711_read(hx711_data, chan->address);
+ if (ret < 0)
+ return ret;
+
+ return hx711_wait_for_ready(hx711_data);
+}
+
+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;
+ int trailing_pulses;
+ int ret;
+
+ /* Reset first so the read starts from a known chip state. */
if (hx711_reset(hx711_data)) {
dev_err(hx711_data->dev, "reset failed!");
return -EIO;
}
- ret = hx711_set_gain_for_channel(hx711_data, chan);
- if (ret < 0)
- return ret;
-
- val = hx711_read(hx711_data);
+ 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);
+ }
- return val;
+ return hx711_read(hx711_data, trailing_pulses);
}
static int hx711_read_raw(struct iio_dev *indio_dev,
@@ -274,12 +326,13 @@ 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:
mutex_lock(&hx711_data->lock);
- *val = hx711_reset_read(hx711_data, chan->channel);
+ *val = hx711_reset_read(hx711_data, chan);
mutex_unlock(&hx711_data->lock);
@@ -290,7 +343,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);
@@ -332,7 +388,8 @@ static int hx711_write_raw(struct iio_dev *indio_dev,
if (gain != 32)
hx711_data->gain_chan_a = gain;
- ret = hx711_read(hx711_data);
+ ret = hx711_read(hx711_data,
+ hx711_get_gain_to_pulse(hx711_data->gain_set));
if (ret < 0) {
mutex_unlock(&hx711_data->lock);
return ret;
@@ -368,7 +425,7 @@ static irqreturn_t hx711_trigger(int irq, void *p)
iio_for_each_active_channel(indio_dev, i) {
hx711_data->buffer.channel[j] = hx711_reset_read(hx711_data,
- indio_dev->channels[i].channel);
+ &indio_dev->channels[i]);
j++;
}
@@ -423,6 +480,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,
@@ -455,10 +516,69 @@ 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,
+ .num_channels = ARRAY_SIZE(hx711_chan_spec),
+ .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;
struct hx711_data *hx711_data;
+ const struct hx711_chip_info *chip_info;
struct iio_dev *indio_dev;
int ret;
int i;
@@ -472,6 +592,9 @@ static int hx711_probe(struct platform_device *pdev)
mutex_init(&hx711_data->lock);
+ chip_info = device_get_match_data(dev);
+ hx711_data->chip_info = chip_info;
+
/*
* PD_SCK stands for power down and serial clock input of HX711
* in the driver it is an output
@@ -510,12 +633,19 @@ 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) {
+ /* Fixed-gain variant: compute scale once at probe. */
+ 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;
hx711_data->clock_frequency = 400000;
ret = device_property_read_u32(&pdev->dev, "clock-frequency",
@@ -533,11 +663,10 @@ static int hx711_probe(struct platform_device *pdev)
hx711_data->data_ready_delay_ns =
1000000000 / hx711_data->clock_frequency;
- indio_dev->name = "hx711";
- indio_dev->info = &hx711_iio_info;
+ indio_dev->name = chip_info->name;
indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->channels = hx711_chan_spec;
- indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec);
+ indio_dev->channels = chip_info->channels;
+ indio_dev->num_channels = chip_info->num_channels;
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
@@ -554,7 +683,8 @@ static int hx711_probe(struct platform_device *pdev)
}
static const struct of_device_id of_hx711_match[] = {
- { .compatible = "avia,hx711", },
+ { .compatible = "avia,hx710b", .data = &hx710b_chip },
+ { .compatible = "avia,hx711", .data = &hx711_chip },
{ }
};
@@ -571,7 +701,7 @@ static struct platform_driver hx711_driver = {
module_platform_driver(hx711_driver);
MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
-MODULE_DESCRIPTION("HX711 bitbanging driver - ADC for weight cells");
+MODULE_DESCRIPTION("HX711/HX710B GPIO ADC driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:hx711-gpio");
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/2] iio: adc: hx711: add support for HX710B
2026-04-19 17:46 ` [PATCH v2 2/2] iio: adc: hx711: add support for HX710B Piyush Patle
@ 2026-04-20 9:03 ` Andy Shevchenko
0 siblings, 0 replies; 5+ messages in thread
From: Andy Shevchenko @ 2026-04-20 9:03 UTC (permalink / raw)
To: Piyush Patle
Cc: jic23, ak, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
linux-iio, devicetree, linux-kernel
On Sun, Apr 19, 2026 at 11:16:40PM +0530, Piyush Patle wrote:
> The HX711 uses trailing SCK pulses after each 24-bit conversion to
> select the channel and gain for the next measurement: 1 pulse gives
> channel A at gain 128, 2 pulses give channel B at gain 32, and 3 pulses
> give channel A at gain 64.
>
> The HX710B works differently: gain is fixed at 128 and the trailing
> pulses select only the channel. One trailing pulse selects the
> differential input (channel 0, 10 SPS) and two trailing pulses select
> the DVDD-AVDD supply monitor (channel 1, 40 SPS).
>
> Refactor the driver around a per-chip hx711_chip_info structure so both
> variants can share the same core. Each chip provides its own
> iio_chan_spec array and iio_info pointer. The HX710B stores per-channel
> trailing pulse counts in chan->address (1 for channel 0, 2 for
> channel 1) instead of a separate array. A bool fixed_gain flag and
> fixed_gain_val field in hx711_chip_info distinguish the fixed-gain path
> from the HX711's user-selectable gain path without conflating unrelated
> properties. The HX710B differential input channel is described with
> .differential=1 and .channel2=1 as required by the IIO ABI.
>
> Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
> ---
> Changes in v2:
> - Fix pulse count bug: hx710b values were {25, 26} (total SCK cycles);
> corrected to {1, 2} (trailing-only, hx711_read() clocks 24 data bits)
Which questions how it was tested...
> - Add .differential = 1 and .channel2 = 1 to HX710B channel 0
> - Move trailing pulse counts from a separate array to chan->address
> (1 for ch0, 2 for ch1); remove chan_pulse_count / num_chan_pulses
> - Replace chan_pulse_count != NULL tests with dedicated bool fixed_gain
> flag; add fixed_gain_val field to hx711_chip_info
> - Add const struct iio_info *iio_info to hx711_chip_info; probe sets
> indio_dev->info = chip_info->iio_info directly
> - Remove NULL check after device_get_match_data()
> - Remove reset_channel from hx711_chip_info (always 0; use literal)
> - Change hx711_reset_read() and hx710b_set_channel() to take
> const struct iio_chan_spec * instead of int chan
> - Revert hx711_data struct member alignment noise
> - Restore trailing blank line at end of file (unrelated removal reverted)
> - Sort of_device_id entries alphabetically (hx710b before hx711)
> - Expand commit message to explain HX711 vs HX710B trailing-pulse model
> - Restore file header to mention weight sensor modules
...
> config HX711
> - tristate "AVIA HX711 ADC for weight cells"
> + tristate "AVIA HX711 and HX710B ADC"
This won't scale. Better to put something like "and compatible".
Also use plural "ADCs".
> depends on GPIOLIB
> select IIO_BUFFER
> select IIO_TRIGGERED_BUFFER
> help
> - If you say yes here you get support for AVIA HX711 ADC which is used
> - for weigh cells
> + If you say yes here you get support for AVIA HX711 and HX710B ADCs
> + which are used for bridge sensors such as weigh cells.
Usually for the less churn in the future we list them one per line. This
will give easier understanding of what is supported (keep them also sorted).
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.
> This driver uses two GPIOs, one acts as the clock and controls the
> channel selection and gain, the other one is used for the measurement
> data
>
> + The HX710B is a variant with fixed gain and a different channel
> + selection scheme.
> +
> Currently the raw value is read from the chip and delivered.
> To get an actual weight one needs to subtract the
> zero offset and multiply by a scale factor.
...
> - * HX711: analog to digital converter for weight sensor module
> + * HX711/HX710B: ADC driver for weight sensor modules
Use same as in Kconfig:
* HX711 and compatible ADCs driver for weight sensor modules
...
> +/**
> + * 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
> + * @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;
> + int num_channels;
Why signed?
> + const struct iio_info *iio_info;
> + bool fixed_gain;
> + int fixed_gain_val;
> +};
...
> struct hx711_data {
> struct device *dev;
> struct gpio_desc *gpiod_pd_sck;
> struct gpio_desc *gpiod_dout;
> int gain_set; /* gain set on device */
> int gain_chan_a; /* gain for channel A */
> + int channel_set; /* HX710B current channel */
> + int scale; /* HX710B fixed scale */
Check if those need to be signed.
> + const struct hx711_chip_info *chip_info;
> struct mutex lock;
> }
...
> - for (i = 0; i < hx711_get_gain_to_pulse(hx711_data->gain_set); i++)
> + for (i = 0; i < trailing_pulses; i++)
If 'i' is used only once here, it can be converted to
for (unsigned int i = 0; i < trailing_pulses; i++)
> hx711_cycle(hx711_data);
>
> return value;
...
> + .num_channels = ARRAY_SIZE(hx711_chan_spec),
You also probably want to revisit inclusion block. At least follow IWYU in the
code you added here, exempli gratia include array_size.h and types.h if not yet
included.
...
> hx711_data->clock_frequency = 400000;
Sounds like I2C or SD standard speed :-)
Not sure, but can be also converted to use 400 * HZ_PER_KHZ (from units.h)
in a separate change.
...
> hx711_data->data_ready_delay_ns =
> 1000000000 / hx711_data->clock_frequency;
Side note, in a separate change you can use constants from time.h, id est
NSEC_PER_SEC.
...
> static const struct of_device_id of_hx711_match[] = {
> - { .compatible = "avia,hx711", },
> + { .compatible = "avia,hx710b", .data = &hx710b_chip },
Please, split this to a separate change. So, first introduce the chip_info,
then add your device support using given infrastructure.
That said, you also can convert the driver to use guard()() from cleanup.h
in a separate change.
> + { .compatible = "avia,hx711", .data = &hx711_chip },
> { }
> };
...
> -MODULE_DESCRIPTION("HX711 bitbanging driver - ADC for weight cells");
Ah, this removes crucial information. So, this driver probably just needs to
use i2c_gpio?
> +MODULE_DESCRIPTION("HX711/HX710B GPIO ADC driver");
Use what is written in Kconfig.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/2] dt-bindings: iio: adc: avia-hx711: add avia,hx710b compatible
2026-04-19 17:46 ` [PATCH v2 1/2] dt-bindings: iio: adc: avia-hx711: add avia,hx710b compatible Piyush Patle
@ 2026-04-21 8:23 ` Krzysztof Kozlowski
0 siblings, 0 replies; 5+ messages in thread
From: Krzysztof Kozlowski @ 2026-04-21 8:23 UTC (permalink / raw)
To: Piyush Patle
Cc: jic23, ak, dlechner, nuno.sa, andy, robh, krzk+dt, conor+dt,
linux-iio, devicetree, linux-kernel
On Sun, Apr 19, 2026 at 11:16:39PM +0530, Piyush Patle wrote:
> description: |
> - Bit-banging driver using two GPIOs:
> - - sck-gpio gives a clock to the sensor with 24 cycles for data retrieval
> - and up to 3 cycles for selection of the input channel and gain for the
> - next measurement
> - - dout-gpio is the sensor data the sensor responds to the clock
> + The HX711 is a 24-bit ADC with selectable gain (32/64/128) and two
> + differential input channels. Channel A supports gain 64 and 128;
> + channel B supports gain 32.
>
> - Specifications about the driver can be found at:
> - http://www.aviaic.com/ENProducts.aspx
> + The HX710B is a 24-bit ADC with fixed gain of 128. Channel 0 is the
> + differential input and channel 1 measures the DVDD-AVDD supply
> + voltage difference.
>
> properties:
> compatible:
> enum:
> + - avia,hx710b
> - avia,hx711
>
> sck-gpios:
> @@ -40,13 +40,45 @@ properties:
>
> avdd-supply:
> description:
> - Definition of the regulator used as analog supply
> + Analog supply voltage (AVDD). Also serves as the voltage reference on
> + both chips; no separate vref-supply is required.
There is no such thing as vref-supply.
> +
> + dvdd-supply:
> + description:
> + Digital supply voltage (DVDD). HX711 only.
> +
> + vsup-supply:
> + description:
> + Supply voltage for the on-chip regulator (VSUP). HX711 only.
> +
> + rate-gpios:
> + description:
> + GPIO connected to the RATE pin (HX711 only). When driven low the
> + output data rate is 10 SPS; when driven high it is 80 SPS. If
> + omitted the RATE pin state is determined by the board wiring.
> + maxItems: 1
>
> clock-frequency:
> + description:
> + Controls the SCK bit-bang timing. The value is used to derive the
> + delay between SCK edges; keep the SCK high time below 60 us to
> + avoid triggering chip power-down mode. Defaults to 400 kHz if not
> + specified.
Don't repeat constraints in free form text. Drop last sentence.
> minimum: 20000
> maximum: 2500000
> default: 400000
>
> +allOf:
> + - if:
> + properties:
> + compatible:
> + const: avia,hx710b
> + then:
> + properties:
> + vsup-supply: false
> + dvdd-supply: false
> + rate-gpios: false
> +
> required:
> - compatible
> - sck-gpios
> @@ -58,10 +90,19 @@ additionalProperties: false
> examples:
> - |
> #include <dt-bindings/gpio/gpio.h>
> - weight {
> + weight0 {
Don't change the node names.
> compatible = "avia,hx711";
> sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
> dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
> + rate-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
> avdd-supply = <&avdd>;
> clock-frequency = <100000>;
> };
> + - |
> + #include <dt-bindings/gpio/gpio.h>
> + weight1 {
> + compatible = "avia,hx710b";
> + sck-gpios = <&gpio3 11 GPIO_ACTIVE_HIGH>;
> + dout-gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>;
> + avdd-supply = <&avdd>;
Why no clock-frequency? So basically difference is one property? Then no
need for new example, less code to maintain.
But OTOH, where is vsup and dvdd?
> + };
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-04-21 8:23 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-19 17:46 [PATCH v2 0/2] iio: adc: hx711: add HX710B support Piyush Patle
2026-04-19 17:46 ` [PATCH v2 1/2] dt-bindings: iio: adc: avia-hx711: add avia,hx710b compatible Piyush Patle
2026-04-21 8:23 ` Krzysztof Kozlowski
2026-04-19 17:46 ` [PATCH v2 2/2] iio: adc: hx711: add support for HX710B Piyush Patle
2026-04-20 9:03 ` Andy Shevchenko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox