Re: [PATCH 4/4] iio: pressure: mpl3115: add hardware FIFO support

SeungJu Cheon <[email protected]> Sun, 31 May 2026 20:15:45 +0900
Newsgroups dev.linux.lists.linux-kernel-mentees,org.kernel.vger.linux-iio
Message-ID <CAGwK=3pJFnif5GToHOS_Y5uo6meGYNAZPp8qECjiDLUgcPdcrg@mail.gmail.com>
Hi Andy,

On Sat, May 30, 2026 at 10:33 PM Andy Shevchenko
<[email protected]> wrote:
> > +       u8 fifo_buf[MPL3115_FIFO_SIZE * MPL3115_FIFO_SAMPLE_SIZE]
> > +               __aligned(IIO_DMA_MINALIGN);
>
> We have a macro for this,
...
> > +       u8 buffer[MPL3115_BUF_SIZE] __aligned(sizeof(s64)) = { };
>
> Don't we have a macro for this?

I'll rework the per-sample buffer as a struct with explicit fields
(__be32 pressure, __be16 temp, aligned_s64 ts), as Jonathan suggested,
which removes the manual offsets and alignment here.

> > +       ts = iio_get_time_ns(indio_dev);
> > +       for (i = 0; i < sample_count; i++) {
>
>   for (unsigned int i = 0; ...) {

Will declare i in the loop.

> > +               memcpy(&buffer[MPL3115_BUF_PRESS_OFFSET], &sample[0], 3);
> > +               memcpy(&buffer[MPL3115_BUF_TEMP_OFFSET], &sample[3], 2);
>
> These two sound to me like something which might require endianness
> handling, but if you put this as CPU native one and leave user space
> to take care of, it may be okay.

These are big-endian channels (scan_type.endianness = IIO_BE), pushed
as-is for user space to decode. The struct rework will make that
explicit with __be32/__be16 fields.

> > +       value = clamp_val(value, 1, MPL3115_FIFO_SIZE - 1);
>
> Why not clamp()?

Will use clamp().

> > +               mpl3115_set_active(data, true);
>
> Instead of having an argument, just make two helpers: set_active() /
> set_inactive().

Will split into mpl3115_set_active() / mpl3115_set_inactive().

> > +       return mpl3115_config_interrupt(data,
> > +               data->ctrl_reg1 | MPL3115_CTRL1_ACTIVE, ctrl_reg4);
>
> In some cases the FIELD_PREP()/FIELD_GET() is used, why not use FIELD_MODIFY()?

I'll review the FIELD_MODIFY() usage and apply it where appropriate.

> > +static const unsigned long mpl3115_scan_masks[] = {
> > +       BIT(0) | BIT(1),
> > +       0,
>
> No comma in terminator entry.

Will fix.

> > -       ret = devm_iio_triggered_buffer_setup(&client->dev,
> > [...]
>
> Before modifying this, it might make sense to split necessary bits to
> the helper function and then simply reuse it as needed.

Makes sense. I'll look into factoring the common setup into a helper
so the FIFO and triggered-buffer paths can reuse it.

Thanks for the review.

On Sat, May 30, 2026 at 10:33 PM Andy Shevchenko
<[email protected]> wrote:
>
> On Sat, May 30, 2026 at 1:40 PM SeungJu Cheon <[email protected]> wrote:
> >
> > Add support for the MPL3115A2 hardware FIFO.
> >
> > The device provides a 32-sample FIFO with configurable
> > watermark interrupts, allowing buffered data acquisition
> > with reduced interrupt and CPU overhead.
> >
> > Use a kfifo-backed IIO buffer when a DRDY interrupt and
> > SMBus block reads are available, falling back to the
> > existing triggered buffer implementation otherwise.
> >
> > When enabled, the driver configures the FIFO in circular
> > mode and drains accumulated samples on watermark
> > interrupts.
> >
> > Overflow conditions are handled by flushing available
> > samples before resetting the FIFO, avoiding unnecessary
> > data loss.
> >
> > The hardware always captures pressure and temperature
> > samples together, so FIFO operation requires both channels
> > to be enabled.
> >
> > Register cache updates are performed only after successful
> > I2C writes to keep cached and hardware state consistent.
> >
> > No functional change for non-buffered operation.
>
> ...
>
> > +       u8 fifo_buf[MPL3115_FIFO_SIZE * MPL3115_FIFO_SAMPLE_SIZE]
> > +               __aligned(IIO_DMA_MINALIGN);
>
> We have a macro for this,
>
> ...
>
> > +static int mpl3115_fifo_flush(struct iio_dev *indio_dev)
> > +{
> > +       struct mpl3115_data *data = iio_priv(indio_dev);
> > +       u8 buffer[MPL3115_BUF_SIZE] __aligned(sizeof(s64)) = { };
>
> Don't we have a macro for this?
>
> > +       unsigned int sample_count, i;
> > +       int ret;
> > +       bool overflow;
> > +       s64 ts;
> > +
> > +       ret = i2c_smbus_read_byte_data(data->client, MPL3115_F_STATUS);
> > +       if (ret < 0)
> > +               return ret;
> > +
> > +       overflow = FIELD_GET(MPL3115_F_STATUS_F_OVF, ret);
> > +       sample_count = FIELD_GET(MPL3115_F_STATUS_F_CNT, ret);
> > +       if (sample_count == 0)
> > +               return overflow ? mpl3115_fifo_reset(data) : 0;
> > +
> > +       ret = mpl3115_fifo_transfer(data, sample_count);
> > +       if (ret)
> > +               return ret;
> > +
> > +       ts = iio_get_time_ns(indio_dev);
> > +       for (i = 0; i < sample_count; i++) {
>
>   for (unsigned int i = 0; ...) {
>
> > +               u8 *sample = &data->fifo_buf[i * MPL3115_FIFO_SAMPLE_SIZE];
>
> > +               memcpy(&buffer[MPL3115_BUF_PRESS_OFFSET], &sample[0], 3);
> > +               memcpy(&buffer[MPL3115_BUF_TEMP_OFFSET], &sample[3], 2);
>
> These two sound to me like something which might require endianness
> handling, but if you put this as CPU native one and leave user space
> to take care of, it may be okay.
>
> > +
> > +               iio_push_to_buffers_with_ts(indio_dev, buffer, sizeof(buffer), ts);
> > +       }
> > +
> > +       if (overflow) {
>
> > +               dev_warn_ratelimited(&data->client->dev,
> > +                                    "FIFO overflow, samples may be lost\n");
> > +               return mpl3115_fifo_reset(data);
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int mpl3115_set_watermark(struct iio_dev *indio_dev, unsigned int value)
> > +{
> > +       struct mpl3115_data *data = iio_priv(indio_dev);
>
> > +       value = clamp_val(value, 1, MPL3115_FIFO_SIZE - 1);
>
> Why not clamp()?
>
> > +       guard(mutex)(&data->lock);
> > +       data->watermark = value;
> > +
> > +       return 0;
> > +}
>
> ...
>
> > +static int mpl3115_buffer_postenable(struct iio_dev *indio_dev)
> > +{
> > +       struct mpl3115_data *data = iio_priv(indio_dev);
> > +       u8 ctrl_reg4;
> > +       int ret;
> > +
> > +       guard(mutex)(&data->lock);
> > +
> > +       ret = mpl3115_set_active(data, false);
> > +       if (ret)
> > +               return ret;
> > +
> > +       ret = mpl3115_set_fifo(data, MPL3115_F_MODE_CIRCULAR);
> > +       if (ret) {
> > +               mpl3115_set_active(data, true);
>
> Instead of having an argument, just make two helpers: set_active() /
> set_inactive().
>
> > +               return ret;
> > +       }
>
> > +       ctrl_reg4 = data->ctrl_reg4;
> > +       ctrl_reg4 |= MPL3115_CTRL4_INT_EN_FIFO;
> > +       ctrl_reg4 &= ~MPL3115_CTRL4_INT_EN_DRDY;
> > +
> > +       return mpl3115_config_interrupt(data,
> > +               data->ctrl_reg1 | MPL3115_CTRL1_ACTIVE, ctrl_reg4);
>
> In some cases the FIELD_PREP()/FIELD_GET() is used, why not use FIELD_MODIFY()?
>
> > +}
>
> ...
>
> > +static const unsigned long mpl3115_scan_masks[] = {
> > +       BIT(0) | BIT(1),
> > +       0,
>
> No comma in terminator entry.
>
> > +};
>
> ...
>
> > -       ret = devm_iio_triggered_buffer_setup(&client->dev,
> > -                                     indio_dev,
> > -                                     NULL,
> > -                                     mpl3115_trigger_handler,
> > -                                     NULL);
> > -       if (ret)
> > -               return ret;
>
> Before modifying this, it might make sense to split necessary bits to
> the helper function and then simply reuse it as needed.
>
> --
> With Best Regards,
> Andy Shevchenko