Re: [PATCH v2 04/12] iio: imu: inv_icm42600: add gyroscope IIO device

From: Jonathan Cameron
Date: Sat Jun 06 2020 - 10:33:58 EST


On Tue, 2 Jun 2020 09:10:29 +0000
Jean-Baptiste Maneyrol <JManeyrol@xxxxxxxxxxxxxx> wrote:

> Hi Jonathan,
>
> for the calibration bias, value is expressed in g unit, fixed,
> independant from any scale value. So I can switch to g instead of SI
> unit, but this will still not be like raw data which are dependent of
> the scale value. That's why I used SI units.
>
> Another solution, would be to adapt the value depending on the scale
> setting. So that it will correspond to raw data. But this also
> invovles complex computation.
>
> Tell me what you prefer.

I'm not actually that fussed, because the vast majority of
users will never touch this due to need to perform a calibration
procedure to know what to set it to. We have always left
it loosely defined, so perhaps our best plan is to not tighten
that up.

However, I would like part specific ABI docs to state the units
you have have for it. Otherwise no user will have any way of
knowing what they should do if they are in a position to do
high accuracy calibration.

Alternative would be to make it in raw units and deal with the
dependence between scale and the value here. That's kind of
my ideal option, but I understand its complex to do and of little
utility on a calibration twiddle.

Jonathan


>
> Thanks,
> JB
>
> From: Jonathan Cameron <jic23@xxxxxxxxxx>
> Sent: Sunday, May 31, 2020 13:54
> To: Jean-Baptiste Maneyrol <JManeyrol@xxxxxxxxxxxxxx>
> Cc: robh+dt@xxxxxxxxxx <robh+dt@xxxxxxxxxx>; robh@xxxxxxxxxx
> <robh@xxxxxxxxxx>; mchehab+huawei@xxxxxxxxxx
> <mchehab+huawei@xxxxxxxxxx>; davem@xxxxxxxxxxxxx
> <davem@xxxxxxxxxxxxx>; gregkh@xxxxxxxxxxxxxxxxxxx
> <gregkh@xxxxxxxxxxxxxxxxxxx>; linux-iio@xxxxxxxxxxxxxxx
> <linux-iio@xxxxxxxxxxxxxxx>; devicetree@xxxxxxxxxxxxxxx
> <devicetree@xxxxxxxxxxxxxxx>; linux-kernel@xxxxxxxxxxxxxxx
> <linux-kernel@xxxxxxxxxxxxxxx> Subject: Re: [PATCH v2 04/12] iio:
> imu: inv_icm42600: add gyroscope IIO device CAUTION: This email
> originated from outside of the organization. Please make sure the
> sender is who they say they are and do not click links or open
> attachments unless you recognize the sender and know the content is
> safe.
>
> On Wed, 27 May 2020 20:57:03 +0200
> Jean-Baptiste Maneyrol <jmaneyrol@xxxxxxxxxxxxxx> wrote:
>
> > Add IIO device for gyroscope sensor with data polling interface.
> > Attributes: raw, scale, sampling_frequency, calibbias.
> >
> > Gyroscope in low noise mode.
> >
> > Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@xxxxxxxxxxxxxx>
>
> Unusual to have a calibration offset specified in output units,
> which contributes a lot of the complexity in here.
> Normally those are strictly front end (output of some calibration
> DAC). So if they have units (and often they don't) I'd expect them to
> be the same as _raw.
>
> We need to tidy up the docs on this though as it doesn't express
> any sort of preference. It's hard to be specific as often the
> calibration scales are defined - they are just like tweaking a POT on
> an analog sensor board.
>
> A few trivial other things inline, including a suggestion to modify
> the layering of the driver a tiny bit during probe.
>
> Thanks,
>
> Jonathan
>
> > ---
> >Â drivers/iio/imu/inv_icm42600/inv_icm42600.hÂÂ |ÂÂ 6 +
> > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 4 +
> > .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 600
> >++++++++++++++++++ 3 files changed, 610 insertions(+)
> >Â create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> >
> > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
> > b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index
> > 14c8ef152418..c1023d59b37b 100644 ---
> > a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++
> > b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -120,6 +120,8 @@
> > struct inv_icm42600_suspended {
> >ÂÂ *Â @orientation:ÂÂÂ sensor chip orientation relative to main
> >hardware.
> >ÂÂ *Â @conf:ÂÂÂÂÂÂÂÂÂÂ chip sensors configurations.
> >ÂÂ *Â @suspended:ÂÂÂÂÂÂÂÂÂÂÂÂÂ suspended sensors configuration.
> > + *Â @indio_gyro:ÂÂÂÂ gyroscope IIO device.
> > + *Â @buffer:ÂÂÂÂÂÂÂÂ data transfer buffer aligned for DMA.
> >ÂÂ */
> >Â struct inv_icm42600_state {
> >ÂÂÂÂÂÂÂ struct mutex lock;
> > @@ -131,6 +133,8 @@ struct inv_icm42600_state {
> >ÂÂÂÂÂÂÂ struct iio_mount_matrix orientation;
> >ÂÂÂÂÂÂÂ struct inv_icm42600_conf conf;
> >ÂÂÂÂÂÂÂ struct inv_icm42600_suspended suspended;
> > +ÂÂÂÂ struct iio_dev *indio_gyro;
> > +ÂÂÂÂ uint8_t buffer[2] ____cacheline_aligned;
> >Â };
>
> >Â /* Virtual register addresses: @bank on MSB (4 upper bits),
> >@address on LSB */
> > @@ -369,4 +373,6 @@ int inv_icm42600_debugfs_reg(struct iio_dev
> > *indio_dev, unsigned int reg,
> >Â int inv_icm42600_core_probe(struct regmap *regmap, int chip,
> >ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ inv_icm42600_bus_setup bus_setup);
>
> > +int inv_icm42600_gyro_init(struct inv_icm42600_state *st);
> > +
> >Â #endif
> > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
> > b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index
> > 81b171d6782c..dccb7bcc782e 100644 ---
> > a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++
> > b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -510,6
> > +510,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int
> > chip,
> >ÂÂÂÂÂÂÂ if (ret)
> >ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂ ret = inv_icm42600_gyro_init(st);
> > +ÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
> > +
> >ÂÂÂÂÂÂÂ /* setup runtime power management */
> >ÂÂÂÂÂÂÂ ret = pm_runtime_set_active(dev);
> >ÂÂÂÂÂÂÂ if (ret)
> > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> > b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c new file mode
> > 100644 index 000000000000..9d9672989b23
> > --- /dev/null
> > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> > @@ -0,0 +1,600 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Copyright (C) 2020 Invensense, Inc.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/device.h>
> > +#include <linux/mutex.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/regmap.h>
> > +#include <linux/delay.h>
> > +#include <linux/math64.h>
> > +#include <linux/iio/iio.h>
> > +
> > +#include "inv_icm42600.h"
> > +
> > +#define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info)
> > Â \
> > +ÂÂÂÂ {
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .type = IIO_ANGL_VEL,
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .modified = 1,
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .channel2 = _modifier,
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .info_mask_separate =
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(IIO_CHAN_INFO_RAW) |
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(IIO_CHAN_INFO_CALIBBIAS),
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .info_mask_shared_by_type =
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(IIO_CHAN_INFO_SCALE),
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .info_mask_shared_by_type_available =
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(IIO_CHAN_INFO_SCALE) |
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(IIO_CHAN_INFO_CALIBBIAS),
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .info_mask_shared_by_all =
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(IIO_CHAN_INFO_SAMP_FREQ),
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .info_mask_shared_by_all_available =
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(IIO_CHAN_INFO_SAMP_FREQ),
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .scan_index = _index,
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .scan_type = {
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ .sign = 's',
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ .realbits = 16,
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ .storagebits = 16,
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ .endianness = IIO_BE,
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ },
> > Â \
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .ext_info = _ext_info,
> > Â \
> > +ÂÂÂÂ }
> > +
> > +enum inv_icm42600_gyro_scan {
> > +ÂÂÂÂ INV_ICM42600_GYRO_SCAN_X,
> > +ÂÂÂÂ INV_ICM42600_GYRO_SCAN_Y,
> > +ÂÂÂÂ INV_ICM42600_GYRO_SCAN_Z,
> > +};
> > +
> > +static const struct iio_chan_spec_ext_info
> > inv_icm42600_gyro_ext_infos[] = {
> > +ÂÂÂÂ IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL,
> > inv_icm42600_get_mount_matrix),
> > +ÂÂÂÂ {},
> > +};
> > +
> > +static const struct iio_chan_spec inv_icm42600_gyro_channels[] = {
> > +ÂÂÂÂ INV_ICM42600_GYRO_CHAN(IIO_MOD_X, INV_ICM42600_GYRO_SCAN_X,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ inv_icm42600_gyro_ext_infos),
> > +ÂÂÂÂ INV_ICM42600_GYRO_CHAN(IIO_MOD_Y, INV_ICM42600_GYRO_SCAN_Y,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ inv_icm42600_gyro_ext_infos),
> > +ÂÂÂÂ INV_ICM42600_GYRO_CHAN(IIO_MOD_Z, INV_ICM42600_GYRO_SCAN_Z,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ inv_icm42600_gyro_ext_infos),
> > +};
> > +
> > +static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state
> > *st,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct iio_chan_spec const
> > *chan,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int16_t *val)
> > +{
> > +ÂÂÂÂ struct device *dev = regmap_get_device(st->map);
> > +ÂÂÂÂ struct inv_icm42600_sensor_conf conf =
> > INV_ICM42600_SENSOR_CONF_INIT;
> > +ÂÂÂÂ unsigned int reg;
> > +ÂÂÂÂ __be16 *data;
> > +ÂÂÂÂ int ret;
> > +
> > +ÂÂÂÂ if (chan->type != IIO_ANGL_VEL)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ switch (chan->channel2) {
> > +ÂÂÂÂ case IIO_MOD_X:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ reg = INV_ICM42600_REG_GYRO_DATA_X;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ case IIO_MOD_Y:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ reg = INV_ICM42600_REG_GYRO_DATA_Y;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ case IIO_MOD_Z:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ reg = INV_ICM42600_REG_GYRO_DATA_Z;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ default:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +ÂÂÂÂ }
> > +
> > +ÂÂÂÂ pm_runtime_get_sync(dev);
> > +ÂÂÂÂ mutex_lock(&st->lock);
> > +
> > +ÂÂÂÂ /* enable gyro sensor */
> > +ÂÂÂÂ conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
> > +ÂÂÂÂ ret = inv_icm42600_set_gyro_conf(st, &conf, NULL);
> > +ÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ goto exit;
> > +
> > +ÂÂÂÂ /* read gyro register data */
> > +ÂÂÂÂ data = (__be16 *)&st->buffer[0];
> > +ÂÂÂÂ ret = regmap_bulk_read(st->map, reg, data, sizeof(*data));
> > +ÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ goto exit;
> > +
> > +ÂÂÂÂ *val = (int16_t)be16_to_cpup(data);
> > +ÂÂÂÂ if (*val == INV_ICM42600_DATA_INVALID)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = -EINVAL;
> > +exit:
> > +ÂÂÂÂ mutex_unlock(&st->lock);
> > +ÂÂÂÂ pm_runtime_mark_last_busy(dev);
> > +ÂÂÂÂ pm_runtime_put_autosuspend(dev);
> > +ÂÂÂÂ return ret;
> > +}
> > +
> > +/* IIO format int + nano */
> > +static const int inv_icm42600_gyro_scale[] = {
> > +ÂÂÂÂ /* +/- 2000dps => 0.001065264 rad/s */
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_2000DPS] = 0,
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_2000DPS + 1] = 1065264,
> > +ÂÂÂÂ /* +/- 1000dps => 0.000532632 rad/s */
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_1000DPS] = 0,
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_1000DPS + 1] = 532632,
> > +ÂÂÂÂ /* +/- 500dps => 0.000266316 rad/s */
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_500DPS] = 0,
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_500DPS + 1] = 266316,
> > +ÂÂÂÂ /* +/- 250dps => 0.000133158 rad/s */
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_250DPS] = 0,
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_250DPS + 1] = 133158,
> > +ÂÂÂÂ /* +/- 125dps => 0.000066579 rad/s */
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_125DPS] = 0,
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_125DPS + 1] = 66579,
> > +ÂÂÂÂ /* +/- 62.5dps => 0.000033290 rad/s */
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_62_5DPS] = 0,
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_62_5DPS + 1] = 33290,
> > +ÂÂÂÂ /* +/- 31.25dps => 0.000016645 rad/s */
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_31_25DPS] = 0,
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_31_25DPS + 1] = 16645,
> > +ÂÂÂÂ /* +/- 15.625dps => 0.000008322 rad/s */
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_15_625DPS] = 0,
> > +ÂÂÂÂ [2 * INV_ICM42600_GYRO_FS_15_625DPS + 1] = 8322,
> > +};
> > +
> > +static int inv_icm42600_gyro_read_scale(struct inv_icm42600_state
> > *st,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int *val, int *val2)
> > +{
> > +ÂÂÂÂ unsigned int idx;
> > +
> > +ÂÂÂÂ idx = st->conf.gyro.fs;
> > +
> > +ÂÂÂÂ *val = inv_icm42600_gyro_scale[2 * idx];
> > +ÂÂÂÂ *val2 = inv_icm42600_gyro_scale[2 * idx + 1];
> > +ÂÂÂÂ return IIO_VAL_INT_PLUS_NANO;
> > +}
> > +
> > +static int inv_icm42600_gyro_write_scale(struct inv_icm42600_state
> > *st,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int val, int val2)
> > +{
> > +ÂÂÂÂ struct device *dev = regmap_get_device(st->map);
> > +ÂÂÂÂ unsigned int idx;
> > +ÂÂÂÂ struct inv_icm42600_sensor_conf conf =
> > INV_ICM42600_SENSOR_CONF_INIT;
> > +ÂÂÂÂ int ret;
> > +
> > +ÂÂÂÂ for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_gyro_scale); idx
> > += 2) {
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (val == inv_icm42600_gyro_scale[idx] &&
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ val2 == inv_icm42600_gyro_scale[idx + 1])
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ }
> > +ÂÂÂÂ if (idx >= ARRAY_SIZE(inv_icm42600_gyro_scale))
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ conf.fs = idx / 2;
> > +
> > +ÂÂÂÂ pm_runtime_get_sync(dev);
> > +ÂÂÂÂ mutex_lock(&st->lock);
> > +
> > +ÂÂÂÂ ret = inv_icm42600_set_gyro_conf(st, &conf, NULL);
> > +
> > +ÂÂÂÂ mutex_unlock(&st->lock);
> > +ÂÂÂÂ pm_runtime_mark_last_busy(dev);
> > +ÂÂÂÂ pm_runtime_put_autosuspend(dev);
> > +
> > +ÂÂÂÂ return ret;
> > +}
> > +
> > +/* IIO format int + micro */
> > +static const int inv_icm42600_gyro_odr[] = {
> > +ÂÂÂÂ /* 12.5Hz */
> > +ÂÂÂÂ 12, 500000,
> > +ÂÂÂÂ /* 25Hz */
> > +ÂÂÂÂ 25, 0,
> > +ÂÂÂÂ /* 50Hz */
> > +ÂÂÂÂ 50, 0,
> > +ÂÂÂÂ /* 100Hz */
> > +ÂÂÂÂ 100, 0,
> > +ÂÂÂÂ /* 200Hz */
> > +ÂÂÂÂ 200, 0,
> > +ÂÂÂÂ /* 1kHz */
> > +ÂÂÂÂ 1000, 0,
> > +ÂÂÂÂ /* 2kHz */
> > +ÂÂÂÂ 2000, 0,
> > +ÂÂÂÂ /* 4kHz */
> > +ÂÂÂÂ 4000, 0,
> > +};
> > +
> > +static const int inv_icm42600_gyro_odr_conv[] = {
> > +ÂÂÂÂ INV_ICM42600_ODR_12_5HZ,
> > +ÂÂÂÂ INV_ICM42600_ODR_25HZ,
> > +ÂÂÂÂ INV_ICM42600_ODR_50HZ,
> > +ÂÂÂÂ INV_ICM42600_ODR_100HZ,
> > +ÂÂÂÂ INV_ICM42600_ODR_200HZ,
> > +ÂÂÂÂ INV_ICM42600_ODR_1KHZ_LN,
> > +ÂÂÂÂ INV_ICM42600_ODR_2KHZ_LN,
> > +ÂÂÂÂ INV_ICM42600_ODR_4KHZ_LN,
> > +};
> > +
> > +static int inv_icm42600_gyro_read_odr(struct inv_icm42600_state
> > *st,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int *val, int *val2)
> > +{
> > +ÂÂÂÂ unsigned int odr;
> > +ÂÂÂÂ unsigned int i;
> > +
> > +ÂÂÂÂ odr = st->conf.gyro.odr;
> > +
> > +ÂÂÂÂ for (i = 0; i < ARRAY_SIZE(inv_icm42600_gyro_odr_conv); ++i) {
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (inv_icm42600_gyro_odr_conv[i] == odr)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ }
> > +ÂÂÂÂ if (i >= ARRAY_SIZE(inv_icm42600_gyro_odr_conv))
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ *val = inv_icm42600_gyro_odr[2 * i];
> > +ÂÂÂÂ *val2 = inv_icm42600_gyro_odr[2 * i + 1];
> > +
> > +ÂÂÂÂ return IIO_VAL_INT_PLUS_MICRO;
> > +}
> > +
> > +static int inv_icm42600_gyro_write_odr(struct inv_icm42600_state
> > *st,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int val, int val2)
> > +{
> > +ÂÂÂÂ struct device *dev = regmap_get_device(st->map);
> > +ÂÂÂÂ unsigned int idx;
> > +ÂÂÂÂ struct inv_icm42600_sensor_conf conf =
> > INV_ICM42600_SENSOR_CONF_INIT;
> > +ÂÂÂÂ int ret;
> > +
> > +ÂÂÂÂ for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_gyro_odr); idx +=
> > 2) {
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (val == inv_icm42600_gyro_odr[idx] &&
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ val2 == inv_icm42600_gyro_odr[idx + 1])
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ }
> > +ÂÂÂÂ if (idx >= ARRAY_SIZE(inv_icm42600_gyro_odr))
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ conf.odr = inv_icm42600_gyro_odr_conv[idx / 2];
> > +
> > +ÂÂÂÂ pm_runtime_get_sync(dev);
> > +ÂÂÂÂ mutex_lock(&st->lock);
> > +
> > +ÂÂÂÂ ret = inv_icm42600_set_gyro_conf(st, &conf, NULL);
> > +
> > +ÂÂÂÂ mutex_unlock(&st->lock);
> > +ÂÂÂÂ pm_runtime_mark_last_busy(dev);
> > +ÂÂÂÂ pm_runtime_put_autosuspend(dev);
> > +
> > +ÂÂÂÂ return ret;
> > +}
> > +
> > +/*
> > + * Calibration bias values, IIO range format int + nano.
> > + * Value is limited to +/-64dps coded on 12 bits signed. Step is
> > 1/32 dps.
> > + */
> > +static int inv_icm42600_gyro_calibbias[] = {
> > +ÂÂÂÂ -1, 117010721,ÂÂÂÂÂÂÂÂÂ /* min: -1.117010721 rad/s */
> > +ÂÂÂÂ 0, 545415,ÂÂÂÂÂÂÂÂÂÂÂÂÂ /* step: 0.000545415 rad/s */
> > +ÂÂÂÂ 1, 116465306,ÂÂÂÂÂÂÂÂÂÂ /* max: 1.116465306 rad/s */
> > +};
> > +
> > +static int inv_icm42600_gyro_read_offset(struct inv_icm42600_state
> > *st,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct iio_chan_spec const
> > *chan,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int *val, int *val2)
> > +{
> > +ÂÂÂÂ struct device *dev = regmap_get_device(st->map);
> > +ÂÂÂÂ int64_t val64;
> > +ÂÂÂÂ int32_t bias;
> > +ÂÂÂÂ unsigned int reg;
> > +ÂÂÂÂ int16_t offset;
> > +ÂÂÂÂ uint8_t data[2];
> > +ÂÂÂÂ int ret;
> > +
> > +ÂÂÂÂ if (chan->type != IIO_ANGL_VEL)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ switch (chan->channel2) {
> > +ÂÂÂÂ case IIO_MOD_X:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ reg = INV_ICM42600_REG_OFFSET_USER0;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ case IIO_MOD_Y:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ reg = INV_ICM42600_REG_OFFSET_USER1;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ case IIO_MOD_Z:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ reg = INV_ICM42600_REG_OFFSET_USER3;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ default:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +ÂÂÂÂ }
> > +
> > +ÂÂÂÂ pm_runtime_get_sync(dev);
> > +ÂÂÂÂ mutex_lock(&st->lock);
> > +
> > +ÂÂÂÂ ret = regmap_bulk_read(st->map, reg, st->buffer,
> > sizeof(data));
> > +ÂÂÂÂ memcpy(data, st->buffer, sizeof(data));
> > +
> > +ÂÂÂÂ mutex_unlock(&st->lock);
> > +ÂÂÂÂ pm_runtime_mark_last_busy(dev);
> > +ÂÂÂÂ pm_runtime_put_autosuspend(dev);
> > +ÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
> > +
> > +ÂÂÂÂ /* 12 bits signed value */
> > +ÂÂÂÂ switch (chan->channel2) {
> > +ÂÂÂÂ case IIO_MOD_X:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ offset = sign_extend32(((data[1] & 0x0F) << 8) |
> > data[0], 11);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ case IIO_MOD_Y:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ offset = sign_extend32(((data[0] & 0xF0) << 4) |
> > data[1], 11);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ case IIO_MOD_Z:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ offset = sign_extend32(((data[1] & 0x0F) << 8) |
> > data[0], 11);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ default:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +ÂÂÂÂ }
> > +
> > +ÂÂÂÂ /*
> > +ÂÂÂÂÂ * convert raw offset to dps then to rad/s
> > +ÂÂÂÂÂ * 12 bits signed raw max 64 to dps: 64 / 2048
> > +ÂÂÂÂÂ * dps to rad: Pi / 180
> > +ÂÂÂÂÂ * result in nano (1000000000)
> > +ÂÂÂÂÂ * (offset * 64 * Pi * 1000000000) / (2048 * 180)
> > +ÂÂÂÂÂ */
> > +ÂÂÂÂ val64 = (int64_t)offset * 64LL * 3141592653LL;
> > +ÂÂÂÂ /* for rounding, add + or - divisor (2048 * 180) divided by 2
> > */
> > +ÂÂÂÂ if (val64 >= 0)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ val64 += 2048 * 180 / 2;
> > +ÂÂÂÂ else
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ val64 -= 2048 * 180 / 2;
> > +ÂÂÂÂ bias = div_s64(val64, 2048 * 180);
> > +ÂÂÂÂ *val = bias / 1000000000L;
> > +ÂÂÂÂ *val2 = bias % 1000000000L;
> > +
> > +ÂÂÂÂ return IIO_VAL_INT_PLUS_NANO;
> > +}
> > +
> > +static int inv_icm42600_gyro_write_offset(struct
> > inv_icm42600_state *st,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct iio_chan_spec const
> > *chan,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int val, int val2)
> > +{
> > +ÂÂÂÂ struct device *dev = regmap_get_device(st->map);
> > +ÂÂÂÂ int64_t val64, min, max;
> > +ÂÂÂÂ unsigned int reg, regval;
> > +ÂÂÂÂ int16_t offset;
> > +ÂÂÂÂ int ret;
> > +
> > +ÂÂÂÂ if (chan->type != IIO_ANGL_VEL)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ switch (chan->channel2) {
> > +ÂÂÂÂ case IIO_MOD_X:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ reg = INV_ICM42600_REG_OFFSET_USER0;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ case IIO_MOD_Y:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ reg = INV_ICM42600_REG_OFFSET_USER1;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ case IIO_MOD_Z:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ reg = INV_ICM42600_REG_OFFSET_USER3;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ default:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +ÂÂÂÂ }
> > +
> > +ÂÂÂÂ /* inv_icm42600_gyro_calibbias: min - step - max in nano */
> > +ÂÂÂÂ min = (int64_t)inv_icm42600_gyro_calibbias[0] * 1000000000LL +
> > +ÂÂÂÂÂÂÂÂÂÂ (int64_t)inv_icm42600_gyro_calibbias[1];
> > +ÂÂÂÂ max = (int64_t)inv_icm42600_gyro_calibbias[4] * 1000000000LL +
> > +ÂÂÂÂÂÂÂÂÂÂ (int64_t)inv_icm42600_gyro_calibbias[5];
> > +ÂÂÂÂ val64 = (int64_t)val * 1000000000LL + (int64_t)val2;
> > +ÂÂÂÂ if (val64 < min || val64 > max)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ /*
> > +ÂÂÂÂÂ * convert rad/s to dps then to raw value
> > +ÂÂÂÂÂ * rad to dps: 180 / Pi
> > +ÂÂÂÂÂ * dps to raw 12 bits signed, max 64: 2048 / 64
> > +ÂÂÂÂÂ * val in nano (1000000000)
> > +ÂÂÂÂÂ * val * 180 * 2048 / (Pi * 1000000000 * 64)
> > +ÂÂÂÂÂ */
> > +ÂÂÂÂ val64 = val64 * 180LL * 2048LL;
> > +ÂÂÂÂ /* for rounding, add + or - divisor (3141592653 * 64) divided
> > by 2 */
> > +ÂÂÂÂ if (val64 >= 0)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ val64 += 3141592653LL * 64LL / 2LL;
> > +ÂÂÂÂ else
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ val64 -= 3141592653LL * 64LL / 2LL;
> > +ÂÂÂÂ offset = div64_s64(val64, 3141592653LL * 64LL);
> > +
> > +ÂÂÂÂ /* clamp value limited to 12 bits signed */
> > +ÂÂÂÂ if (offset < -2048)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ offset = -2048;
> > +ÂÂÂÂ else if (offset > 2047)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ offset = 2047;
> > +
> > +ÂÂÂÂ pm_runtime_get_sync(dev);
> > +ÂÂÂÂ mutex_lock(&st->lock);
> > +
> > +ÂÂÂÂ switch (chan->channel2) {
> > +ÂÂÂÂ case IIO_MOD_X:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* OFFSET_USER1 register is shared */
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = regmap_read(st->map,
> > INV_ICM42600_REG_OFFSET_USER1,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ &regval);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ goto out_unlock;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ st->buffer[0] = offset & 0xFF;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ st->buffer[1] = (regval & 0xF0) | ((offset & 0xF00)
> > >> 8);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ case IIO_MOD_Y:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* OFFSET_USER1 register is shared */
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = regmap_read(st->map,
> > INV_ICM42600_REG_OFFSET_USER1,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ &regval);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ goto out_unlock;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ st->buffer[0] = ((offset & 0xF00) >> 4) | (regval &
> > 0x0F);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ st->buffer[1] = offset & 0xFF;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ case IIO_MOD_Z:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* OFFSET_USER4 register is shared */
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = regmap_read(st->map,
> > INV_ICM42600_REG_OFFSET_USER4,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ &regval);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ goto out_unlock;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ st->buffer[0] = offset & 0xFF;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ st->buffer[1] = (regval & 0xF0) | ((offset & 0xF00)
> > >> 8);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ break;
> > +ÂÂÂÂ default:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = -EINVAL;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ goto out_unlock;
> > +ÂÂÂÂ }
> > +
> > +ÂÂÂÂ ret = regmap_bulk_write(st->map, reg, st->buffer, 2);
> > +
> > +out_unlock:
> > +ÂÂÂÂ mutex_unlock(&st->lock);
> > +ÂÂÂÂ pm_runtime_mark_last_busy(dev);
> > +ÂÂÂÂ pm_runtime_put_autosuspend(dev);
> > +ÂÂÂÂ return ret;
> > +}
> > +
> > +static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct iio_chan_spec const
> > *chan,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int *val, int *val2, long mask)
> > +{
> > +ÂÂÂÂ struct inv_icm42600_state *st =
> > iio_device_get_drvdata(indio_dev);
> > +ÂÂÂÂ int16_t data;
> > +ÂÂÂÂ int ret;
> > +
> > +ÂÂÂÂ if (chan->type != IIO_ANGL_VEL)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ switch (mask) {
> > +ÂÂÂÂ case IIO_CHAN_INFO_RAW:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = iio_device_claim_direct_mode(indio_dev);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = inv_icm42600_gyro_read_sensor(st, chan, &data);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ iio_device_release_direct_mode(indio_dev);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ *val = data;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return IIO_VAL_INT;
> > +ÂÂÂÂ case IIO_CHAN_INFO_SCALE:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return inv_icm42600_gyro_read_scale(st, val, val2);
> > +ÂÂÂÂ case IIO_CHAN_INFO_SAMP_FREQ:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return inv_icm42600_gyro_read_odr(st, val, val2);
> > +ÂÂÂÂ case IIO_CHAN_INFO_CALIBBIAS:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return inv_icm42600_gyro_read_offset(st, chan, val,
> > val2);
> > +ÂÂÂÂ default:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +ÂÂÂÂ }
> > +}
> > +
> > +static int inv_icm42600_gyro_read_avail(struct iio_dev *indio_dev,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct iio_chan_spec const
> > *chan,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ const int **vals,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int *type, int *length, long
> > mask) +{
> > +ÂÂÂÂ if (chan->type != IIO_ANGL_VEL)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ switch (mask) {
> > +ÂÂÂÂ case IIO_CHAN_INFO_SCALE:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ *vals = inv_icm42600_gyro_scale;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ *type = IIO_VAL_INT_PLUS_NANO;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ *length = ARRAY_SIZE(inv_icm42600_gyro_scale);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return IIO_AVAIL_LIST;
> > +ÂÂÂÂ case IIO_CHAN_INFO_SAMP_FREQ:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ *vals = inv_icm42600_gyro_odr;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ *type = IIO_VAL_INT_PLUS_MICRO;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ *length = ARRAY_SIZE(inv_icm42600_gyro_odr);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return IIO_AVAIL_LIST;
> > +ÂÂÂÂ case IIO_CHAN_INFO_CALIBBIAS:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ *vals = inv_icm42600_gyro_calibbias;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ *type = IIO_VAL_INT_PLUS_NANO;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return IIO_AVAIL_RANGE;
> > +ÂÂÂÂ default:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +ÂÂÂÂ }
> > +}
> > +
> > +static int inv_icm42600_gyro_write_raw(struct iio_dev *indio_dev,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct iio_chan_spec const
> > *chan,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int val, int val2, long mask)
> > +{
> > +ÂÂÂÂ struct inv_icm42600_state *st =
> > iio_device_get_drvdata(indio_dev);
> > +ÂÂÂÂ int ret;
> > +
> > +ÂÂÂÂ if (chan->type != IIO_ANGL_VEL)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ switch (mask) {
> > +ÂÂÂÂ case IIO_CHAN_INFO_SCALE:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = iio_device_claim_direct_mode(indio_dev);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = inv_icm42600_gyro_write_scale(st, val, val2);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ iio_device_release_direct_mode(indio_dev);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
> > +ÂÂÂÂ case IIO_CHAN_INFO_SAMP_FREQ:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return inv_icm42600_gyro_write_odr(st, val, val2);
> > +ÂÂÂÂ case IIO_CHAN_INFO_CALIBBIAS:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = iio_device_claim_direct_mode(indio_dev);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = inv_icm42600_gyro_write_offset(st, chan, val,
> > val2);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ iio_device_release_direct_mode(indio_dev);
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
> > +ÂÂÂÂ default:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +ÂÂÂÂ }
> > +}
> > +
> > +static int inv_icm42600_gyro_write_raw_get_fmt(struct iio_dev
> > *indio_dev,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct iio_chan_spec
> > const *chan,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ long mask)
> > +{
> > +ÂÂÂÂ if (chan->type != IIO_ANGL_VEL)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +
> > +ÂÂÂÂ switch (mask) {
> > +ÂÂÂÂ case IIO_CHAN_INFO_SCALE:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return IIO_VAL_INT_PLUS_NANO;
> > +ÂÂÂÂ case IIO_CHAN_INFO_SAMP_FREQ:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return IIO_VAL_INT_PLUS_MICRO;
> > +ÂÂÂÂ case IIO_CHAN_INFO_CALIBBIAS:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return IIO_VAL_INT_PLUS_NANO;
> > +ÂÂÂÂ default:
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
> > +ÂÂÂÂ }
> > +}
> > +
> > +static const struct iio_info inv_icm42600_gyro_info = {
> > +ÂÂÂÂ .read_raw = inv_icm42600_gyro_read_raw,
> > +ÂÂÂÂ .read_avail = inv_icm42600_gyro_read_avail,
> > +ÂÂÂÂ .write_raw = inv_icm42600_gyro_write_raw,
> > +ÂÂÂÂ .write_raw_get_fmt = inv_icm42600_gyro_write_raw_get_fmt,
> > +ÂÂÂÂ .debugfs_reg_access = inv_icm42600_debugfs_reg,
> > +};
> > +
> > +int inv_icm42600_gyro_init(struct inv_icm42600_state *st)
>
> This feels like the layering would be clearer if this
> returned the struct iio_dev * and the assignment happened in the
> core driver.
>
> Then state parameter can be const and it'll be obvious it has
> no side effects on the state structure.
>
> > +{
> > +ÂÂÂÂ struct device *dev = regmap_get_device(st->map);
> > +ÂÂÂÂ const char *name;
> > +ÂÂÂÂ struct iio_dev *indio_dev;
> > +
> > +ÂÂÂÂ name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->name);
> > +ÂÂÂÂ if (!name)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -ENOMEM;
> > +
> > +ÂÂÂÂ indio_dev = devm_iio_device_alloc(dev, 0);
> > +ÂÂÂÂ if (!indio_dev)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -ENOMEM;
> > +
> > +ÂÂÂÂ iio_device_set_drvdata(indio_dev, st);
> > +ÂÂÂÂ indio_dev->dev.parent = dev;
> > +ÂÂÂÂ indio_dev->name = name;
> > +ÂÂÂÂ indio_dev->info = &inv_icm42600_gyro_info;
> > +ÂÂÂÂ indio_dev->modes = INDIO_DIRECT_MODE;
> > +ÂÂÂÂ indio_dev->channels = inv_icm42600_gyro_channels;
> > +ÂÂÂÂ indio_dev->num_channels =
> > ARRAY_SIZE(inv_icm42600_gyro_channels); +
> > +ÂÂÂÂ st->indio_gyro = indio_dev;
> > +ÂÂÂÂ return devm_iio_device_register(dev, st->indio_gyro);
> > +}