diff options
| author | Oleksij Rempel <o.rempel@pengutronix.de> | 2026-02-10 16:51:07 +0300 |
|---|---|---|
| committer | Jonathan Cameron <Jonathan.Cameron@huawei.com> | 2026-03-22 15:43:48 +0300 |
| commit | 8d68801a696ce101349db6896c10afb5f8d1c228 (patch) | |
| tree | a01b9c580d605d78d329a3da68e3a1a8c249240a | |
| parent | 1fa14dd130fae3feccdde112ed26f48042cf5d7b (diff) | |
| download | linux-8d68801a696ce101349db6896c10afb5f8d1c228.tar.xz | |
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 <o.rempel@pengutronix.de>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
| -rw-r--r-- | drivers/iio/dac/ds4424.c | 14 |
1 files changed, 12 insertions, 2 deletions
diff --git a/drivers/iio/dac/ds4424.c b/drivers/iio/dac/ds4424.c index f88e92927bf2..4eff052c2b61 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)) |
