On 26/06/05 03:09PM, Jonathan Cameron wrote: > On Fri, 5 Jun 2026 12:34:31 +0100 > Rodrigo Alencar <[email protected]> wrote: > > > On 26/06/03 01:41PM, Jonathan Cameron wrote: > > > On Tue, 02 Jun 2026 17:33:57 +0100 > > > Rodrigo Alencar via B4 Relay > > > <[email protected]> wrote: > > > > > > > From: Rodrigo Alencar <[email protected]> > > > > > > > > Implement trigger handler by leveraging the LDAC gpio to update all DAC > > > > channels at once when it is available. Also, the multiple channel writes > > > > can be flushed at once with the sync() operation. > > > > ... > > > > > > +static irqreturn_t ad5686_trigger_handler(int irq, void *p) > > > > +{ > > > > + struct iio_poll_func *pf = p; > > > > + struct iio_dev *indio_dev = pf->indio_dev; > > > > + struct iio_buffer *buffer = indio_dev->buffer; > > > > + struct ad5686_state *st = iio_priv(indio_dev); > > > > + u16 val[AD5686_MAX_CHANNELS] = { }; > > > > + int ret, ch, i = 0; > > > > + bool async_update; > > > > + u8 cmd; > > > > + > > > > + ret = iio_pop_from_buffer(buffer, val); > > > > + if (ret) > > > > + goto out; > > > > + > > > > + mutex_lock(&st->lock); > > > > + > > > > + async_update = st->ldac_gpio && > > > > bitmap_weight(indio_dev->active_scan_mask, > > > > + > > > > iio_get_masklength(indio_dev)) > 1; > > > > + if (async_update) { > > > > + /* use ldac to update all channels simultaneously */ > > > > + cmd = AD5686_CMD_WRITE_INPUT_N; > > > > + gpiod_set_value_cansleep(st->ldac_gpio, 0); > > > > + } else { > > > > + cmd = AD5686_CMD_WRITE_INPUT_N_UPDATE_N; > > > > + } > > > > + > > > > + iio_for_each_active_channel(indio_dev, ch) { > > > > + ret = st->ops->write(st, cmd, > > > > indio_dev->channels[ch].address, val[i++]); > > > > + if (ret) > > > > + goto cleanup; > > > > + } > > > > + > > > > + if (st->ops->sync) > > > > + ret = st->ops->sync(st); /* flush all pending transfers > > > > */ > > > > + > > > > +cleanup: > > > > It turns out that this label is not really needed. When sync() op is > > available > > it must be called regardless of write failure, so the bus data can reset its > > state. Then moving "cleanup" up would just make it useless. > > > > > > + if (async_update) > > > > > > Error paths are always fun. Do we care about setting ldac_gpio to 1 if > > > we failed to write the channel values? That will set any that did > > > successfully > > > update, but not all of them. Note I'm not sure on the right answer for > > > this. > > > There may not be one! > > > > I would not see a problem with that, as there is no much we can do with > > errors > > in a interrupt handler. > > > > > > > > > + gpiod_set_value_cansleep(st->ldac_gpio, 1); > > > > + > > > > + mutex_unlock(&st->lock); > > > > +out: > > > > + iio_trigger_notify_done(indio_dev->trig); > > > We get this pattern so often (though not always). Feels like maybe > > > we should put some effort into a generic opt in solution for this. > > > > > > A job for another day but options that come to mind. > > > 1) (hideous) a flag > > > 2) Maybe an alternative callback. thread_always_complete or > > > something like that. Pain to wire through all the calls though > > > and injecting the necessary wrapper isn't great either. > > > Implementation wise would be a case of popping in a wrapper function > > > in iio_trigger_attach_poll() call to request_threaded_irq(). > > > 3) Maybe a helper macro? Bit ugly as we'd need one to generate > > > the wrapper function and another to use the same name for > > > the registration function. > > > > > > Hmm. Those are all ugly (maybe 2 is ok ish). Suggestions welcome! > > > > using a cleanup.h? with something like: > > > > static inline void iio_trigger_always_done(struct iio_poll_func **ppf) > > { > > iio_trigger_notify_done((*ppf)->indio_dev->trig); > > } > > > > static irqreturn_t ad5686_trigger_handler(int irq, void *p) > > { > > struct iio_poll_func *pf __cleanup(iio_trigger_always_done) = p; > > That's not a nice pattern given the lack of any local constructing. The > ownership > transfer isn't obvious as both p and pf are really same type (it's slightly > hidden by the void * nature of p) - ideally we'd want p to be unusable after > that transfer. Could do something hideous like > struct iio_poll_func *pf __cleanup(iio_trigger_always_done) = > __get_and_null(p, NULL); > where p is set NULL so it becomes dead but that is ugly and not what that > is for so I doubt it would be popular and so we'd end up with yet another > weird macro. There is some precedence with take_fd() but the use of that > is complex and I think it is only used to grab ownership from a local CLASS() > defined cleanup. > > So it would work, but I've actively argued against this style elsewhere > in the kernel so don't really want it in IIO either! > > Key disadvantage is that it is yet another weird bit of cleanup.h stuff for > people to learn and we have enough of those already. > > So indeed an option but I'm not really liking it.
That makes sense, I understand the concern. I didn't take __cleanup() as ownership transfer. I thought it was just to register actions to variables when they go out of scope or something. In that case the pointer itself is being "cleaned up" (with **ppf in the cleanup action) not the memory that it points to. -- Kind regards, Rodrigo Alencar

