[PATCH 3/9] w1: ds2482: set the strong pull-up with its byte
From: Greg Kroah-Hartman
Date: Tue Oct 27 2026 - 12:06:02 EST
From: Josef Bacik <josef@xxxxxxxxxxxxxx>
The eight channels of a DS2482-800 are eight independent 1-wire masters
for the w1 core, but share one I2C device. Each bus operation consists of
several I2C transfers: select the channel, send the command, poll the
status, set the read pointer, read the result. access_lock keeps the
operations of the channels apart.
ds2482_w1_set_pullup() polls the status, writes the configuration and
polls again without the lock. Polling sets the read pointer of the device
to the status register. In the middle of a read on another channel, after
that one has set the pointer to the data register, this makes the read
return the status instead of the data. The cached copy of the pointer in
pdev->read_prt can go wrong as well.
The lock alone is not enough. The strong pull-up is a setting of the
whole chip which is used up by the next byte. If an operation of another
channel gets in before the byte it was meant for, that channel gets the
pull-up, and the sensor converts without power.
So only note the request in ds2482_w1_set_pullup(), and write the
configuration in ds2482_w1_write_byte(), under the lock and after the
channel has been selected. The w1 core calls the former right before the
latter, under the bus mutex of the channel.
Fixes: 9c95bb6f25ff ("w1: ds2482: Added 1-Wire pull-up support to the driver")
Cc: stable <stable@xxxxxxxxxx>
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/w1/masters/ds2482.c | 36 +++++++++++++++++++++---------------
1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index cbd11bc61274..5498bb04f7ce 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -103,6 +103,7 @@ struct ds2482_data;
struct ds2482_w1_chan {
struct ds2482_data *pdev;
u8 channel;
+ bool spu; /* strong pullup after the next byte */
struct w1_bus_master w1_bm;
};
@@ -336,6 +337,19 @@ static void ds2482_w1_write_byte(void *data, u8 byte)
if (pdev->w1_count > 1)
ds2482_set_channel(pdev, pchan->channel);
+ if (pchan->spu) {
+ pchan->spu = false;
+ /* the wait above and this one are crucial, otherwise devices
+ * might not be powered long enough, causing e.g. a w1_therm
+ * sensor to provide wrong conversion results
+ */
+ /* note: it seems like both SPU and APU have to be set! */
+ ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
+ ds2482_calculate_config(DS2482_REG_CFG_SPU |
+ DS2482_REG_CFG_APU));
+ ds2482_wait_1wire_idle(pdev);
+ }
+
/* Send the write byte command */
ds2482_send_cmd_data(pdev, DS2482_CMD_1WIRE_WRITE_BYTE, byte);
@@ -420,27 +434,19 @@ static u8 ds2482_w1_reset_bus(void *data)
static u8 ds2482_w1_set_pullup(void *data, int delay)
{
struct ds2482_w1_chan *pchan = data;
- struct ds2482_data *pdev = pchan->pdev;
- u8 retval = 1;
/* if delay is non-zero activate the pullup,
* the strong pullup will be automatically deactivated
* by the master, so do not explicitly deactive it
+ *
+ * The setting is used up by the next byte on any channel of the chip:
+ * ds2482_w1_write_byte() makes it, in one go with the byte.
*/
- if (delay) {
- /* both waits are crucial, otherwise devices might not be
- * powered long enough, causing e.g. a w1_therm sensor to
- * provide wrong conversion results
- */
- ds2482_wait_1wire_idle(pdev);
- /* note: it seems like both SPU and APU have to be set! */
- retval = ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG,
- ds2482_calculate_config(DS2482_REG_CFG_SPU |
- DS2482_REG_CFG_APU));
- ds2482_wait_1wire_idle(pdev);
- }
+ if (!delay)
+ return 1;
- return retval;
+ pchan->spu = true;
+ return 0;
}
--
2.56.0