From: Oleksij Rempel Date: Tue, 10 Feb 2026 13:51:07 +0000 (+0100) Subject: iio: dac: ds4424: support per-variant output range limits X-Git-Tag: v7.1-rc1~17^2~120^2~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8d68801a696ce101349db6896c10afb5f8d1c228;p=thirdparty%2Fkernel%2Fstable.git iio: dac: ds4424: support per-variant output range limits The DS4402/DS4404 variants operate with a 5-bit resolution (31 steps), whereas the DS4422/DS4424 support 7-bit (127 steps). Previously, the driver enforced a hardcoded 7-bit mask (DS4424_DAC_MASK) for all variants. This allowed users to write values exceeding the 5-bit range to DS4402/DS4404 devices, resulting in silent truncation or undefined behavior. Add a `result_mask` field to the chip_info structure to define the valid data range for each variant. Use this mask to: 1. Correctly mask register values in read_raw(). 2. Return -EINVAL in write_raw() if the input value exceeds the variant's capabilities. Signed-off-by: Oleksij Rempel Reviewed-by: Andy Shevchenko Signed-off-by: Jonathan Cameron --- diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c index f88e92927bf2a..4eff052c2b619 100644 --- a/drivers/iio/dac/ds4424.c +++ b/drivers/iio/dac/ds4424.c @@ -22,6 +22,7 @@ #define DS4424_MAX_DAC_CHANNELS 4 #define DS4424_DAC_MASK GENMASK(6, 0) +#define DS4404_DAC_MASK GENMASK(4, 0) #define DS4424_DAC_SOURCE BIT(7) #define DS4424_DAC_ADDR(chan) ((chan) + 0xf8) @@ -36,26 +37,31 @@ struct ds4424_chip_info { const char *name; + u8 result_mask; u8 num_channels; }; static const struct ds4424_chip_info ds4402_info = { .name = "ds4402", + .result_mask = DS4404_DAC_MASK, .num_channels = DS4422_MAX_DAC_CHANNELS, }; static const struct ds4424_chip_info ds4404_info = { .name = "ds4404", + .result_mask = DS4404_DAC_MASK, .num_channels = DS4424_MAX_DAC_CHANNELS, }; static const struct ds4424_chip_info ds4422_info = { .name = "ds4422", + .result_mask = DS4424_DAC_MASK, .num_channels = DS4422_MAX_DAC_CHANNELS, }; static const struct ds4424_chip_info ds4424_info = { .name = "ds4424", + .result_mask = DS4424_DAC_MASK, .num_channels = DS4424_MAX_DAC_CHANNELS, }; @@ -65,6 +71,7 @@ struct ds4424_data { uint8_t save[DS4424_MAX_DAC_CHANNELS]; struct regulator *vcc_reg; uint8_t raw[DS4424_MAX_DAC_CHANNELS]; + const struct ds4424_chip_info *chip_info; }; static const struct iio_chan_spec ds4424_channels[] = { @@ -115,6 +122,7 @@ static int ds4424_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { + struct ds4424_data *data = iio_priv(indio_dev); int ret, regval; switch (mask) { @@ -127,7 +135,7 @@ static int ds4424_read_raw(struct iio_dev *indio_dev, return ret; } - *val = regval & DS4424_DAC_MASK; + *val = regval & data->chip_info->result_mask; if (!(regval & DS4424_DAC_SOURCE)) *val = -*val; @@ -142,6 +150,7 @@ static int ds4424_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { + struct ds4424_data *data = iio_priv(indio_dev); unsigned int abs_val; if (val2 != 0) @@ -150,7 +159,7 @@ static int ds4424_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: abs_val = abs(val); - if (abs_val > DS4424_DAC_MASK) + if (abs_val > data->chip_info->result_mask) return -EINVAL; /* @@ -241,6 +250,7 @@ static int ds4424_probe(struct i2c_client *client) i2c_set_clientdata(client, indio_dev); data->client = client; indio_dev->name = chip_info->name; + data->chip_info = chip_info; data->vcc_reg = devm_regulator_get(&client->dev, "vcc"); if (IS_ERR(data->vcc_reg))