* [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC
@ 2026-06-03 18:48 Piyush Patle
2026-06-03 18:48 ` [PATCH v11 01/11] dt-bindings: iio: adc: hx711: clean up existing binding text Piyush Patle
` (10 more replies)
0 siblings, 11 replies; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
The HX710B is a 24-bit ADC from AVIA Semiconductor, related to the
HX711 already supported in this driver. Unlike the HX711 (which has
selectable gain and two input channels), the HX710B has a fixed gain
of 128 and two operating modes selected by the trailing PD_SCK pulse
count after each conversion:
25 pulses (1 trailing): differential input at 10 SPS
26 pulses (2 trailing): DVDD-AVDD supply monitor at 40 SPS
27 pulses (3 trailing): differential input at 40 SPS
This series first extends the existing HX711 binding and driver with
preparatory refactoring, then adds HX710B support on top.
The differential input is exposed as a single IIO channel with
IIO_CHAN_INFO_SAMP_FREQ, allowing userspace to select 10 or 40 SPS
without needing two separate channels for the same physical input.
The supply monitor is a second channel at fixed 40 SPS.
This revision is rebased onto current mainline. Note that
iio_device_claim_direct_mode() / iio_device_release_direct_mode() were
removed from the IIO core since v10, so 11/11 now uses the replacement
iio_device_claim_direct() / iio_device_release_direct() API.
Tested on a PocketBeagle2 (TI AM625): the avia,hx710b node probes and
the driver registers its two IIO channels.
Changes from v10:
- 02/11: Retitled to "add VSUP and DVDD supply properties"; the
commit message now documents both supplies (the patch already
added both; only the title/text were out of sync). [Jonathan]
- 04/11: Reworded commit message so DVDD is no longer described as
HX710B-specific (it is added for both parts in 02/11). The
compatible match now uses "contains: const: avia,hx710b" so the
constraints still apply if the compatible is later used as a
fallback. dvdd-supply is now required for HX710B (in the HX710B
branch only, so existing HX711 device trees are unaffected) and
added to the HX710B example. [Jonathan, Conor, Sashiko]
- 11/11: Kconfig title and file header use "similar" instead of
"compatible". Simplified the tail of hx711_set_hx710b_channel()
to "return hx711_wait_for_ready()". Dropped an unrelated
reindentation of the iio_push_to_buffers_with_timestamp() call.
Converted hx710b_write_raw() to the new
iio_device_claim_direct() API (see above). [Jonathan]
The Reviewed-by (Andy Shevchenko) and Acked-by (Conor Dooley) tags on
02/11 and 04/11 are carried over although those patches changed; please
re-confirm if you disagree with the reworked constraints.
Patches 01/11, 03/11, and 05/11 are unchanged from v10.
Piyush Patle (11):
dt-bindings: iio: adc: hx711: clean up existing binding text
dt-bindings: iio: adc: hx711: add VSUP and DVDD supply properties
dt-bindings: iio: adc: hx711: add RATE GPIO property
dt-bindings: iio: adc: hx711: add HX710B support
iio: adc: hx711: move scale computation to per-device storage
iio: adc: hx711: introduce hx711_chip_info structure
iio: adc: hx711: pass trailing pulse count into hx711_read
iio: adc: hx711: split variable assignments in hx711_read and
hx711_reset
iio: adc: hx711: localize loop iterators in hx711_read
iio: adc: hx711: pass iio_chan_spec to hx711_reset_read
iio: adc: hx711: add support for HX710B
.../bindings/iio/adc/avia-hx711.yaml | 82 ++++-
drivers/iio/adc/Kconfig | 8 +-
drivers/iio/adc/hx711.c | 343 +++++++++++++++---
3 files changed, 359 insertions(+), 74 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v11 01/11] dt-bindings: iio: adc: hx711: clean up existing binding text
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 18:48 ` [PATCH v11 02/11] dt-bindings: iio: adc: hx711: add VSUP and DVDD supply properties Piyush Patle
` (9 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
Rewrite the binding description and property text so it describes the
existing HX711 hardware behavior directly instead of documenting old
driver implementation details.
Also clarify that clock-frequency controls the SCK bit-bang timing.
No functional change.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/iio/adc/avia-hx711.yaml | 25 ++++++++-----------
1 file changed, 10 insertions(+), 15 deletions(-)
diff --git a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
index 9c57eb13f892..1ea60dff98d5 100644
--- a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
@@ -10,14 +10,9 @@ 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
-
- Specifications about the driver can be found at:
- http://www.aviaic.com/ENProducts.aspx
+ 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.
properties:
compatible:
@@ -26,23 +21,23 @@ properties:
sck-gpios:
description:
- Definition of the GPIO for the clock (output). In the datasheet it is
- named PD_SCK
+ GPIO for the clock output (PD_SCK in the datasheet).
maxItems: 1
dout-gpios:
description:
- Definition of the GPIO for the data-out sent by the sensor in
- response to the clock (input).
- See Documentation/devicetree/bindings/gpio/gpio.txt for information
- on how to specify a consumer gpio.
+ GPIO for the data output from the sensor (DOUT in the datasheet).
maxItems: 1
avdd-supply:
description:
- Definition of the regulator used as analog supply
+ Analog supply voltage (AVDD).
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.
minimum: 20000
maximum: 2500000
default: 400000
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v11 02/11] dt-bindings: iio: adc: hx711: add VSUP and DVDD supply properties
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
2026-06-03 18:48 ` [PATCH v11 01/11] dt-bindings: iio: adc: hx711: clean up existing binding text Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 18:48 ` [PATCH v11 03/11] dt-bindings: iio: adc: hx711: add RATE GPIO property Piyush Patle
` (8 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
Document the optional VSUP supply used by the HX711 on-chip regulator.
Also document the DVDD digital supply. DVDD is a board-supplied digital
input rail (figure 1 of the datasheet shows it as a separate supply, not
merely a bypass capacitor point) that was missing from the original
binding.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../devicetree/bindings/iio/adc/avia-hx711.yaml | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
index 1ea60dff98d5..0baf620e9057 100644
--- a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
@@ -33,6 +33,19 @@ properties:
description:
Analog supply voltage (AVDD).
+ vsup-supply:
+ description:
+ Supply voltage for the on-chip regulator (VSUP).
+
+ dvdd-supply:
+ description:
+ Digital supply voltage (DVDD). On the HX711, DVDD is a
+ board-supplied digital rail; it was missing from the original
+ binding. On the HX710B, DVDD must be greater than or equal to
+ AVDD; when DVDD is a battery rail and AVDD is a regulated supply,
+ one channel monitors the DVDD-AVDD difference for battery level
+ detection.
+
clock-frequency:
description:
Controls the SCK bit-bang timing. The value is used to derive the
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v11 03/11] dt-bindings: iio: adc: hx711: add RATE GPIO property
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
2026-06-03 18:48 ` [PATCH v11 01/11] dt-bindings: iio: adc: hx711: clean up existing binding text Piyush Patle
2026-06-03 18:48 ` [PATCH v11 02/11] dt-bindings: iio: adc: hx711: add VSUP and DVDD supply properties Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 18:48 ` [PATCH v11 04/11] dt-bindings: iio: adc: hx711: add HX710B support Piyush Patle
` (7 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
Document the optional RATE pin GPIO used to select the HX711 output
data rate.
Update the example to show the property in use.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
index 0baf620e9057..099235b5fd54 100644
--- a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
@@ -46,6 +46,13 @@ properties:
one channel monitors the DVDD-AVDD difference for battery level
detection.
+ rate-gpios:
+ description:
+ GPIO connected to the RATE pin. 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
@@ -70,6 +77,7 @@ examples:
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>;
};
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v11 04/11] dt-bindings: iio: adc: hx711: add HX710B support
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
` (2 preceding siblings ...)
2026-06-03 18:48 ` [PATCH v11 03/11] dt-bindings: iio: adc: hx711: add RATE GPIO property Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 19:02 ` sashiko-bot
2026-06-03 18:48 ` [PATCH v11 05/11] iio: adc: hx711: move scale computation to per-device storage Piyush Patle
` (6 subsequent siblings)
10 siblings, 1 reply; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
Add the avia,hx710b compatible and document the HX710B VREF supply.
Add constraints that forbid HX711-only properties on HX710B nodes and
require vref-supply and dvdd-supply for HX710B, then add a separate
HX710B example.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
---
.../bindings/iio/adc/avia-hx711.yaml | 38 ++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
index 099235b5fd54..13a3a8b007e2 100644
--- a/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml
@@ -4,7 +4,7 @@
$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>
@@ -14,9 +14,14 @@ description: |
differential input channels. Channel A supports gain 64 and 128;
channel B supports gain 32.
+ The HX710B is a 24-bit ADC with fixed gain of 128. One input measures
+ the differential voltage between the two input pins; a second measures
+ the DVDD-AVDD supply voltage difference for battery level detection.
+
properties:
compatible:
enum:
+ - avia,hx710b
- avia,hx711
sck-gpios:
@@ -53,6 +58,10 @@ properties:
RATE pin state is determined by the board wiring.
maxItems: 1
+ vref-supply:
+ description:
+ Reference voltage input (VREF).
+
clock-frequency:
description:
Controls the SCK bit-bang timing. The value is used to derive the
@@ -62,6 +71,23 @@ properties:
maximum: 2500000
default: 400000
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: avia,hx710b
+ then:
+ properties:
+ vsup-supply: false
+ rate-gpios: false
+ required:
+ - vref-supply
+ - dvdd-supply
+ else:
+ properties:
+ vref-supply: false
+
required:
- compatible
- sck-gpios
@@ -81,3 +107,13 @@ examples:
avdd-supply = <&avdd>;
clock-frequency = <100000>;
};
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ weight {
+ compatible = "avia,hx710b";
+ sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
+ dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
+ avdd-supply = <&avdd>;
+ dvdd-supply = <&dvdd>;
+ vref-supply = <&vref>;
+ };
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v11 05/11] iio: adc: hx711: move scale computation to per-device storage
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
` (3 preceding siblings ...)
2026-06-03 18:48 ` [PATCH v11 04/11] dt-bindings: iio: adc: hx711: add HX710B support Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 18:48 ` [PATCH v11 06/11] iio: adc: hx711: introduce hx711_chip_info structure Piyush Patle
` (5 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
The gain-to-scale table is global today, so probe-time scale updates for
one device overwrite the values used by any earlier device instance.
Fix this by making the gain table const and storing the computed scale
values per device in hx711_data.
No functional change for single-sensor configurations.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
drivers/iio/adc/hx711.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index 1db8b68a8f64..86d2a70dd3de 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -28,22 +28,20 @@
struct hx711_gain_to_scale {
int gain;
int gain_pulse;
- int scale;
int channel;
};
/*
* .scale depends on AVDD which in turn is known as soon as the regulator
- * is available
- * therefore we set .scale in hx711_probe()
+ * is available; it is stored per device in hx711_data.gain_scale[]
*
* channel A in documentation is channel 0 in source code
* channel B in documentation is channel 1 in source code
*/
-static struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = {
- { 128, 1, 0, 0 },
- { 32, 2, 0, 1 },
- { 64, 3, 0, 0 }
+static const struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = {
+ { 128, 1, 0 },
+ { 32, 2, 1 },
+ { 64, 3, 0 },
};
static int hx711_get_gain_to_pulse(int gain)
@@ -56,22 +54,22 @@ static int hx711_get_gain_to_pulse(int gain)
return 1;
}
-static int hx711_get_gain_to_scale(int gain)
+static int hx711_get_gain_to_scale(const int *gain_scale, int gain)
{
int i;
for (i = 0; i < HX711_GAIN_MAX; i++)
if (hx711_gain_to_scale[i].gain == gain)
- return hx711_gain_to_scale[i].scale;
+ return gain_scale[i];
return 0;
}
-static int hx711_get_scale_to_gain(int scale)
+static int hx711_get_scale_to_gain(const int *gain_scale, int scale)
{
int i;
for (i = 0; i < HX711_GAIN_MAX; i++)
- if (hx711_gain_to_scale[i].scale == scale)
+ if (gain_scale[i] == scale)
return hx711_gain_to_scale[i].gain;
return -EINVAL;
}
@@ -82,6 +80,7 @@ struct hx711_data {
struct gpio_desc *gpiod_dout;
int gain_set; /* gain set on device */
int gain_chan_a; /* gain for channel A */
+ int gain_scale[HX711_GAIN_MAX];
struct mutex lock;
/*
* triggered buffer
@@ -290,7 +289,8 @@ 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);
+ *val2 = hx711_get_gain_to_scale(hx711_data->gain_scale,
+ hx711_data->gain_set);
mutex_unlock(&hx711_data->lock);
@@ -321,7 +321,7 @@ static int hx711_write_raw(struct iio_dev *indio_dev,
mutex_lock(&hx711_data->lock);
- gain = hx711_get_scale_to_gain(val2);
+ gain = hx711_get_scale_to_gain(hx711_data->gain_scale, val2);
if (gain < 0) {
mutex_unlock(&hx711_data->lock);
return gain;
@@ -386,6 +386,7 @@ static ssize_t hx711_scale_available_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
+ struct hx711_data *hx711_data = iio_priv(dev_to_iio_dev(dev));
struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr);
int channel = iio_attr->address;
int i, len = 0;
@@ -393,7 +394,7 @@ static ssize_t hx711_scale_available_show(struct device *dev,
for (i = 0; i < HX711_GAIN_MAX; i++)
if (hx711_gain_to_scale[i].channel == channel)
len += sprintf(buf + len, "0.%09d ",
- hx711_gain_to_scale[i].scale);
+ hx711_data->gain_scale[i]);
len += sprintf(buf + len, "\n");
@@ -511,7 +512,7 @@ static int hx711_probe(struct platform_device *pdev)
ret *= 100;
for (i = 0; i < HX711_GAIN_MAX; i++)
- hx711_gain_to_scale[i].scale =
+ hx711_data->gain_scale[i] =
ret / hx711_gain_to_scale[i].gain / 1678;
hx711_data->gain_set = 128;
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v11 06/11] iio: adc: hx711: introduce hx711_chip_info structure
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
` (4 preceding siblings ...)
2026-06-03 18:48 ` [PATCH v11 05/11] iio: adc: hx711: move scale computation to per-device storage Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 19:00 ` sashiko-bot
2026-06-03 18:48 ` [PATCH v11 07/11] iio: adc: hx711: pass trailing pulse count into hx711_read Piyush Patle
` (4 subsequent siblings)
10 siblings, 1 reply; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
Add a per-variant static configuration structure and populate the IIO
device fields from it at probe time.
This is a preparatory change for adding support for more HX711-compatible
hardware variants without duplicating the probe-time setup.
No functional change for existing HX711 users.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
drivers/iio/adc/hx711.c | 41 ++++++++++++++++++++++++++++++++++++-----
1 file changed, 36 insertions(+), 5 deletions(-)
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index 86d2a70dd3de..10ccc69f209b 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -4,6 +4,8 @@
*
* Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de>
*/
+#include <linux/array_size.h>
+#include <linux/dev_printk.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -74,6 +76,20 @@ static int hx711_get_scale_to_gain(const int *gain_scale, int scale)
return -EINVAL;
}
+/**
+ * struct hx711_chip_info - per-variant static configuration
+ * @name: IIO device name
+ * @channels: channel specification array
+ * @num_channels: number of entries in @channels
+ * @iio_info: IIO info ops for this variant
+ */
+struct hx711_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channels __counted_by_ptr(num_channels);
+ unsigned int num_channels;
+ const struct iio_info *iio_info;
+};
+
struct hx711_data {
struct device *dev;
struct gpio_desc *gpiod_pd_sck;
@@ -81,6 +97,7 @@ struct hx711_data {
int gain_set; /* gain set on device */
int gain_chan_a; /* gain for channel A */
int gain_scale[HX711_GAIN_MAX];
+ const struct hx711_chip_info *chip_info;
struct mutex lock;
/*
* triggered buffer
@@ -456,8 +473,16 @@ static const struct iio_chan_spec hx711_chan_spec[] = {
IIO_CHAN_SOFT_TIMESTAMP(2),
};
+static const struct hx711_chip_info hx711_chip = {
+ .name = "hx711",
+ .channels = hx711_chan_spec,
+ .iio_info = &hx711_iio_info,
+ .num_channels = ARRAY_SIZE(hx711_chan_spec),
+};
+
static int hx711_probe(struct platform_device *pdev)
{
+ const struct hx711_chip_info *chip_info;
struct device *dev = &pdev->dev;
struct hx711_data *hx711_data;
struct iio_dev *indio_dev;
@@ -473,6 +498,12 @@ static int hx711_probe(struct platform_device *pdev)
mutex_init(&hx711_data->lock);
+ chip_info = device_get_match_data(dev);
+ if (!chip_info)
+ return dev_err_probe(dev, -ENODEV, "missing driver data\n");
+
+ 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
@@ -534,11 +565,11 @@ 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->info = chip_info->iio_info;
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,
@@ -555,7 +586,7 @@ static int hx711_probe(struct platform_device *pdev)
}
static const struct of_device_id of_hx711_match[] = {
- { .compatible = "avia,hx711", },
+ { .compatible = "avia,hx711", .data = &hx711_chip },
{ }
};
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v11 07/11] iio: adc: hx711: pass trailing pulse count into hx711_read
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
` (5 preceding siblings ...)
2026-06-03 18:48 ` [PATCH v11 06/11] iio: adc: hx711: introduce hx711_chip_info structure Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 18:48 ` [PATCH v11 08/11] iio: adc: hx711: split variable assignments in hx711_read and hx711_reset Piyush Patle
` (3 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
Move the trailing-pulse selection out of hx711_read() and into its
callers.
This is a preparatory change so later variant-specific code can pass the
per-channel pulse count without adding a separate read path.
No functional change.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
drivers/iio/adc/hx711.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index 10ccc69f209b..30e1ce321747 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -155,7 +155,7 @@ 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)
+static int hx711_read(struct hx711_data *hx711_data, int trailing_pulses)
{
int i, ret;
int value = 0;
@@ -174,7 +174,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;
@@ -237,7 +237,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;
@@ -249,7 +250,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;
@@ -264,8 +266,8 @@ static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
static int hx711_reset_read(struct hx711_data *hx711_data, int chan)
{
+ int trailing_pulses;
int ret;
- int val;
/*
* hx711_reset() must be called from here
@@ -280,9 +282,8 @@ static int hx711_reset_read(struct hx711_data *hx711_data, int chan)
if (ret < 0)
return ret;
- val = hx711_read(hx711_data);
-
- return val;
+ trailing_pulses = hx711_get_gain_to_pulse(hx711_data->gain_set);
+ return hx711_read(hx711_data, trailing_pulses);
}
static int hx711_read_raw(struct iio_dev *indio_dev,
@@ -349,7 +350,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;
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v11 08/11] iio: adc: hx711: split variable assignments in hx711_read and hx711_reset
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
` (6 preceding siblings ...)
2026-06-03 18:48 ` [PATCH v11 07/11] iio: adc: hx711: pass trailing pulse count into hx711_read Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 18:48 ` [PATCH v11 09/11] iio: adc: hx711: localize loop iterators in hx711_read Piyush Patle
` (2 subsequent siblings)
10 siblings, 0 replies; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
Separate the initial value assignments from the declarations in
hx711_read() and hx711_reset().
This is a small preparatory cleanup before the later loop-iterator and
variant-specific changes adjust the local variable layout in these
functions.
No functional change.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
drivers/iio/adc/hx711.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index 30e1ce321747..4ccb0bf2d71f 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -159,9 +159,10 @@ static int hx711_read(struct hx711_data *hx711_data, int trailing_pulses)
{
int i, ret;
int value = 0;
- int val = gpiod_get_value(hx711_data->gpiod_dout);
+ int val;
/* we double check if it's really down */
+ val = gpiod_get_value(hx711_data->gpiod_dout);
if (val)
return -EIO;
@@ -204,8 +205,9 @@ static int hx711_wait_for_ready(struct hx711_data *hx711_data)
static int hx711_reset(struct hx711_data *hx711_data)
{
- int val = hx711_wait_for_ready(hx711_data);
+ int val;
+ val = hx711_wait_for_ready(hx711_data);
if (val) {
/*
* an examination with the oszilloscope indicated
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v11 09/11] iio: adc: hx711: localize loop iterators in hx711_read
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
` (7 preceding siblings ...)
2026-06-03 18:48 ` [PATCH v11 08/11] iio: adc: hx711: split variable assignments in hx711_read and hx711_reset Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 18:48 ` [PATCH v11 10/11] iio: adc: hx711: pass iio_chan_spec to hx711_reset_read Piyush Patle
2026-06-03 18:48 ` [PATCH v11 11/11] iio: adc: hx711: add support for HX710B Piyush Patle
10 siblings, 0 replies; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
Tighten the scope of the loop variables in hx711_read() now that
trailing-pulse selection is already handled by the callers.
Also replace the 24-bit loop bound with a named constant while touching
the same code.
Suggested-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
drivers/iio/adc/hx711.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index 4ccb0bf2d71f..e5d842853b71 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -23,6 +23,8 @@
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
+#define HX711_DATA_BITS 24
+
/* gain to pulse and scale conversion */
#define HX711_GAIN_MAX 3
#define HX711_RESET_GAIN 128
@@ -157,16 +159,16 @@ static int hx711_cycle(struct hx711_data *hx711_data)
static int hx711_read(struct hx711_data *hx711_data, int trailing_pulses)
{
- int i, ret;
int value = 0;
int val;
+ int ret;
/* we double check if it's really down */
val = gpiod_get_value(hx711_data->gpiod_dout);
if (val)
return -EIO;
- for (i = 0; i < 24; i++) {
+ for (int i = 0; i < HX711_DATA_BITS; i++) {
value <<= 1;
ret = hx711_cycle(hx711_data);
if (ret)
@@ -175,7 +177,7 @@ static int hx711_read(struct hx711_data *hx711_data, int trailing_pulses)
value ^= 0x800000;
- for (i = 0; i < trailing_pulses; i++)
+ for (int i = 0; i < trailing_pulses; i++)
hx711_cycle(hx711_data);
return value;
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v11 10/11] iio: adc: hx711: pass iio_chan_spec to hx711_reset_read
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
` (8 preceding siblings ...)
2026-06-03 18:48 ` [PATCH v11 09/11] iio: adc: hx711: localize loop iterators in hx711_read Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 18:48 ` [PATCH v11 11/11] iio: adc: hx711: add support for HX710B Piyush Patle
10 siblings, 0 replies; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
Change hx711_reset_read() to accept the channel descriptor directly and
update its callers accordingly.
Split the existing HX711 channel-selection work into a small helper so a
later variant-specific change can add a matching helper without growing
hx711_reset_read() further.
No functional change.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
drivers/iio/adc/hx711.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index e5d842853b71..fde95758b9a0 100644
--- a/drivers/iio/adc/hx711.c
+++ b/drivers/iio/adc/hx711.c
@@ -268,7 +268,23 @@ 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)
+static int hx711_set_hx711_channel(struct hx711_data *hx711_data,
+ const struct iio_chan_spec *chan,
+ int *trailing_pulses)
+{
+ int ret;
+
+ 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 0;
+}
+
+static int hx711_reset_read(struct hx711_data *hx711_data,
+ const struct iio_chan_spec *chan)
{
int trailing_pulses;
int ret;
@@ -282,11 +298,10 @@ static int hx711_reset_read(struct hx711_data *hx711_data, int chan)
return -EIO;
}
- ret = hx711_set_gain_for_channel(hx711_data, chan);
+ ret = hx711_set_hx711_channel(hx711_data, chan, &trailing_pulses);
if (ret < 0)
return ret;
- trailing_pulses = hx711_get_gain_to_pulse(hx711_data->gain_set);
return hx711_read(hx711_data, trailing_pulses);
}
@@ -300,7 +315,7 @@ static int hx711_read_raw(struct iio_dev *indio_dev,
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);
@@ -390,8 +405,8 @@ static irqreturn_t hx711_trigger(int irq, void *p)
memset(&hx711_data->buffer, 0, sizeof(hx711_data->buffer));
iio_for_each_active_channel(indio_dev, i) {
- hx711_data->buffer.channel[j] = hx711_reset_read(hx711_data,
- indio_dev->channels[i].channel);
+ hx711_data->buffer.channel[j] =
+ hx711_reset_read(hx711_data, &indio_dev->channels[i]);
j++;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v11 11/11] iio: adc: hx711: add support for HX710B
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
` (9 preceding siblings ...)
2026-06-03 18:48 ` [PATCH v11 10/11] iio: adc: hx711: pass iio_chan_spec to hx711_reset_read Piyush Patle
@ 2026-06-03 18:48 ` Piyush Patle
2026-06-03 19:06 ` sashiko-bot
10 siblings, 1 reply; 15+ messages in thread
From: Piyush Patle @ 2026-06-03 18:48 UTC (permalink / raw)
To: linux-iio, devicetree, linux-kernel
Cc: jic23, ak, robh, krzk+dt, conor+dt, andy, nuno.sa, dlechner
Add support for the AVIA HX710B ADC, which shares the HX711 GPIO
interface but uses trailing PD_SCK pulses to select the active mode.
Model the HX710B with variant-specific channel tables and IIO info,
track the active channel across conversions, and use the fixed gain
value when computing scale.
Also update the adjacent Kconfig text, file header, and module
description so the driver text matches the newly supported variant.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
---
drivers/iio/adc/Kconfig | 8 +-
drivers/iio/adc/hx711.c | 222 ++++++++++++++++++++++++++++++++++++----
2 files changed, 205 insertions(+), 25 deletions(-)
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index a9dedbb8eb46..28188c97030f 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -791,13 +791,15 @@ config HI8435
called hi8435.
config HX711
- tristate "AVIA HX711 ADC for weight cells"
+ tristate "AVIA HX711 and similar 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 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
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
index fde95758b9a0..447699e1d60b 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 and similar ADCs driver for weigh sensor modules
*
* Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de>
*/
@@ -15,6 +15,8 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/delay.h>
+#include <linux/types.h>
+
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
@@ -84,12 +86,16 @@ static int hx711_get_scale_to_gain(const int *gain_scale, int scale)
* @channels: channel specification array
* @num_channels: number of entries in @channels
* @iio_info: IIO info ops for this variant
+ * @fixed_gain_val: fixed PGA gain (used when @has_fixed_gain is true)
+ * @has_fixed_gain: true if the variant has a fixed ADC gain
*/
struct hx711_chip_info {
const char *name;
const struct iio_chan_spec *channels __counted_by_ptr(num_channels);
unsigned int num_channels;
const struct iio_info *iio_info;
+ unsigned int fixed_gain_val;
+ bool has_fixed_gain;
};
struct hx711_data {
@@ -99,6 +105,8 @@ struct hx711_data {
int gain_set; /* gain set on device */
int gain_chan_a; /* gain for channel A */
int gain_scale[HX711_GAIN_MAX];
+ int channel_set; /* HX710B active channel */
+ unsigned int samp_freq; /* HX710B differential channel sample rate */
const struct hx711_chip_info *chip_info;
struct mutex lock;
/*
@@ -207,6 +215,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;
val = hx711_wait_for_ready(hx711_data);
@@ -226,8 +235,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;
+ if (info->has_fixed_gain)
+ hx711_data->channel_set = 0;
+ else
+ /* after a reset the gain is 128 */
+ hx711_data->gain_set = HX711_RESET_GAIN;
}
return val;
@@ -283,9 +295,47 @@ static int hx711_set_hx711_channel(struct hx711_data *hx711_data,
return 0;
}
+/*
+ * Return the trailing pulse count for an HX710B channel (Table 3 in
+ * the datasheet). The supply-monitor channel always uses 2 trailing
+ * pulses; the differential channel uses 1 (10 SPS) or 3 (40 SPS).
+ */
+static int hx710b_trailing_pulses(const struct hx711_data *hx711_data,
+ const struct iio_chan_spec *chan)
+{
+ if (!chan->differential)
+ return 2;
+ return hx711_data->samp_freq == 10 ? 1 : 3;
+}
+
+/*
+ * Switch the HX710B to the requested channel for the next conversion.
+ * channel_set tracks the trailing pulse count that was last sent to the
+ * chip; it is updated immediately after hx711_read() commits the new
+ * mode in hardware, before waiting for the chip to be ready again.
+ */
+static int hx711_set_hx710b_channel(struct hx711_data *hx711_data,
+ const struct iio_chan_spec *chan)
+{
+ int trailing_pulses = hx710b_trailing_pulses(hx711_data, chan);
+ int ret;
+
+ if (hx711_data->channel_set == trailing_pulses)
+ return 0;
+
+ ret = hx711_read(hx711_data, trailing_pulses);
+ if (ret < 0)
+ return ret;
+
+ hx711_data->channel_set = trailing_pulses;
+
+ 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;
@@ -298,9 +348,16 @@ static int hx711_reset_read(struct hx711_data *hx711_data,
return -EIO;
}
- ret = hx711_set_hx711_channel(hx711_data, chan, &trailing_pulses);
- if (ret < 0)
- return ret;
+ if (info->has_fixed_gain) {
+ ret = hx711_set_hx710b_channel(hx711_data, chan);
+ if (ret < 0)
+ return ret;
+ trailing_pulses = hx710b_trailing_pulses(hx711_data, chan);
+ } else {
+ ret = hx711_set_hx711_channel(hx711_data, chan, &trailing_pulses);
+ if (ret < 0)
+ return ret;
+ }
return hx711_read(hx711_data, trailing_pulses);
}
@@ -322,6 +379,9 @@ static int hx711_read_raw(struct iio_dev *indio_dev,
if (*val < 0)
return *val;
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = hx711_data->samp_freq;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
mutex_lock(&hx711_data->lock);
@@ -399,20 +459,26 @@ static irqreturn_t hx711_trigger(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct hx711_data *hx711_data = iio_priv(indio_dev);
int i, j = 0;
+ int ret;
mutex_lock(&hx711_data->lock);
memset(&hx711_data->buffer, 0, sizeof(hx711_data->buffer));
iio_for_each_active_channel(indio_dev, i) {
- hx711_data->buffer.channel[j] =
- hx711_reset_read(hx711_data, &indio_dev->channels[i]);
- j++;
+ ret = hx711_reset_read(hx711_data, &indio_dev->channels[i]);
+ if (ret < 0) {
+ dev_err_ratelimited(hx711_data->dev,
+ "read failed: %d\n", ret);
+ goto out_unlock;
+ }
+ hx711_data->buffer.channel[j++] = ret;
}
iio_push_to_buffers_with_timestamp(indio_dev, &hx711_data->buffer,
pf->timestamp);
+out_unlock:
mutex_unlock(&hx711_data->lock);
iio_trigger_notify_done(indio_dev->trig);
@@ -462,6 +528,52 @@ static const struct iio_info hx711_iio_info = {
.attrs = &hx711_attribute_group,
};
+static const int hx710b_samp_freq_avail[] = { 10, 40 };
+
+static int hx710b_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = hx710b_samp_freq_avail;
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(hx710b_samp_freq_avail);
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int hx710b_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct hx711_data *hx711_data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (val != 10 && val != 40)
+ return -EINVAL;
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ mutex_lock(&hx711_data->lock);
+ hx711_data->samp_freq = val;
+ mutex_unlock(&hx711_data->lock);
+ iio_device_release_direct(indio_dev);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info hx710b_iio_info = {
+ .read_raw = hx711_read_raw,
+ .write_raw = hx710b_write_raw,
+ .read_avail = hx710b_read_avail,
+};
+
static const struct iio_chan_spec hx711_chan_spec[] = {
{
.type = IIO_VOLTAGE,
@@ -494,6 +606,51 @@ static const struct iio_chan_spec hx711_chan_spec[] = {
IIO_CHAN_SOFT_TIMESTAMP(2),
};
+/*
+ * HX710B channels (Table 3 in datasheet).
+ * 25 pulses (1 trailing): differential input, 10 SPS
+ * 26 pulses (2 trailing): DVDD-AVDD supply monitor, 40 SPS
+ * 27 pulses (3 trailing): differential input, 40 SPS
+ * Channel 0 exposes both differential rates via IIO_CHAN_INFO_SAMP_FREQ.
+ * Channel 2 is used for the supply monitor to avoid aliasing the
+ * channel2 terminal of the differential pair.
+ */
+static const struct iio_chan_spec hx710b_chan_spec[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .differential = 1,
+ .channel = 0,
+ .channel2 = 1,
+ .indexed = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 24,
+ .storagebits = 32,
+ .endianness = IIO_CPU,
+ },
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .channel = 2,
+ .indexed = 1,
+ .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,
@@ -501,6 +658,15 @@ static const struct hx711_chip_info hx711_chip = {
.num_channels = ARRAY_SIZE(hx711_chan_spec),
};
+static const struct hx711_chip_info hx710b_chip = {
+ .name = "hx710b",
+ .channels = hx710b_chan_spec,
+ .iio_info = &hx710b_iio_info,
+ .num_channels = ARRAY_SIZE(hx710b_chan_spec),
+ .fixed_gain_val = 128,
+ .has_fixed_gain = true,
+};
+
static int hx711_probe(struct platform_device *pdev)
{
const struct hx711_chip_info *chip_info;
@@ -543,32 +709,43 @@ static int hx711_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(hx711_data->gpiod_dout),
"failed to get dout-gpiod\n");
- ret = devm_regulator_get_enable_read_voltage(dev, "avdd");
+ if (chip_info->has_fixed_gain)
+ ret = devm_regulator_get_enable_read_voltage(dev, "vref");
+ else
+ ret = devm_regulator_get_enable_read_voltage(dev, "avdd");
if (ret < 0)
return ret;
/*
- * with
- * full scale differential input range: AVDD / GAIN
+ * With
+ * full scale differential input range: reference / GAIN
* full scale output data: 2^24
* we can say:
- * AVDD / GAIN = 2^24
+ * reference / GAIN = 2^24
* therefore:
- * 1 LSB = AVDD / GAIN / 2^24
- * AVDD is in uV, but we need 10^-9 mV
+ * 1 LSB = reference / GAIN / 2^24
+ * reference is in uV, but we need 10^-9 mV
* approximately to fit into a 32 bit number:
- * 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV]
+ * 1 LSB = (reference * 100) / GAIN / 1678 [10^-9 mV]
*/
/* we need 10^-9 mV */
ret *= 100;
- for (i = 0; i < HX711_GAIN_MAX; i++)
- hx711_data->gain_scale[i] =
- ret / hx711_gain_to_scale[i].gain / 1678;
+ if (chip_info->has_fixed_gain) {
+ for (i = 0; i < HX711_GAIN_MAX; i++)
+ hx711_data->gain_scale[i] =
+ ret / chip_info->fixed_gain_val / 1678;
+ hx711_data->gain_set = chip_info->fixed_gain_val;
+ hx711_data->samp_freq = 10;
+ } else {
+ for (i = 0; i < HX711_GAIN_MAX; i++)
+ hx711_data->gain_scale[i] =
+ 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;
+ }
hx711_data->clock_frequency = 400000;
ret = device_property_read_u32(&pdev->dev, "clock-frequency",
@@ -607,6 +784,7 @@ static int hx711_probe(struct platform_device *pdev)
}
static const struct of_device_id of_hx711_match[] = {
+ { .compatible = "avia,hx710b", .data = &hx710b_chip },
{ .compatible = "avia,hx711", .data = &hx711_chip },
{ }
};
@@ -624,7 +802,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 and similar bitbanging ADC driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:hx711-gpio");
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v11 06/11] iio: adc: hx711: introduce hx711_chip_info structure
2026-06-03 18:48 ` [PATCH v11 06/11] iio: adc: hx711: introduce hx711_chip_info structure Piyush Patle
@ 2026-06-03 19:00 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-06-03 19:00 UTC (permalink / raw)
To: Piyush Patle; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The driver now unconditionally fails to probe if `device_get_match_data()` returns NULL, which breaks legacy platform device instantiation.
- [Low] The patch uses an undefined macro `__counted_by_ptr` in the definition of `struct hx711_chip_info`, causing a syntax error and build failure.
--
commit 9bf695b7a4a3ec692793615e524f77137dfcf73f
Author: Piyush Patle <piyushpatle228@gmail.com>
iio: adc: hx711: introduce hx711_chip_info structure
Add a per-variant static configuration structure and populate the IIO
device fields from it at probe time. This prepares the driver for
supporting more compatible hardware variants.
> No functional change for existing HX711 users.
[Severity: High]
Is this description accurate? For legacy platform devices instantiated by
name, the newly added match data check prevents the driver from probing.
> diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
> index 823fd74f9cf95..062d6860da7d6 100644
> --- a/drivers/iio/adc/hx711.c
> +++ b/drivers/iio/adc/hx711.c
[ ... ]
> @@ -74,6 +76,20 @@ static int hx711_get_scale_to_gain(const int *gain_scale, int scale)
> return -EINVAL;
> }
>
> +/**
> + * struct hx711_chip_info - per-variant static configuration
> + * @name: IIO device name
> + * @channels: channel specification array
> + * @num_channels: number of entries in @channels
> + * @iio_info: IIO info ops for this variant
> + */
> +struct hx711_chip_info {
> + const char *name;
> + const struct iio_chan_spec *channels __counted_by_ptr(num_channels);
[Severity: Low]
Does this compile? The macro __counted_by_ptr is not defined anywhere in
the kernel headers, which causes a syntax error and build failure.
> + unsigned int num_channels;
> + const struct iio_info *iio_info;
> +};
[ ... ]
> @@ -473,6 +498,12 @@ static int hx711_probe(struct platform_device *pdev)
>
> mutex_init(&hx711_data->lock);
>
> + chip_info = device_get_match_data(dev);
> + if (!chip_info)
> + return dev_err_probe(dev, -ENODEV, "missing driver data\n");
[Severity: High]
Will this break legacy platform device instantiation?
For devices instantiated manually via board files matching the driver name
hx711-gpio, device_get_match_data() will return NULL because the driver
does not provide a platform_device_id table.
Prior to this patch, the probe function ran successfully for these devices.
Now it aborts with -ENODEV.
> +
> + hx711_data->chip_info = chip_info;
> +
> /*
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603184859.89693-1-piyushpatle228@gmail.com?part=6
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v11 04/11] dt-bindings: iio: adc: hx711: add HX710B support
2026-06-03 18:48 ` [PATCH v11 04/11] dt-bindings: iio: adc: hx711: add HX710B support Piyush Patle
@ 2026-06-03 19:02 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-06-03 19:02 UTC (permalink / raw)
To: Piyush Patle; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The HX710B driver fails to request and enable the `avdd-supply` and `dvdd-supply` regulators, leaving the chip unpowered.
- [Low] The driver uses a non-existent compiler macro `__counted_by_ptr`, which will cause a build failure.
--
commit 4a57ad17002849c3ffed8137401cf0ed7fd81778
Author: Piyush Patle <piyushpatle228@gmail.com>
iio: adc: hx711: add support for HX710B
This commit adds support for the AVIA HX710B ADC, sharing the GPIO interface
with the HX711 but using trailing pulses for mode selection. It introduces
variant-specific channel configurations and tracks active channels across
conversions. Additionally, it refactors the gain and scale computations to
use fixed values for the new variant.
> diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
> index 5c326f01c5543..e90780dfd34e5 100644
> --- a/drivers/iio/adc/hx711.c
> +++ b/drivers/iio/adc/hx711.c
> @@ -84,12 +86,16 @@ static int hx711_get_scale_to_gain(const int *gain_scale, int scale)
> * @channels: channel specification array
> * @num_channels: number of entries in @channels
> * @iio_info: IIO info ops for this variant
> + * @fixed_gain_val: fixed PGA gain (used when @has_fixed_gain is true)
> + * @has_fixed_gain: true if the variant has a fixed ADC gain
> */
> struct hx711_chip_info {
> const char *name;
> const struct iio_chan_spec *channels __counted_by_ptr(num_channels);
[Severity: Low]
Will this compile? The __counted_by_ptr macro doesn't appear to be defined
anywhere in the kernel, whereas __counted_by is used for flexible array
members. Could this result in a syntax error during the build?
> unsigned int num_channels;
> const struct iio_info *iio_info;
> + unsigned int fixed_gain_val;
> + bool has_fixed_gain;
> };
[ ... ]
> @@ -543,32 +709,43 @@ static int hx711_probe(struct platform_device *pdev)
> return dev_err_probe(dev, PTR_ERR(hx711_data->gpiod_dout),
> "failed to get dout-gpiod\n");
>
> - ret = devm_regulator_get_enable_read_voltage(dev, "avdd");
> + if (chip_info->has_fixed_gain)
> + ret = devm_regulator_get_enable_read_voltage(dev, "vref");
> + else
> + ret = devm_regulator_get_enable_read_voltage(dev, "avdd");
> if (ret < 0)
> return ret;
[Severity: High]
Does this leave the HX710B unpowered? The device tree bindings require
both avdd-supply and dvdd-supply for the avia,hx710b compatible.
However, when has_fixed_gain is true for the HX710B variant, the driver
only requests the vref supply. If avdd and dvdd are controlled by actual
regulators on the board, will they remain disabled and cause the hardware
to fail?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603184859.89693-1-piyushpatle228@gmail.com?part=4
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v11 11/11] iio: adc: hx711: add support for HX710B
2026-06-03 18:48 ` [PATCH v11 11/11] iio: adc: hx711: add support for HX710B Piyush Patle
@ 2026-06-03 19:06 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-06-03 19:06 UTC (permalink / raw)
To: Piyush Patle; +Cc: robh, devicetree, conor+dt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The triggered buffer loop unconditionally performs physical hardware reads for all active channels, including the IIO soft timestamp channel. For the HX711, `hx711_reset_read()` returns `-EINVAL` for the timestamp channel; this patch introduces a new `if (ret < 0)` check that catches this error, prints a failure, and aborts the trigger entirely, completely breaking buffer capture when the timestamp is enabled. For the newly added HX710B, the driver incorrectly interprets the timestamp channel as having `differential = 0`, performing a ~100ms blocking dummy hardware read and then writing the result to `hx711_data->buffer.channel[j++]` at index 2, which violates the `u32 channel[2]` array bounds and risks UBSAN kernel panics.
Pre-existing issues:
- [High] The driver allows `IIO_CHAN_INFO_RAW` sysfs reads to proceed concurrently with triggered buffer captures due to a missing `iio_device_claim_direct()` call, which causes hardware state machine corruption and data loss.
--
commit 4a57ad17002849c3ffed8137401cf0ed7fd81778
Author: Piyush Patle <piyushpatle228@gmail.com>
iio: adc: hx711: add support for HX710B
Add support for the AVIA HX710B ADC, which shares the HX711 GPIO
interface but uses trailing PD_SCK pulses to select the active mode.
Model the HX710B with variant-specific channel tables and IIO info,
track the active channel across conversions, and use the fixed gain
value when computing scale.
> diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
> index 5c326f01c5543..e90780dfd34e5 100644
> --- a/drivers/iio/adc/hx711.c
> +++ b/drivers/iio/adc/hx711.c
[ ... ]
> @@ -322,6 +379,9 @@ static int hx711_read_raw(struct iio_dev *indio_dev,
> if (*val < 0)
> return *val;
> return IIO_VAL_INT;
[Severity: High]
This is a pre-existing issue, but does hx711_read_raw() allow
IIO_CHAN_INFO_RAW sysfs reads to proceed concurrently with triggered
buffer captures?
Since there is no iio_device_claim_direct() call to serialize against
the active IIO buffer, a concurrent sysfs read might acquire the lock
between trigger samples.
Because the hardware relies on the trailing pulses of the previous read
to set the channel and gain for the next conversion, could an interleaved
sysfs read clock out data intended for the buffer and reset the hardware,
corrupting the data stream for userspace?
> + case IIO_CHAN_INFO_SAMP_FREQ:
> + *val = hx711_data->samp_freq;
> + return IIO_VAL_INT;
> case IIO_CHAN_INFO_SCALE:
> *val = 0;
> mutex_lock(&hx711_data->lock);
[ ... ]
> @@ -399,20 +459,26 @@ static irqreturn_t hx711_trigger(int irq, void *p)
> struct iio_dev *indio_dev = pf->indio_dev;
> struct hx711_data *hx711_data = iio_priv(indio_dev);
> int i, j = 0;
> + int ret;
>
> mutex_lock(&hx711_data->lock);
>
> memset(&hx711_data->buffer, 0, sizeof(hx711_data->buffer));
>
> iio_for_each_active_channel(indio_dev, i) {
> - hx711_data->buffer.channel[j] =
> - hx711_reset_read(hx711_data, &indio_dev->channels[i]);
> - j++;
> + ret = hx711_reset_read(hx711_data, &indio_dev->channels[i]);
> + if (ret < 0) {
> + dev_err_ratelimited(hx711_data->dev,
> + "read failed: %d\n", ret);
> + goto out_unlock;
> + }
> + hx711_data->buffer.channel[j++] = ret;
[Severity: High]
Does this new error check accidentally cause a regression by aborting the
trigger entirely when the IIO soft timestamp channel is enabled?
iio_for_each_active_channel() iterates over the active_scan_mask, which
includes the timestamp channel.
For the HX711, it appears hx711_reset_read() will return -EINVAL for the
timestamp channel. Would this new check catch that and completely abort
the capture without pushing data?
Furthermore, for the newly added HX710B, hx710b_trailing_pulses() seems
to evaluate !chan->differential as true for the timestamp channel. Would
this result in a hardware read that writes to hx711_data->buffer.channel[2],
overflowing the bounds of the u32 channel[2] array?
> }
>
> iio_push_to_buffers_with_timestamp(indio_dev, &hx711_data->buffer,
> pf->timestamp);
>
> +out_unlock:
> mutex_unlock(&hx711_data->lock);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260603184859.89693-1-piyushpatle228@gmail.com?part=11
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-06-03 19:06 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-03 18:48 [PATCH v11 00/11] iio: adc: Add support for AVIA HX710B ADC Piyush Patle
2026-06-03 18:48 ` [PATCH v11 01/11] dt-bindings: iio: adc: hx711: clean up existing binding text Piyush Patle
2026-06-03 18:48 ` [PATCH v11 02/11] dt-bindings: iio: adc: hx711: add VSUP and DVDD supply properties Piyush Patle
2026-06-03 18:48 ` [PATCH v11 03/11] dt-bindings: iio: adc: hx711: add RATE GPIO property Piyush Patle
2026-06-03 18:48 ` [PATCH v11 04/11] dt-bindings: iio: adc: hx711: add HX710B support Piyush Patle
2026-06-03 19:02 ` sashiko-bot
2026-06-03 18:48 ` [PATCH v11 05/11] iio: adc: hx711: move scale computation to per-device storage Piyush Patle
2026-06-03 18:48 ` [PATCH v11 06/11] iio: adc: hx711: introduce hx711_chip_info structure Piyush Patle
2026-06-03 19:00 ` sashiko-bot
2026-06-03 18:48 ` [PATCH v11 07/11] iio: adc: hx711: pass trailing pulse count into hx711_read Piyush Patle
2026-06-03 18:48 ` [PATCH v11 08/11] iio: adc: hx711: split variable assignments in hx711_read and hx711_reset Piyush Patle
2026-06-03 18:48 ` [PATCH v11 09/11] iio: adc: hx711: localize loop iterators in hx711_read Piyush Patle
2026-06-03 18:48 ` [PATCH v11 10/11] iio: adc: hx711: pass iio_chan_spec to hx711_reset_read Piyush Patle
2026-06-03 18:48 ` [PATCH v11 11/11] iio: adc: hx711: add support for HX710B Piyush Patle
2026-06-03 19:06 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox