aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/iio/adc/ti-ads7128.c59
1 files changed, 48 insertions, 11 deletions
diff --git a/drivers/iio/adc/ti-ads7128.c b/drivers/iio/adc/ti-ads7128.c
index 743b2b3c4e0b..8db2a608c566 100644
--- a/drivers/iio/adc/ti-ads7128.c
+++ b/drivers/iio/adc/ti-ads7128.c
@@ -49,6 +49,9 @@ struct ti_ads7128_chip_info {
struct regmap *regmap;
struct regulator *regulator;
struct mutex state_lock;
+ int min_raw[8];
+ int max_raw[8];
+ u8 min_max_valid;
};
static const struct regmap_config ti_ads7128_regmap_config = {
@@ -59,34 +62,68 @@ static const struct regmap_config ti_ads7128_regmap_config = {
static int ti_ads7128_read_min_max(struct ti_ads7128_chip_info *chip,
unsigned int channel_val, int *min_val, int *max_val)
{
- unsigned int regval;
+ unsigned int regval, i;
u8 stats_en = BIT(5);
- u8 buf[2] = {};
+ u8 min_buf[2 * 8];
+ u8 max_buf[2 * 8];
int ret;
+ /*
+ * The datasheet claims that just reading the MIN/MAX registers will
+ * reset their values, but that did not happen in practice. This is
+ * either a hardware bug or a mistake in the datasheet mistake.
+ *
+ * So instead we read all MIN/MAX registers and reset all MIN/MAX
+ * registers by setting STATS_EN in GENERAL_CFG, while keeping track
+ * of the 'last read' status ourselves. It's more overhead (since
+ * MIN/MAX is read for all channels instead of just one), but this is
+ * not something that is normally done very frequently.
+ */
+
/* disable recording statistics */
regval = TI_ADS7128_CLR_BIT_MASK | TI_ADS7128_GENERAL_CFG;
ret = regmap_write(chip->regmap, regval, stats_en);
if (ret < 0)
return ret;
- /* read minimum voltage value */
- regval = TI_ADS7128_MULTI_REG_RD_MASK | TI_ADS7128_MIN_LSB(channel_val);
- ret = regmap_bulk_read(chip->regmap, regval, buf, sizeof(buf));
+ /* read minimum voltage values */
+ regval = TI_ADS7128_MULTI_REG_RD_MASK | TI_ADS7128_MIN_LSB(0);
+ ret = regmap_bulk_read(chip->regmap, regval, min_buf, sizeof(min_buf));
if (ret < 0)
return ret;
- *min_val = (buf[1] << 4) | (buf[0] >> 4);
- /* read maximum voltage value */
- regval = TI_ADS7128_MULTI_REG_RD_MASK | TI_ADS7128_MAX_LSB(channel_val);
- ret = regmap_bulk_read(chip->regmap, regval, buf, sizeof(buf));
+ /* read maximum voltage values */
+ regval = TI_ADS7128_MULTI_REG_RD_MASK | TI_ADS7128_MAX_LSB(0);
+ ret = regmap_bulk_read(chip->regmap, regval, max_buf, sizeof(max_buf));
if (ret < 0)
return ret;
- *max_val = (buf[1] << 4) | (buf[0] >> 4);
/* reset and re-enable recording statistics */
regval = TI_ADS7128_SET_BIT_MASK | TI_ADS7128_GENERAL_CFG;
- return regmap_write(chip->regmap, regval, stats_en);
+ ret = regmap_write(chip->regmap, regval, stats_en);
+
+ /* Update the min/max_raw values */
+ for (i = 0; i < 8; i++) {
+ int min_raw = (min_buf[i * 2 + 1] << 4) | (min_buf[i * 2] >> 4);
+ int max_raw = (max_buf[i * 2 + 1] << 4) | (max_buf[i * 2] >> 4);
+
+ if (chip->min_max_valid & BIT(i)) {
+ if (chip->min_raw[i] < min_raw)
+ min_raw = chip->min_raw[i];
+ if (chip->max_raw[i] > max_raw)
+ max_raw = chip->max_raw[i];
+ } else {
+ chip->min_max_valid |= BIT(i);
+ }
+ chip->min_raw[i] = min_raw;
+ chip->max_raw[i] = max_raw;
+ }
+
+ *min_val = chip->min_raw[channel_val];
+ *max_val = chip->max_raw[channel_val];
+ /* Start new min/max scanning for this channel */
+ chip->min_max_valid &= ~BIT(channel_val);
+ return ret;
}
static int ti_ads7128_read_raw_multi(struct iio_dev *indio_dev,

Privacy Policy