From: Joshua Crofts Date: Wed, 13 May 2026 14:35:52 +0000 (+0200) Subject: iio: magnetometer: ak8975: ensure device is awake for buffered capture X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=eaead586b3d95890832449f2887283b067426ecc;p=thirdparty%2Flinux.git iio: magnetometer: ak8975: ensure device is awake for buffered capture Currently, the ak8975_start_read_axis() can be called while the device is autosuspended, causing two issues: 1. I2C transfers in the aforementioned function will fail or timeout because ak8975_runtime_suspend() disables the device regulators. 2. Since ak8975_fill_buffer() does not hold runtime references, ak8975_runtime_suspend() can run concurrently, and since PM callbacks do not use a locking mechanism, it may cause a race accessing the control register via the I2C bus. Fix this issue by adding struct iio_buffer_setup_ops that contains preenable and postdisable functions to ensure correct that device is powered on when running a buffered capture. Fixes: bc11ca4a0b84 ("iio:magnetometer:ak8975: triggered buffer support") Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/20260511-magnetometer-fixes-post-pickup-v7-0-9d910faa28b6%40gmail.com Cc: Signed-off-by: Joshua Crofts Signed-off-by: Jonathan Cameron --- diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index dbab4d0bba348..0fb2fd03d11ce 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -899,6 +899,28 @@ static irqreturn_t ak8975_handle_trigger(int irq, void *p) return IRQ_HANDLED; } +static int ak8975_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ak8975_data *data = iio_priv(indio_dev); + struct device *dev = &data->client->dev; + + return pm_runtime_resume_and_get(dev); +} + +static int ak8975_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ak8975_data *data = iio_priv(indio_dev); + struct device *dev = &data->client->dev; + + pm_runtime_put_autosuspend(dev); + + return 0; +} + +static const struct iio_buffer_setup_ops ak8975_buffer_setup_ops = { + .preenable = ak8975_buffer_preenable, + .postdisable = ak8975_buffer_postdisable, +}; static int ak8975_probe(struct i2c_client *client) { const struct i2c_device_id *id = i2c_client_get_device_id(client); @@ -992,7 +1014,7 @@ static int ak8975_probe(struct i2c_client *client) indio_dev->name = name; ret = iio_triggered_buffer_setup(indio_dev, NULL, ak8975_handle_trigger, - NULL); + &ak8975_buffer_setup_ops); if (ret) { dev_err(&client->dev, "triggered buffer setup failed\n"); goto power_off;