Tue, Oct 29, 2024 at 04:02:46PM +0100, Julien Stephan kirjoitti: > The alert functionality is an out of range indicator and can be used as an > early indicator of an out of bounds conversion result. > > ALERT_LOW_THRESHOLD and ALERT_HIGH_THRESHOLD registers are common to all > channels. > > When using 1 SDO line (only mode supported by the driver right now), i.e > data outputs only on SDOA, SDOB (or SDOD for 4 channels variants) is > used as an alert pin. The alert pin is updated at the end of the > conversion (set to low if an alert occurs) and is cleared on a falling > edge of CS. > > The ALERT register contains information about the exact alert status: > channel and direction. Unfortunately we can't read this register because > in buffered read we cannot claim for direct mode. > > User can set high/low thresholds and enable event detection using the > regular iio events: > > events/in_thresh_falling_value > events/in_thresh_rising_value > events/thresh_either_en > > Because we cannot read ALERT register, we can't determine the exact > channel that triggers the alert, neither the direction (hight/low > threshold violation), so we send and IIO_EV_DIR_EITHER event for all > channels. This is ok, because the primary use case for this chip is to > hardwire the alert line to shutdown the device. > > When reading a channel raw data, we have to trigger 2 spi transactions: a > first transaction that will trigger a conversion and a second > transaction to read the conversion. By design a new conversion is > initiated on each falling edge of CS. This will trigger a second > interrupt. To avoid that we disable irq in the hard irq handler and > re-enable them in thread handler. ... > #include <linux/iio/buffer.h> > #include <linux/iio/iio.h> > +#include <linux/iio/events.h> Perhaps keep it ordered? > #include <linux/iio/trigger_consumer.h> > #include <linux/iio/triggered_buffer.h> ... > + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { > + struct ad7380_state *st = iio_priv(indio_dev); > + int ret; > + > + if (state == st->alert_en) > + return 0; > + > + /* > + * According to the datasheet, high threshold must always be > + * greater than low threshold Missed period at the end. > + */ > + if (state && st->high_th < st->low_th) > + return -EINVAL; > + > + ret = regmap_update_bits(st->regmap, > + AD7380_REG_ADDR_CONFIG1, > + AD7380_CONFIG1_ALERTEN, > + FIELD_PREP(AD7380_CONFIG1_ALERTEN, state)); > + > + if (ret) > + return ret; > + > + st->alert_en = state; > + > + return 0; > + } > + unreachable(); > +} ... > +static int ad7380_write_event_value(struct iio_dev *indio_dev, > + const struct iio_chan_spec *chan, > + enum iio_event_type type, > + enum iio_event_direction dir, > + enum iio_event_info info, > + int val, int val2) > +{ > + iio_device_claim_direct_scoped(return -EBUSY, indio_dev) { > + struct ad7380_state *st = iio_priv(indio_dev); > + int ret; > + > + /* > + * According to the datasheet, > + * AD7380_REG_ADDR_ALERT_HIGH_TH[11:0] are the MSB of the 16-bit > + * internal alert high register. LSB are set to 0x0. > + * AD7380_REG_ADDR_ALERT_LOW_TH[11:0] are the MSB of the 16 bit > + * internal alert low register. LSB are set to 0xf. > + * > + * When alert is enabled the conversion from the adc is compared > + * immediately to the alert high/low thresholds, before any > + * oversampling. This means that the thresholds are the same for > + * normal mode and oversampling mode. > + * For 12 and 14 bits, the thresholds are still on 16 bits. > + */ > + if (val < 0 || val > 2047) What about having val >= BIT(11) here? > + return -EINVAL; > + > + switch (dir) { > + case IIO_EV_DIR_RISING: > + ret = regmap_write(st->regmap, > + AD7380_REG_ADDR_ALERT_HIGH_TH, > + val); > + if (!ret) > + st->high_th = val << 4 | 0xf; GENMASK() ? Predefined constant? > + return ret; if (ret) return ret; ... return 0; (yes, more verbose, but better for reading and maintenance) > + case IIO_EV_DIR_FALLING: > + ret = regmap_write(st->regmap, > + AD7380_REG_ADDR_ALERT_LOW_TH, > + val); > + if (!ret) > + st->low_th = val << 4; > + return ret; > + default: > + return -EINVAL; > + } > + } > + unreachable(); > +} ... > + st->high_th = 0x7ff; > + st->low_th = 0x800; I would go with BIT(11) - 1 and BIT(11) as it seems related to the amount of bits in the hardware. ... > +static irqreturn_t ad7380_event_handler(int irq, void *private) > +{ > + struct iio_dev *indio_dev = private; > + s64 timestamp = iio_get_time_ns(indio_dev); > + struct ad7380_state *st = iio_priv(indio_dev); > + const struct iio_chan_spec *chan = &indio_dev->channels[0]; > + int i = 0, j = 0; Why signed? And for 'i' the assignment is redundant. > + > + for (i = 0; i < st->chip_info->num_channels - 1; i++) { > + iio_push_event(indio_dev, > + chan->differential ? > + IIO_DIFF_EVENT_CODE(IIO_VOLTAGE, > + j, > + j + 1, > + IIO_EV_TYPE_THRESH, > + IIO_EV_DIR_EITHER) : > + IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, > + i, > + IIO_EV_TYPE_THRESH, > + IIO_EV_DIR_EITHER), > + timestamp); > + j += 2; > + } > + > + enable_irq(irq); > + > + return IRQ_HANDLED; > +} -- With Best Regards, Andy Shevchenko