From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 B09B242DFF4; Tue, 5 May 2026 12:35:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777984509; cv=none; b=agXKe9SDfXzD8xBOk8RBOaF4sK+kPVDcd+J1hHX/or+ao9ssWwRsyBcXzG0lveV0wxHA9L6D9pZURhoX5JUiVavM90XCJQ36sR+Kzvl1wGppckzkpDZG6lH51IjM3XE96eX2uW09Qex5RwmcdqVritb+WtK47km9imhxP2R0FuM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777984509; c=relaxed/simple; bh=u0xwIMbyvkg/mtecXeNFHRPMN4pzjZZQWY09VE6SMH0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=FgJIPxzOOT9qXN3VRWKmxgUMdjif4pfoMcX4dkMnefrUngf6qo3xnGlAHMpYA3ucgpthyBQl7uWjS3lR/iqOxxWjmj2KM9r5is/0uL54uikLNBB5cmeEeuHc7Q35JMiQevSXsQ+oPWLQGYO/vgZvq3Sw6J6YM6UoRLreH7VOvJY= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=sBoHns0y; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="sBoHns0y" Received: by smtp.kernel.org (Postfix) with ESMTPS id 8DB15C2BCF7; Tue, 5 May 2026 12:35:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777984509; bh=u0xwIMbyvkg/mtecXeNFHRPMN4pzjZZQWY09VE6SMH0=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=sBoHns0yWhnt2vuATW+3uwLnQn1eyn0gjj8oHJgshxqzC+WVU4l8MNpnHksj610+8 KWVgTQ82uXN7Z4HuRkXKe+3WBrAL+ZlpkBHExBi0HYSS6GG5zpDo1vppnyAaTU4KB1 elw0v7J1gjhfFvAojaRRLz8BlxY43U2fCDyqHUWFcq34/BBqEESWvCtZOQ6FcbUb4t L5Lf3SNuExwrJKJooqq/rb2A3vSa2o2HCAcoNVpZ0X3YYRcsZHVSSy1fAaf3ILhdrT OUyTZtOImbIJIvxN/8Px1dBXNSxC4gK5hxm9hMZ5YHErC5y+yAsEyOmFc3oAyqqdHn kfL/dWsK+MkTA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 85707CD3436; Tue, 5 May 2026 12:35:09 +0000 (UTC) From: Rodrigo Alencar via B4 Relay Date: Tue, 05 May 2026 13:35:05 +0100 Subject: [PATCH v6 04/12] iio: dac: ad5686: fix powerdown control on dual-channel devices Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260505-ad5686-fixes-v6-4-c2d5f7be32be@analog.com> References: <20260505-ad5686-fixes-v6-0-c2d5f7be32be@analog.com> In-Reply-To: <20260505-ad5686-fixes-v6-0-c2d5f7be32be@analog.com> To: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Stefan Popa , Jonathan Cameron , Greg Kroah-Hartman , Michael Auchter , Jonathan Cameron Cc: Lars-Peter Clausen , Michael Hennerich , Jonathan Cameron , David Lechner , Andy Shevchenko , Rodrigo Alencar X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1777984508; l=4744; i=rodrigo.alencar@analog.com; s=default; h=from:subject:message-id; bh=q9RsXynw1DeLjVzb9XXMh+mg3Wiw/FLZusoLxzx209U=; b=1qJuNiEFKUA5AHVblIk1ERbcLkRCazFDIw+lt6WISmatZWH2TyprIDcA51Ta6dI8/xMGlT3Zk ySRY8KAaTEfBsMmuXRmRBfL4gqX+CmdXhgAJ+00iFqGLOp0ybZuVLKO X-Developer-Key: i=rodrigo.alencar@analog.com; a=ed25519; pk=ULeHbgU/OYh/PG/4anHDfLgldFItQHAhOktYRVLMFRo= X-Endpoint-Received: by B4 Relay for rodrigo.alencar@analog.com/default with auth_id=561 X-Original-From: Rodrigo Alencar Reply-To: rodrigo.alencar@analog.com From: Rodrigo Alencar 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 --- drivers/iio/dac/ad5686.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 9eb6b61c471d..19440b17645b 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -25,26 +25,37 @@ static const char * const ad5686_powerdown_modes[] = { "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_powerdown_mode_enum = { 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_powerdown(struct iio_dev *indio_dev, 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; -- 2.43.0