On Fri, 04 Sep 2026 21:24:26 +0200 Wadim Mueller <[email protected]> wrote:
> Bind the driver to an emulated SLF3S on a fake I2C adapter, back it with > a regulator whose enable and disable callbacks are counted, and check > that the two stay paired across suspend and resume - including the cycles > in which the sensor NACKs a command or the supply refuses to come up. > > The suspend/resume helpers reproduce the PM core's rule that a resume > callback only runs after a suspend callback that returned 0, so that the > tests cannot construct an ordering the core never produces. One of the > tests relies on it: it cycles the device ten times with rotating failure > injection and asserts that the driver's enable count never climbs above > one. > > Signed-off-by: Wadim Mueller <[email protected]> Interesting approach to testing the flows. I'm not sure we want to carry this level of testing for a driver in the tree. Would like to hear the views of others on this. There is some really nice stuff in here. Makes me wonder if we should build a specific test device + driver that would hit all the widest possible set of corner cases that aren't device specific. The one slightly unusual thing for this device is the error on telling to stop when it is already stopped. A couple of things I noted whilst taking a first look. I'll want to take some time when I'm a lot more awake than I am today to look at this closely. Thanks! Jonathan > diff --git a/drivers/iio/flow/slf3s-kunit.c b/drivers/iio/flow/slf3s-kunit.c > new file mode 100644 > index 000000000000..d5e2db855838 > --- /dev/null > +++ b/drivers/iio/flow/slf3s-kunit.c > @@ -0,0 +1,734 @@ > + > +static void slf3s_fake_put_word(struct slf3s_fake *f, u8 *dst, u16 val) > +{ > + dst[0] = val >> 8; > + dst[1] = val & 0xff; Use a put_unaligned_be16() for this. > + dst[2] = crc8(f->crc_table, dst, 2, SLF3S_TEST_CRC8_INIT); > +} > +static int slf3s_test_init(struct kunit *test) > +{ > + struct regulator_consumer_supply *supply; > + struct regulator_init_data *init_data; > + struct i2c_board_info info = { }; > + struct regulator_config config = { }; > + struct slf3s_test_ctx *ctx; > + struct device *parent; > + char *consumer; > + int ret; > + > + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, ctx); > + test->priv = ctx; > + > + /* Actions run in reverse, so destroy after the unbind takes the locks. > */ > + mutex_init(&ctx->fake.lock); > + ret = kunit_add_action_or_reset(test, slf3s_test_destroy_mutex, > + &ctx->fake.lock); > + KUNIT_ASSERT_EQ(test, ret, 0); > + > + mutex_init(&ctx->reg.lock); > + ret = kunit_add_action_or_reset(test, slf3s_test_destroy_mutex, > + &ctx->reg.lock); > + KUNIT_ASSERT_EQ(test, ret, 0); Given those are deep in the emulation which is not what we are testing, do we need to bother with the mutex destroy calls? That is only there for some debugging of locks that isn't relevant here I think. > + > + crc8_populate_msb(ctx->fake.crc_table, SLF3S_TEST_CRC8_POLY); > + ctx->fake.state = SLF3S_FAKE_OFF;

