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

Andy Shevchenko <[email protected]>
Newsgroups dev.linux.lists.linux-kernel-mentees,org.kernel.vger.linux-iio
Message-ID <CAHp75VcN7B5BdKZGBiw5cbhYesGsO_tStcN3cKgggiHiuSnJ7w@mail.gmail.com>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.