Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Oleksij Rempel and committed by
Jonathan Cameron
8d68801a 1fa14dd1

+12 -2
+12 -2
drivers/iio/dac/ds4424.c
··· 22 22 #define DS4424_MAX_DAC_CHANNELS 4 23 23 24 24 #define DS4424_DAC_MASK GENMASK(6, 0) 25 + #define DS4404_DAC_MASK GENMASK(4, 0) 25 26 #define DS4424_DAC_SOURCE BIT(7) 26 27 27 28 #define DS4424_DAC_ADDR(chan) ((chan) + 0xf8) ··· 37 36 38 37 struct ds4424_chip_info { 39 38 const char *name; 39 + u8 result_mask; 40 40 u8 num_channels; 41 41 }; 42 42 43 43 static const struct ds4424_chip_info ds4402_info = { 44 44 .name = "ds4402", 45 + .result_mask = DS4404_DAC_MASK, 45 46 .num_channels = DS4422_MAX_DAC_CHANNELS, 46 47 }; 47 48 48 49 static const struct ds4424_chip_info ds4404_info = { 49 50 .name = "ds4404", 51 + .result_mask = DS4404_DAC_MASK, 50 52 .num_channels = DS4424_MAX_DAC_CHANNELS, 51 53 }; 52 54 53 55 static const struct ds4424_chip_info ds4422_info = { 54 56 .name = "ds4422", 57 + .result_mask = DS4424_DAC_MASK, 55 58 .num_channels = DS4422_MAX_DAC_CHANNELS, 56 59 }; 57 60 58 61 static const struct ds4424_chip_info ds4424_info = { 59 62 .name = "ds4424", 63 + .result_mask = DS4424_DAC_MASK, 60 64 .num_channels = DS4424_MAX_DAC_CHANNELS, 61 65 }; 62 66 ··· 71 65 uint8_t save[DS4424_MAX_DAC_CHANNELS]; 72 66 struct regulator *vcc_reg; 73 67 uint8_t raw[DS4424_MAX_DAC_CHANNELS]; 68 + const struct ds4424_chip_info *chip_info; 74 69 }; 75 70 76 71 static const struct iio_chan_spec ds4424_channels[] = { ··· 122 115 struct iio_chan_spec const *chan, 123 116 int *val, int *val2, long mask) 124 117 { 118 + struct ds4424_data *data = iio_priv(indio_dev); 125 119 int ret, regval; 126 120 127 121 switch (mask) { ··· 135 127 return ret; 136 128 } 137 129 138 - *val = regval & DS4424_DAC_MASK; 130 + *val = regval & data->chip_info->result_mask; 139 131 if (!(regval & DS4424_DAC_SOURCE)) 140 132 *val = -*val; 141 133 ··· 150 142 struct iio_chan_spec const *chan, 151 143 int val, int val2, long mask) 152 144 { 145 + struct ds4424_data *data = iio_priv(indio_dev); 153 146 unsigned int abs_val; 154 147 155 148 if (val2 != 0) ··· 159 150 switch (mask) { 160 151 case IIO_CHAN_INFO_RAW: 161 152 abs_val = abs(val); 162 - if (abs_val > DS4424_DAC_MASK) 153 + if (abs_val > data->chip_info->result_mask) 163 154 return -EINVAL; 164 155 165 156 /* ··· 250 241 i2c_set_clientdata(client, indio_dev); 251 242 data->client = client; 252 243 indio_dev->name = chip_info->name; 244 + data->chip_info = chip_info; 253 245 254 246 data->vcc_reg = devm_regulator_get(&client->dev, "vcc"); 255 247 if (IS_ERR(data->vcc_reg))