From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 889E93112A5; Sun, 7 Jun 2026 10:33:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780828436; cv=none; b=F+7JsMO3eLzMRFgFuAvx/x0SQcGVrhIxMfp+6W7PmAlRP7tzj4ZRnSIdVZmzVSMZ+VHm3XTAtbIWSY5Kn3Z/98vuIzriqSl5nkcqHVGzG6BuOvSgD0mL1xk2DiwZ/vlS7/UOpsPz9VCQsaJ6v5WvB7oD70Tm9MndltwB4Ms6fqo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780828436; c=relaxed/simple; bh=9OwcrnzmB7LwGl/UiFf6b1181BtUbbUiOoB07gkbwHo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=htZfgjVeK6qAsFKBGo41wENdRee5RK985HditmBnvHx8TfA7LVZbaxLszE5iumXVJq4cmJUz3HknB8d+2A9/y88zxSm2wZ+tHOXwsLuXcewBwCbRPrNiEQZezB64TYYPHvZ2vPcDKarCo/fo7v/RmLlcF75sey19z6h8upvpR/Q= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=t6lRSrxf; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="t6lRSrxf" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A21471F00893; Sun, 7 Jun 2026 10:33:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1780828434; bh=323a3HNq+EriP2YYgvGM01LMTnmsPwU+jqRW3VEkiv8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=t6lRSrxfBLBaLnWOR6q7hE7z64Aslroprts2Qt7pfaUyAudZybqWSZZ+5123g/KvI VDIIl/XDBd2VIoJzPR2guf852x9SqXcvyVMo5Vm83ve9/s1Bzmrdzpk625eCxijzxH dVEclS9v6XvwMOS8K9iuKpUPB3xrKJrQshG2Zbq4= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Rodrigo Alencar , Stable@vger.kernel.org, Jonathan Cameron Subject: [PATCH 7.0 181/332] iio: dac: ad5686: fix powerdown control on dual-channel devices Date: Sun, 7 Jun 2026 11:59:10 +0200 Message-ID: <20260607095734.712752427@linuxfoundation.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260607095728.031258202@linuxfoundation.org> References: <20260607095728.031258202@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 7.0-stable review patch. If anyone has any objections, please let me know. ------------------ From: Rodrigo Alencar commit 8aeaf25a85263a7a43357e16ad78ab969f6f8aeb upstream. Fix powerdown control by using a proper bit shift for the powerdown mask values. During initialization, powerdown bits are initialized so that unused bits are set to 1 and the correct bit shift is used. Dual-channel devices use one-hot encoding in the address and that reflects on the position of the powerdown bits, which are not channel-index based for that case. Quad-channel devices also use one-hot encoding for the channel address but the result of log2(address) coincides with the channel index value. Mask as 0x3U is used rather than 0x3, because shift can reach value of 30 (last channel of a 16-channel device), which would mess with the sign bit. The issue was introduced when first adding support for dual-channel devices, which overlooked powerdown control differences. Fixes: 7dc8faeab3e3 ("iio: dac: ad5686: add support for AD5338R") Signed-off-by: Rodrigo Alencar Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/dac/ad5686.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -25,26 +25,37 @@ static const char * const ad5686_powerdo "three_state" }; +static inline unsigned int ad5686_pd_mask_shift(const struct iio_chan_spec *chan) +{ + if (chan->channel == chan->address) + return chan->channel * 2; + + /* one-hot encoding is used in dual/quad channel devices */ + return __ffs(chan->address) * 2; +} + static int ad5686_get_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { + unsigned int shift = ad5686_pd_mask_shift(chan); struct ad5686_state *st = iio_priv(indio_dev); guard(mutex)(&st->lock); - return ((st->pwr_down_mode >> (chan->channel * 2)) & 0x3) - 1; + return ((st->pwr_down_mode >> shift) & 0x3U) - 1; } static int ad5686_set_powerdown_mode(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, unsigned int mode) { + unsigned int shift = ad5686_pd_mask_shift(chan); struct ad5686_state *st = iio_priv(indio_dev); guard(mutex)(&st->lock); - st->pwr_down_mode &= ~(0x3 << (chan->channel * 2)); - st->pwr_down_mode |= ((mode + 1) << (chan->channel * 2)); + st->pwr_down_mode &= ~(0x3U << shift); + st->pwr_down_mode |= (mode + 1) << shift; return 0; } @@ -59,12 +70,12 @@ static const struct iio_enum ad5686_powe static ssize_t ad5686_read_dac_powerdown(struct iio_dev *indio_dev, uintptr_t private, const struct iio_chan_spec *chan, char *buf) { + unsigned int shift = ad5686_pd_mask_shift(chan); struct ad5686_state *st = iio_priv(indio_dev); guard(mutex)(&st->lock); - return sysfs_emit(buf, "%d\n", !!(st->pwr_down_mask & - (0x3 << (chan->channel * 2)))); + return sysfs_emit(buf, "%d\n", !!(st->pwr_down_mask & (0x3U << shift))); } static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, @@ -86,9 +97,9 @@ static ssize_t ad5686_write_dac_powerdow guard(mutex)(&st->lock); if (readin) - st->pwr_down_mask |= (0x3 << (chan->channel * 2)); + st->pwr_down_mask |= 0x3U << ad5686_pd_mask_shift(chan); else - st->pwr_down_mask &= ~(0x3 << (chan->channel * 2)); + st->pwr_down_mask &= ~(0x3U << ad5686_pd_mask_shift(chan)); switch (st->chip_info->regmap_type) { case AD5310_REGMAP: @@ -468,7 +479,7 @@ int ad5686_probe(struct device *dev, { struct ad5686_state *st; struct iio_dev *indio_dev; - unsigned int val, ref_bit_msk; + unsigned int val, ref_bit_msk, shift; bool has_external_vref; u8 cmd; int ret, i; @@ -492,9 +503,18 @@ int ad5686_probe(struct device *dev, has_external_vref = ret != -ENODEV; st->vref_mv = has_external_vref ? ret / 1000 : st->chip_info->int_vref_mv; + /* Initialize masks to all ones provided the max shift (last channel) */ + shift = ad5686_pd_mask_shift(&st->chip_info->channels[st->chip_info->num_channels - 1]); + st->pwr_down_mask = GENMASK(shift + 1, 0); + st->pwr_down_mode = GENMASK(shift + 1, 0); + /* Set all the power down mode for all channels to 1K pulldown */ - for (i = 0; i < st->chip_info->num_channels; i++) - st->pwr_down_mode |= (0x01 << (i * 2)); + for (i = 0; i < st->chip_info->num_channels; i++) { + shift = ad5686_pd_mask_shift(&st->chip_info->channels[i]); + st->pwr_down_mask &= ~(0x3U << shift); /* powered up state */ + st->pwr_down_mode &= ~(0x3U << shift); + st->pwr_down_mode |= 0x01U << shift; + } indio_dev->name = name; indio_dev->info = &ad5686_info;