Re: [PATCH] dt-bindings: iio: imu: mpu6050: Improve i2c-gate disallow list
Hello Luca, good catch, thanks for the patch! Acked-by: Jean-Baptiste Maneyrol From: Luca Weiss Sent: Monday, April 8, 2024 18:34 To: ~postmarketos/upstream...@lists.sr.ht <~postmarketos/upstream...@lists.sr.ht>; phone-de...@vger.kernel.org ; Jonathan Cameron ; Lars-Peter Clausen ; Rob Herring ; Krzysztof Kozlowski ; Conor Dooley ; Jean-Baptiste Maneyrol Cc: linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org ; Luca Weiss Subject: [PATCH] dt-bindings: iio: imu: mpu6050: Improve i2c-gate disallow list This Message Is From an Untrusted Sender You have not previously corresponded with this sender. Before all supported sensors except for MPU{9150,9250,9255} were not allowed to use i2c-gate in the bindings which excluded quite a few supported sensors where this functionality is supported. Switch the list of sensors to ones where the Linux driver explicitly disallows support for the auxiliary bus ("inv_mpu_i2c_aux_bus"). Since the driver is also based on "default: return true" this should scale better into the future. Signed-off-by: Luca Weiss --- This fixes dt validation error on qcom-msm8974-lge-nexus5-hammerhead which uses mpu6515 arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dtb: mpu6515@68: i2c-gate: False schema does not allow {'#address-cells': [[1]], '#size-cells': [[0]], 'ak8963@f': {'compatible': ['asahi-kasei,ak8963'], 'reg': [[15]], 'gpios': [[40, 67, 0]], 'vid-supply': [[50]], 'vdd-supply': [[49]]}, 'bmp280@76': {'compatible': ['bosch,bmp280'], 'reg': [[118]], 'vdda-supply': [[50]], 'vddd-supply': [[49]]}} from schema $id: https://urldefense.com/v3/__http://devicetree.org/schemas/iio/imu/invensense,mpu6050.yaml*__;Iw!!FtrhtPsWDhZ6tw!Athn1pwCL_LPpZ97exHEFSkirApIqFF2ISY01IuyHtFBxpbPkcPWh_FmzB_TiCzb8uv1HO0AHY4IeIlv1-o$[devicetree[.]org] --- .../devicetree/bindings/iio/imu/invensense,mpu6050.yaml | 17 + 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml index 297b8a1a7ffb..587ff2bced2d 100644 --- a/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml +++ b/Documentation/devicetree/bindings/iio/imu/invensense,mpu6050.yaml @@ -62,14 +62,15 @@ properties: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# - if: - not: -properties: - compatible: -contains: - enum: -- invensense,mpu9150 -- invensense,mpu9250 -- invensense,mpu9255 + properties: +compatible: + contains: +enum: + - invensense,iam20680 + - invensense,icm20602 + - invensense,icm20608 + - invensense,icm20609 + - invensense,icm20689 then: properties: i2c-gate: false --- base-commit: 8568bb2ccc278f344e6ac44af6ed010a90aa88dc change-id: 20240408-mpu6050-i2c-gate-4ea473e492f4 Best regards, -- Luca Weiss
Re: [PATCH V4] iio:imu:mpu6050: Modify matricies to matrices
Hello, thanks for the patch, JB Acked-by: Jean-Baptiste Maneyrol From: Guoqing chi Sent: Monday, March 22, 2021 02:30 To: ji...@kernel.org Cc: linux-kernel@vger.kernel.org ; chiguoq...@yulong.com ; rdun...@infradead.org ; linux-...@vger.kernel.org ; chi96246...@163.com Subject: [PATCH V4] iio:imu:mpu6050: Modify matricies to matrices 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. From: Guoqing Chi The plural of "matrix" is "matrices". Signed-off-by: Guoqing Chi Acked-by: Randy Dunlap --- V4:adding linux-...@vger.kernel.org. include/linux/platform_data/invensense_mpu6050.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/platform_data/invensense_mpu6050.h b/include/linux/platform_data/invensense_mpu6050.h index 93974f4cfba1..f05b37521f67 100644 --- a/include/linux/platform_data/invensense_mpu6050.h +++ b/include/linux/platform_data/invensense_mpu6050.h @@ -12,7 +12,7 @@ * mounting matrix retrieved from device-tree) * * Contains platform specific information on how to configure the MPU6050 to - * work on this platform. The orientation matricies are 3x3 rotation matricies + * work on this platform. The orientation matrices are 3x3 rotation matrices * that are applied to the data to rotate from the mounting orientation to the * platform orientation. The values must be one of 0, 1, or -1 and each row and * column should have exactly 1 non-zero value. -- 2.17.1
Re: [PATCH v4 08/13] Documentation: ABI: add specific icm42600 documentation
Hello Jonathan, no problem for me, you can move it wherever you see fit. Thank you. JB From: Jonathan Cameron Sent: Saturday, November 14, 2020 16:23 To: Jean-Baptiste Maneyrol Cc: robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH v4 08/13] Documentation: ABI: add specific icm42600 documentation 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 Mon, 22 Jun 2020 17:37:24 +0200 Jean-Baptiste Maneyrol wrote: > Hardware offset available as calibscale sysfs attributes are real > physical values exprimed in SI units. > > calibscale_available sysfs attributes represents the range of > acceptable values. > > Signed-off-by: Jean-Baptiste Maneyrol Hi Jean-Baptiste. This is causing us some issues as the ABI docs are now added to the generated html docs for the kernel. It's been a while, so I've kind of forgotten why we have this file. Was the issue that these are in SI units as opposed to most calibbias controls which are offsets applied to the raw analog reading hitting the ADC? Would you mind if we moved this into the main doc as a note for this particular device? i.e. something in sysfs-bus-iio saying icm42600: Hardware applied calibration offset is in SI units (rad/s or m/s^2 as appropriate) ? Thanks, Jonathan > --- > .../ABI/testing/sysfs-bus-iio-icm42600 | 20 +++ > 1 file changed, 20 insertions(+) > create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-icm42600 > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio-icm42600 > b/Documentation/ABI/testing/sysfs-bus-iio-icm42600 > new file mode 100644 > index ..0bf1fd4f5bf1 > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-bus-iio-icm42600 > @@ -0,0 +1,20 @@ > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibbias > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibbias > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias > +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias > +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias > +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias > +KernelVersion: 5.8 > +Contact: linux-...@vger.kernel.org > +Description: > + Hardware applied calibration offset (assumed to fix production > + inaccuracies). Values represent a real physical offset expressed > + in SI units (m/s^2 for accelerometer and rad/s for gyroscope). > + > +What: > /sys/bus/iio/devices/iio:deviceX/in_accel_calibbias_available > +What: > /sys/bus/iio/devices/iio:deviceX/in_anglvel_calibbias_available > +KernelVersion: 5.8 > +Contact: linux-...@vger.kernel.org > +Description: > + Range of available values for hardware offset. Values in SI > + units (m/s^2 for accelerometer and rad/s for gyroscope).
Re: [PATCH v2 13/18] iio: imu: inv_mpu6050: Simplify with dev_err_probe()
Hello, thanks for the patch. Best regards, JB Reviewed-by: Jean-Baptiste Maneyrol From: linux-iio-ow...@vger.kernel.org on behalf of Krzysztof Kozlowski Sent: Thursday, August 27, 2020 21:26 To: Jonathan Cameron; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald-Stadler; Peter Rosin; Kukjin Kim; Krzysztof Kozlowski; Michael Hennerich; Kevin Hilman; Neil Armstrong; Jerome Brunet; Martin Blumenstingl; Marek Vasut; Maxime Coquelin; Alexandre Torgue; Beniamin Bia; Tomasz Duszynski; Linus Walleij; Andy Shevchenko; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux-samsung-...@vger.kernel.org; linux-amlo...@lists.infradead.org; linux-st...@st-md-mailman.stormreply.com Subject: [PATCH v2 13/18] iio: imu: inv_mpu6050: Simplify with dev_err_probe() 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. Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Krzysztof Kozlowski --- drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 20 ++-- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 3fee3947f772..18a1898e3e34 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -1475,22 +1475,14 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, } st->vdd_supply = devm_regulator_get(dev, "vdd"); - if (IS_ERR(st->vdd_supply)) { - if (PTR_ERR(st->vdd_supply) != -EPROBE_DEFER) - dev_err(dev, "Failed to get vdd regulator %d\n", - (int)PTR_ERR(st->vdd_supply)); - - return PTR_ERR(st->vdd_supply); - } + if (IS_ERR(st->vdd_supply)) + return dev_err_probe(dev, PTR_ERR(st->vdd_supply), +"Failed to get vdd regulator\n"); st->vddio_supply = devm_regulator_get(dev, "vddio"); - if (IS_ERR(st->vddio_supply)) { - if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER) - dev_err(dev, "Failed to get vddio regulator %d\n", - (int)PTR_ERR(st->vddio_supply)); - - return PTR_ERR(st->vddio_supply); - } + if (IS_ERR(st->vddio_supply)) + return dev_err_probe(dev, PTR_ERR(st->vddio_supply), +"Failed to get vddio regulator\n"); result = regulator_enable(st->vdd_supply); if (result) { -- 2.17.1
Re: [PATCH] iio: imu: inv_mpu6050: check for temp_fifo_enable
Hello, this is a case that should never be happening since available scan mask only advertise Accel + Temp, Gyro + Temp, or Accel + Gyro + Temp. More than that, temperature sensor is not working when MEMS engine is off. (it's only purpose it to measure temperature of the MEMS to do data temperature compensation). So I think we can let this check as it is currently, since this is not a supported configuration. Best regards, JB From: Andy Shevchenko Sent: Monday, August 10, 2020 10:02 To: t...@redhat.com Cc: Jonathan Cameron ; Hartmut Knaack ; Lars-Peter Clausen ; Peter Meerwald ; Jean-Baptiste Maneyrol ; Michał Mirosław ; Lee Jones ; linux-iio ; Linux Kernel Mailing List Subject: Re: [PATCH] iio: imu: inv_mpu6050: check for temp_fifo_enable 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 Sun, Aug 9, 2020 at 7:00 PM wrote: > > From: Tom Rix > > clang static analysis reports this problem > > inv_mpu_ring.c:181:18: warning: Division by zero > nb = fifo_count / bytes_per_datum; > ~~~^ > > This is a false positive. > Dividing by 0 is protected by this check > > if (!(st->chip_config.accl_fifo_enable | > st->chip_config.gyro_fifo_enable | > st->chip_config.magn_fifo_enable)) > goto end_session; > bytes_per_datum = 0; > > But there is another fifo, temp_fifo > > if (st->chip_config.temp_fifo_enable) > bytes_per_datum += INV_MPU6050_BYTES_PER_TEMP_SENSOR; > > Which would be skipped if it was the only enabled fifo. > So add to the check. > > Fixes: 2e4c0a5e2576 ("iio: imu: inv_mpu6050: add fifo temperature data > support") > > Signed-off-by: Tom Rix There shouldn't be a blank line in between. Other than that, Reviewed-by: Andy Shevchenko > --- > drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c > b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c > index b533fa2dad0a..5240a400dcb4 100644 > --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c > +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c > @@ -141,6 +141,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) > > if (!(st->chip_config.accl_fifo_enable | > st->chip_config.gyro_fifo_enable | > + st->chip_config.temp_fifo_enable | > st->chip_config.magn_fifo_enable)) > goto end_session; > bytes_per_datum = 0; > -- > 2.18.1 > -- With Best Regards, Andy Shevchenko
[PATCH v4 09/13] iio: imu: inv_icm42600: add device interrupt
Add INT1 interrupt support. Support interrupt edge and level, active high or low. Push-pull or open-drain configurations. Interrupt will be used to read data from the FIFO. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 2 +- .../iio/imu/inv_icm42600/inv_icm42600_core.c | 101 +- .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 3 +- .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 3 +- 4 files changed, 105 insertions(+), 4 deletions(-) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 3b190461a2b6..148894c888cc 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -372,7 +372,7 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable, int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval); -int inv_icm42600_core_probe(struct regmap *regmap, int chip, +int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, inv_icm42600_bus_setup bus_setup); struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index a35ff21f50bb..95b2a6d91e5b 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -9,8 +9,11 @@ #include #include #include +#include +#include #include #include +#include #include #include @@ -408,6 +411,82 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st, return inv_icm42600_set_conf(st, hw->conf); } +static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data) +{ + struct inv_icm42600_state *st = _data; + struct device *dev = regmap_get_device(st->map); + unsigned int status; + int ret; + + mutex_lock(>lock); + + ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, ); + if (ret) + goto out_unlock; + + /* FIFO full */ + if (status & INV_ICM42600_INT_STATUS_FIFO_FULL) + dev_warn(dev, "FIFO full data lost!\n"); + +out_unlock: + mutex_unlock(>lock); + return IRQ_HANDLED; +} + +/** + * inv_icm42600_irq_init() - initialize int pin and interrupt handler + * @st:driver internal state + * @irq: irq number + * @irq_type: irq trigger type + * @open_drain:true if irq is open drain, false for push-pull + * + * Returns 0 on success, a negative error code otherwise. + */ +static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq, +int irq_type, bool open_drain) +{ + struct device *dev = regmap_get_device(st->map); + unsigned int val; + int ret; + + /* configure INT1 interrupt: default is active low on edge */ + switch (irq_type) { + case IRQF_TRIGGER_RISING: + case IRQF_TRIGGER_HIGH: + val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH; + break; + default: + val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW; + break; + } + + switch (irq_type) { + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_HIGH: + val |= INV_ICM42600_INT_CONFIG_INT1_LATCHED; + break; + default: + break; + } + + if (!open_drain) + val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL; + + ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val); + if (ret) + return ret; + + /* Deassert async reset for proper INT pin operation (cf datasheet) */ + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1, +INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0); + if (ret) + return ret; + + return devm_request_threaded_irq(dev, irq, NULL, +inv_icm42600_irq_handler, irq_type, +"inv_icm42600", st); +} + static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st) { int ret; @@ -452,11 +531,14 @@ static void inv_icm42600_disable_pm(void *_data) pm_runtime_disable(dev); } -int inv_icm42600_core_probe(struct regmap *regmap, int chip, +int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, inv_icm42600_bus_setup bus_setup) { struct device *dev = regmap_get_device(regmap); struct inv_icm42600_state *st; + struct irq_data *irq_desc; + int irq_type; + bool open_drain; int ret; if (chip < 0 || chip >= INV_CHIP_NB) { @@ -464,6 +546,19 @@ int inv_icm42600_core_probe(struct reg
[PATCH v4 04/13] iio: imu: inv_icm42600: add gyroscope IIO device
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 --- 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 | 603 ++ 3 files changed, 613 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..d155470d770a 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); +struct iio_dev *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 2eb25c5f77f8..84e9ff320b3b 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -509,6 +509,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, if (ret) return ret; + st->indio_gyro = inv_icm42600_gyro_init(st); + if (IS_ERR(st->indio_gyro)) + return PTR_ERR(st->indio_gyro); + /* 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 ..3875ecbee67e --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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_icm4
[PATCH v4 05/13] iio: imu: inv_icm42600: add accelerometer IIO device
Add IIO device for accelerometer sensor with data polling interface. Attributes: raw, scale, sampling_frequency, calibbias. Accelerometer in low noise mode. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 4 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 592 ++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 4 + 3 files changed, 600 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index d155470d770a..3b190461a2b6 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -121,6 +121,7 @@ struct inv_icm42600_suspended { * @conf: chip sensors configurations. * @suspended:suspended sensors configuration. * @indio_gyro: gyroscope IIO device. + * @indio_accel: accelerometer IIO device. * @buffer: data transfer buffer aligned for DMA. */ struct inv_icm42600_state { @@ -134,6 +135,7 @@ struct inv_icm42600_state { struct inv_icm42600_conf conf; struct inv_icm42600_suspended suspended; struct iio_dev *indio_gyro; + struct iio_dev *indio_accel; uint8_t buffer[2] cacheline_aligned; }; @@ -375,4 +377,6 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st); +struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st); + #endif diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c new file mode 100644 index ..717c6b0869fc --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -0,0 +1,592 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +#define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ + { \ + .type = IIO_ACCEL, \ + .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_accel_scan { + INV_ICM42600_ACCEL_SCAN_X, + INV_ICM42600_ACCEL_SCAN_Y, + INV_ICM42600_ACCEL_SCAN_Z, +}; + +static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42600_get_mount_matrix), + {}, +}; + +static const struct iio_chan_spec inv_icm42600_accel_channels[] = { + INV_ICM42600_ACCEL_CHAN(IIO_MOD_X, INV_ICM42600_ACCEL_SCAN_X, + inv_icm42600_accel_ext_infos), + INV_ICM42600_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42600_ACCEL_SCAN_Y, + inv_icm42600_accel_ext_infos), + INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, + inv_icm42600_accel_ext_infos), +}; + +static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st, + struct iio_chan_spec const *chan, + int16_t *val) +{ + struct device *dev = regmap_get_devi
[PATCH v4 13/13] MAINTAINERS: add entry for inv_icm42600 6-axis imu sensor
Add MAINTAINERS entry for InvenSense ICM-426xx IMU device. Signed-off-by: Jean-Baptiste Maneyrol --- MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 510fa7f7c756..a65771cfc506 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8979,6 +8979,14 @@ F: include/dt-bindings/interconnect/ F: include/linux/interconnect-provider.h F: include/linux/interconnect.h +INVENSENSE ICM-426xx IMU DRIVER +M: Jean-Baptiste Maneyrol +L: linux-...@vger.kernel.org +S: Maintained +W https://invensense.tdk.com/ +F: Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +F: drivers/iio/imu/inv_icm42600/ + INVENSENSE MPU-3050 GYROSCOPE DRIVER M: Linus Walleij L: linux-...@vger.kernel.org -- 2.17.1
[PATCH v4 08/13] Documentation: ABI: add specific icm42600 documentation
Hardware offset available as calibscale sysfs attributes are real physical values exprimed in SI units. calibscale_available sysfs attributes represents the range of acceptable values. Signed-off-by: Jean-Baptiste Maneyrol --- .../ABI/testing/sysfs-bus-iio-icm42600| 20 +++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-icm42600 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-icm42600 b/Documentation/ABI/testing/sysfs-bus-iio-icm42600 new file mode 100644 index ..0bf1fd4f5bf1 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-icm42600 @@ -0,0 +1,20 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias +KernelVersion: 5.8 +Contact:linux-...@vger.kernel.org +Description: + Hardware applied calibration offset (assumed to fix production + inaccuracies). Values represent a real physical offset expressed + in SI units (m/s^2 for accelerometer and rad/s for gyroscope). + +What: /sys/bus/iio/devices/iio:deviceX/in_accel_calibbias_available +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_calibbias_available +KernelVersion: 5.8 +Contact:linux-...@vger.kernel.org +Description: + Range of available values for hardware offset. Values in SI + units (m/s^2 for accelerometer and rad/s for gyroscope). -- 2.17.1
[PATCH v4 06/13] iio: imu: inv_icm42600: add temperature sensor support
Add temperature channel in gyroscope and accelerometer devices. Temperature is available in full 16 bits resolution when reading register and in low 8 bits resolution in the FIFO. Return full precision raw temperature with corresponding scale and offset. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 11 ++- .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 11 ++- .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 84 +++ .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 30 +++ 4 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 717c6b0869fc..3f214df44093 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -13,6 +13,7 @@ #include #include "inv_icm42600.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -45,6 +46,7 @@ enum inv_icm42600_accel_scan { INV_ICM42600_ACCEL_SCAN_X, INV_ICM42600_ACCEL_SCAN_Y, INV_ICM42600_ACCEL_SCAN_Z, + INV_ICM42600_ACCEL_SCAN_TEMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { @@ -59,6 +61,7 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { inv_icm42600_accel_ext_infos), INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, inv_icm42600_accel_ext_infos), + INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), }; static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st, @@ -450,8 +453,14 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev, int16_t data; int ret; - if (chan->type != IIO_ACCEL) + switch (chan->type) { + case IIO_ACCEL: + break; + case IIO_TEMP: + return inv_icm42600_temp_read_raw(indio_dev, chan, val, val2, mask); + default: return -EINVAL; + } switch (mask) { case IIO_CHAN_INFO_RAW: diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index 3875ecbee67e..6a0e7661fa48 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -13,6 +13,7 @@ #include #include "inv_icm42600.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \ { \ @@ -45,6 +46,7 @@ enum inv_icm42600_gyro_scan { INV_ICM42600_GYRO_SCAN_X, INV_ICM42600_GYRO_SCAN_Y, INV_ICM42600_GYRO_SCAN_Z, + INV_ICM42600_GYRO_SCAN_TEMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_gyro_ext_infos[] = { @@ -59,6 +61,7 @@ static const struct iio_chan_spec inv_icm42600_gyro_channels[] = { inv_icm42600_gyro_ext_infos), INV_ICM42600_GYRO_CHAN(IIO_MOD_Z, INV_ICM42600_GYRO_SCAN_Z, inv_icm42600_gyro_ext_infos), + INV_ICM42600_TEMP_CHAN(INV_ICM42600_GYRO_SCAN_TEMP), }; static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st, @@ -461,8 +464,14 @@ static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev, int16_t data; int ret; - if (chan->type != IIO_ANGL_VEL) + switch (chan->type) { + case IIO_ANGL_VEL: + break; + case IIO_TEMP: + return inv_icm42600_temp_read_raw(indio_dev, chan, val, val2, mask); + default: return -EINVAL; + } switch (mask) { case IIO_CHAN_INFO_RAW: diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c new file mode 100644 index ..213cce1c3111 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" +#include "inv_icm42600_temp.h" + +static int inv_icm42600_temp_read(struct inv_icm42600_state *st, int16_t *temp) +{ + struct device *dev = regmap_get_device(st->map); + __be16 *raw; + int ret; + + pm_runtime_get_sync(dev); + mutex_lock(>lock); + + ret = inv_icm42600_set_temp_conf(st, true, NULL); + if (ret) + goto exit
[PATCH v4 11/13] iio: imu: inv_icm42600: add accurate timestamping
Add a timestamping mechanism for buffer that provides accurate event timestamps when using watermark. This mechanism estimates device internal clock by comparing FIFO interrupts delta time and device elapsed time computed by parsing FIFO data. Take interrupt timestamp in hard irq handler and add IIO device specific timestamp structures in device private allocation. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/Makefile | 1 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 5 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 40 +++- .../imu/inv_icm42600/inv_icm42600_buffer.c| 28 +++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 17 +- .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 40 +++- .../imu/inv_icm42600/inv_icm42600_timestamp.c | 195 ++ .../imu/inv_icm42600/inv_icm42600_timestamp.h | 85 8 files changed, 396 insertions(+), 15 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.h diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile index 0f49f6df3647..291714d9aa54 100644 --- a/drivers/iio/imu/inv_icm42600/Makefile +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -6,6 +6,7 @@ inv-icm42600-y += inv_icm42600_gyro.o inv-icm42600-y += inv_icm42600_accel.o inv-icm42600-y += inv_icm42600_temp.o inv-icm42600-y += inv_icm42600_buffer.o +inv-icm42600-y += inv_icm42600_timestamp.o obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o inv-icm42600-i2c-y += inv_icm42600_i2c.o diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 7b52d92739c3..c0f5059b13b3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -126,6 +126,7 @@ struct inv_icm42600_suspended { * @indio_accel: accelerometer IIO device. * @buffer: data transfer buffer aligned for DMA. * @fifo: FIFO management structure. + * @timestamp:interrupt timestamps. */ struct inv_icm42600_state { struct mutex lock; @@ -141,6 +142,10 @@ struct inv_icm42600_state { struct iio_dev *indio_accel; uint8_t buffer[2] cacheline_aligned; struct inv_icm42600_fifo fifo; + struct { + int64_t gyro; + int64_t accel; + } timestamp; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index fbc029bd6e72..3441b0d61c5d 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -17,6 +17,7 @@ #include "inv_icm42600.h" #include "inv_icm42600_temp.h" #include "inv_icm42600_buffer.h" +#include "inv_icm42600_timestamp.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -50,6 +51,7 @@ enum inv_icm42600_accel_scan { INV_ICM42600_ACCEL_SCAN_Y, INV_ICM42600_ACCEL_SCAN_Z, INV_ICM42600_ACCEL_SCAN_TEMP, + INV_ICM42600_ACCEL_SCAN_TIMESTAMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { @@ -65,15 +67,17 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, inv_icm42600_accel_ext_infos), INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), + IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42600_ACCEL_SCAN_TIMESTAMP), }; /* - * IIO buffer data: size must be a power of 2 - * 8 bytes: 6 bytes acceleration and 2 bytes temperature + * IIO buffer data: size must be a power of 2 and timestamp aligned + * 16 bytes: 6 bytes acceleration, 2 bytes temperature, 8 bytes timestamp */ struct inv_icm42600_accel_buffer { struct inv_icm42600_fifo_sensor_data accel; int16_t temp; + int64_t timestamp __aligned(8); }; #define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \ @@ -94,6 +98,7 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_timestamp *ts = iio_priv(indio_dev); struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; unsigned int fifo_en = 0; unsigned int sleep_temp = 0; @@ -121,6 +126,7 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, } /* update data FIFO write */ + inv_icm42600_timestamp_apply_odr(ts, 0, 0, 0); ret = inv_icm42600_buff
[PATCH v4 10/13] iio: imu: inv_icm42600: add buffer support in iio devices
Add all FIFO parsing and reading functions. Add accel and gyro kfifo buffer and FIFO data parsing. Use device interrupt for reading data FIFO and launching accel and gyro parsing. Support hwfifo watermark by multiplexing gyro and accel settings. Support hwfifo flush. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/Kconfig | 1 + drivers/iio/imu/inv_icm42600/Makefile | 1 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 162 - .../imu/inv_icm42600/inv_icm42600_buffer.c| 573 ++ .../imu/inv_icm42600/inv_icm42600_buffer.h| 98 +++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 30 + .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 162 - 8 files changed, 1033 insertions(+), 2 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig index 22390a72f0a3..50cbcfcb6cf1 100644 --- a/drivers/iio/imu/inv_icm42600/Kconfig +++ b/drivers/iio/imu/inv_icm42600/Kconfig @@ -2,6 +2,7 @@ config INV_ICM42600 tristate + select IIO_BUFFER config INV_ICM42600_I2C tristate "InvenSense ICM-426xx I2C driver" diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile index 48965824f00c..0f49f6df3647 100644 --- a/drivers/iio/imu/inv_icm42600/Makefile +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -5,6 +5,7 @@ inv-icm42600-y += inv_icm42600_core.o inv-icm42600-y += inv_icm42600_gyro.o inv-icm42600-y += inv_icm42600_accel.o inv-icm42600-y += inv_icm42600_temp.o +inv-icm42600-y += inv_icm42600_buffer.o obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o inv-icm42600-i2c-y += inv_icm42600_i2c.o diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 148894c888cc..7b52d92739c3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -14,6 +14,8 @@ #include #include +#include "inv_icm42600_buffer.h" + enum inv_icm42600_chip { INV_CHIP_ICM42600, INV_CHIP_ICM42602, @@ -123,6 +125,7 @@ struct inv_icm42600_suspended { * @indio_gyro: gyroscope IIO device. * @indio_accel: accelerometer IIO device. * @buffer: data transfer buffer aligned for DMA. + * @fifo: FIFO management structure. */ struct inv_icm42600_state { struct mutex lock; @@ -137,6 +140,7 @@ struct inv_icm42600_state { struct iio_dev *indio_gyro; struct iio_dev *indio_accel; uint8_t buffer[2] cacheline_aligned; + struct inv_icm42600_fifo fifo; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ @@ -377,6 +381,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st); +int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev); + struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st); +int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev); + #endif diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 3f214df44093..fbc029bd6e72 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -11,9 +11,12 @@ #include #include #include +#include +#include #include "inv_icm42600.h" #include "inv_icm42600_temp.h" +#include "inv_icm42600_buffer.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -64,6 +67,78 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), }; +/* + * IIO buffer data: size must be a power of 2 + * 8 bytes: 6 bytes acceleration and 2 bytes temperature + */ +struct inv_icm42600_accel_buffer { + struct inv_icm42600_fifo_sensor_data accel; + int16_t temp; +}; + +#define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \ + (BIT(INV_ICM42600_ACCEL_SCAN_X) | \ + BIT(INV_ICM42600_ACCEL_SCAN_Y) |\ + BIT(INV_ICM42600_ACCEL_SCAN_Z)) + +#define INV_ICM42600_SCAN_MASK_TEMPBIT(INV_ICM42600_ACCEL_SCAN_TEMP) + +static const unsigned long inv_icm42600_accel_scan_masks[] = { + /* 3-axis accel + temperature */ + INV_ICM42600_SCAN_MASK_ACCEL_3AXIS | INV_ICM42600_SCAN_MASK_TEMP, + 0, +}; + +/* enable accelerometer sensor and FIFO write */ +static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, +
[PATCH v4 01/13] iio: imu: inv_icm42600: add core of new inv_icm42600 driver
Core component of a new driver for InvenSense ICM-426xx devices. It includes registers definition, main probe/setup, and device utility functions. ICM-426xx devices are latest generation of 6-axis IMU, gyroscope+accelerometer and temperature sensor. This device includes a 2K FIFO, supports I2C/I3C/SPI, and provides intelligent motion features like pedometer, tilt detection, and tap detection. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 372 ++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 634 ++ 2 files changed, 1006 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h new file mode 100644 index ..14c8ef152418 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#ifndef INV_ICM42600_H_ +#define INV_ICM42600_H_ + +#include +#include +#include +#include +#include +#include +#include + +enum inv_icm42600_chip { + INV_CHIP_ICM42600, + INV_CHIP_ICM42602, + INV_CHIP_ICM42605, + INV_CHIP_ICM42622, + INV_CHIP_NB, +}; + +/* serial bus slew rates */ +enum inv_icm42600_slew_rate { + INV_ICM42600_SLEW_RATE_20_60NS, + INV_ICM42600_SLEW_RATE_12_36NS, + INV_ICM42600_SLEW_RATE_6_18NS, + INV_ICM42600_SLEW_RATE_4_12NS, + INV_ICM42600_SLEW_RATE_2_6NS, + INV_ICM42600_SLEW_RATE_INF_2NS, +}; + +enum inv_icm42600_sensor_mode { + INV_ICM42600_SENSOR_MODE_OFF, + INV_ICM42600_SENSOR_MODE_STANDBY, + INV_ICM42600_SENSOR_MODE_LOW_POWER, + INV_ICM42600_SENSOR_MODE_LOW_NOISE, + INV_ICM42600_SENSOR_MODE_NB, +}; + +/* gyroscope fullscale values */ +enum inv_icm42600_gyro_fs { + INV_ICM42600_GYRO_FS_2000DPS, + INV_ICM42600_GYRO_FS_1000DPS, + INV_ICM42600_GYRO_FS_500DPS, + INV_ICM42600_GYRO_FS_250DPS, + INV_ICM42600_GYRO_FS_125DPS, + INV_ICM42600_GYRO_FS_62_5DPS, + INV_ICM42600_GYRO_FS_31_25DPS, + INV_ICM42600_GYRO_FS_15_625DPS, + INV_ICM42600_GYRO_FS_NB, +}; + +/* accelerometer fullscale values */ +enum inv_icm42600_accel_fs { + INV_ICM42600_ACCEL_FS_16G, + INV_ICM42600_ACCEL_FS_8G, + INV_ICM42600_ACCEL_FS_4G, + INV_ICM42600_ACCEL_FS_2G, + INV_ICM42600_ACCEL_FS_NB, +}; + +/* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */ +enum inv_icm42600_odr { + INV_ICM42600_ODR_8KHZ_LN = 3, + INV_ICM42600_ODR_4KHZ_LN, + INV_ICM42600_ODR_2KHZ_LN, + INV_ICM42600_ODR_1KHZ_LN, + INV_ICM42600_ODR_200HZ, + INV_ICM42600_ODR_100HZ, + INV_ICM42600_ODR_50HZ, + INV_ICM42600_ODR_25HZ, + INV_ICM42600_ODR_12_5HZ, + INV_ICM42600_ODR_6_25HZ_LP, + INV_ICM42600_ODR_3_125HZ_LP, + INV_ICM42600_ODR_1_5625HZ_LP, + INV_ICM42600_ODR_500HZ, + INV_ICM42600_ODR_NB, +}; + +enum inv_icm42600_filter { + /* Low-Noise mode sensor data filter (3rd order filter by default) */ + INV_ICM42600_FILTER_BW_ODR_DIV_2, + + /* Low-Power mode sensor data filter (averaging) */ + INV_ICM42600_FILTER_AVG_1X = 1, + INV_ICM42600_FILTER_AVG_16X = 6, +}; + +struct inv_icm42600_sensor_conf { + int mode; + int fs; + int odr; + int filter; +}; +#define INV_ICM42600_SENSOR_CONF_INIT {-1, -1, -1, -1} + +struct inv_icm42600_conf { + struct inv_icm42600_sensor_conf gyro; + struct inv_icm42600_sensor_conf accel; + bool temp_en; +}; + +struct inv_icm42600_suspended { + enum inv_icm42600_sensor_mode gyro; + enum inv_icm42600_sensor_mode accel; + bool temp; +}; + +/** + * struct inv_icm42600_state - driver state variables + * @lock: lock for serializing multiple registers access. + * @chip: chip identifier. + * @name: chip name. + * @map: regmap pointer. + * @vdd_supply: VDD voltage regulator for the chip. + * @vddio_supply: I/O voltage regulator for the chip. + * @orientation: sensor chip orientation relative to main hardware. + * @conf: chip sensors configurations. + * @suspended:suspended sensors configuration. + */ +struct inv_icm42600_state { + struct mutex lock; + enum inv_icm42600_chip chip; + const char *name; + struct regmap *map; + struct regulator *vdd_supply; + struct regulator *vddio_supply; + struct iio_mount_matrix orientation; + struct inv_icm42600_conf conf; + struct inv_icm42600_suspended suspended; +}; + +/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ + +/* Bank selection register, available in all banks */ +#define
[PATCH v4 12/13] dt-bindings: iio: imu: Add inv_icm42600 documentation
Document the ICM-426xxx devices devicetree bindings. Signed-off-by: Jean-Baptiste Maneyrol --- .../bindings/iio/imu/invensense,icm42600.yaml | 90 +++ 1 file changed, 90 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml new file mode 100644 index ..abd8d25e1136 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/imu/invensense,icm42600.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: InvenSense ICM-426xx Inertial Measurement Unit + +maintainers: + - Jean-Baptiste Maneyrol + +description: | + 6-axis MotionTracking device that combines a 3-axis gyroscope and a 3-axis + accelerometer. + + It has a configurable host interface that supports I3C, I2C and SPI serial + communication, features a 2kB FIFO and 2 programmable interrupts with + ultra-low-power wake-on-motion support to minimize system power consumption. + + Other industry-leading features include InvenSense on-chip APEX Motion + Processing engine for gesture recognition, activity classification, and + pedometer, along with programmable digital filters, and an embedded + temperature sensor. + + https://invensense.tdk.com/wp-content/uploads/2020/03/DS-000292-ICM-42605-v1.4.pdf + +properties: + compatible: +enum: + - invensense,icm42600 + - invensense,icm42602 + - invensense,icm42605 + - invensense,icm42622 + + reg: +maxItems: 1 + + interrupts: +maxItems: 1 + + drive-open-drain: +type: boolean + + vdd-supply: +description: Regulator that provides power to the sensor + + vddio-supply: +description: Regulator that provides power to the bus + +required: + - compatible + - reg + - interrupts + +examples: + - | +#include +#include +i2c0 { +#address-cells = <1>; +#size-cells = <0>; + +icm42605@68 { + compatible = "invensense,icm42605"; + reg = <0x68>; + interrupt-parent = <>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <>; + vddio-supply = <>; +}; +}; + - | +#include +#include +spi0 { +#address-cells = <1>; +#size-cells = <0>; + +icm42602@0 { + compatible = "invensense,icm42602"; + reg = <0>; + spi-max-frequency = <2400>; + spi-cpha; + spi-cpol; + interrupt-parent = <>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <>; + vddio-supply = <>; +}; +}; -- 2.17.1
[PATCH v4 07/13] iio: imu: add Kconfig and Makefile for inv_icm42600 driver
Add 3 modules: inv-icm42600, inv-icm42600-i2c, inv-icm42600-spi. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42600/Kconfig | 28 +++ drivers/iio/imu/inv_icm42600/Makefile | 13 + 4 files changed, 43 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/Kconfig create mode 100644 drivers/iio/imu/inv_icm42600/Makefile diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index fc4123d518bc..f02883b08480 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -91,6 +91,7 @@ config KMX61 To compile this driver as module, choose M here: the module will be called kmx61. +source "drivers/iio/imu/inv_icm42600/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" source "drivers/iio/imu/st_lsm6dsx/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 88b2c4555230..13e9ff442b11 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_FXOS8700) += fxos8700_core.o obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o +obj-y += inv_icm42600/ obj-y += inv_mpu6050/ obj-$(CONFIG_KMX61) += kmx61.o diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig new file mode 100644 index ..22390a72f0a3 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/Kconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config INV_ICM42600 + tristate + +config INV_ICM42600_I2C + tristate "InvenSense ICM-426xx I2C driver" + depends on I2C + select INV_ICM42600 + select REGMAP_I2C + help + This driver supports the InvenSense ICM-426xx motion tracking + devices over I2C. + + This driver can be built as a module. The module will be called + inv-icm42600-i2c. + +config INV_ICM42600_SPI + tristate "InvenSense ICM-426xx SPI driver" + depends on SPI_MASTER + select INV_ICM42600 + select REGMAP_SPI + help + This driver supports the InvenSense ICM-426xx motion tracking + devices over SPI. + + This driver can be built as a module. The module will be called + inv-icm42600-spi. diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile new file mode 100644 index ..48965824f00c --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-$(CONFIG_INV_ICM42600) += inv-icm42600.o +inv-icm42600-y += inv_icm42600_core.o +inv-icm42600-y += inv_icm42600_gyro.o +inv-icm42600-y += inv_icm42600_accel.o +inv-icm42600-y += inv_icm42600_temp.o + +obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o +inv-icm42600-i2c-y += inv_icm42600_i2c.o + +obj-$(CONFIG_INV_ICM42600_SPI) += inv-icm42600-spi.o +inv-icm42600-spi-y += inv_icm42600_spi.o -- 2.17.1
[PATCH v4 03/13] iio: imu: inv_icm42600: add SPI driver for inv_icm42600 driver
Add SPI driver for InvenSense ICM-426xxx devices. Configure bus signal slew rates as indicated in the datasheet. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 99 +++ 1 file changed, 99 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c new file mode 100644 index ..a9c5e2fdbe2a --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 InvenSense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +static int inv_icm42600_spi_bus_setup(struct inv_icm42600_state *st) +{ + unsigned int mask, val; + int ret; + + /* setup interface registers */ + val = INV_ICM42600_INTF_CONFIG6_I3C_EN | + INV_ICM42600_INTF_CONFIG6_I3C_SDR_EN | + INV_ICM42600_INTF_CONFIG6_I3C_DDR_EN; + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6, +INV_ICM42600_INTF_CONFIG6_MASK, val); + if (ret) + return ret; + + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, +INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0); + if (ret) + return ret; + + /* set slew rates for I2C and SPI */ + mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK | + INV_ICM42600_DRIVE_CONFIG_SPI_MASK; + val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_20_60NS) | + INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_INF_2NS); + ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG, +mask, val); + if (ret) + return ret; + + /* disable i2c bus */ + return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS); +} + +static int inv_icm42600_probe(struct spi_device *spi) +{ + const void *match; + enum inv_icm42600_chip chip; + struct regmap *regmap; + + match = device_get_match_data(>dev); + if (!match) + return -EINVAL; + chip = (enum inv_icm42600_chip)match; + + regmap = devm_regmap_init_spi(spi, _icm42600_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return inv_icm42600_core_probe(regmap, chip, inv_icm42600_spi_bus_setup); +} + +static const struct of_device_id inv_icm42600_of_matches[] = { + { + .compatible = "invensense,icm42600", + .data = (void *)INV_CHIP_ICM42600, + }, { + .compatible = "invensense,icm42602", + .data = (void *)INV_CHIP_ICM42602, + }, { + .compatible = "invensense,icm42605", + .data = (void *)INV_CHIP_ICM42605, + }, { + .compatible = "invensense,icm42622", + .data = (void *)INV_CHIP_ICM42622, + }, + {} +}; +MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); + +static struct spi_driver inv_icm42600_driver = { + .driver = { + .name = "inv-icm42600-spi", + .of_match_table = inv_icm42600_of_matches, + .pm = _icm42600_pm_ops, + }, + .probe = inv_icm42600_probe, +}; +module_spi_driver(inv_icm42600_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-426xx SPI driver"); +MODULE_LICENSE("GPL"); -- 2.17.1
[PATCH v4 02/13] iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver
Add I2C driver for InvenSense ICM-426xxx devices. Configure bus signal slew rates as indicated in the datasheet. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 100 ++ 1 file changed, 100 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c new file mode 100644 index ..4789cead23b3 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 InvenSense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st) +{ + unsigned int mask, val; + int ret; + + /* setup interface registers */ + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6, +INV_ICM42600_INTF_CONFIG6_MASK, +INV_ICM42600_INTF_CONFIG6_I3C_EN); + if (ret) + return ret; + + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, +INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0); + if (ret) + return ret; + + /* set slew rates for I2C and SPI */ + mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK | + INV_ICM42600_DRIVE_CONFIG_SPI_MASK; + val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_12_36NS) | + INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_12_36NS); + ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG, +mask, val); + if (ret) + return ret; + + /* disable SPI bus */ + return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS); +} + +static int inv_icm42600_probe(struct i2c_client *client) +{ + const void *match; + enum inv_icm42600_chip chip; + struct regmap *regmap; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENOTSUPP; + + match = device_get_match_data(>dev); + if (!match) + return -EINVAL; + chip = (enum inv_icm42600_chip)match; + + regmap = devm_regmap_init_i2c(client, _icm42600_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return inv_icm42600_core_probe(regmap, chip, inv_icm42600_i2c_bus_setup); +} + +static const struct of_device_id inv_icm42600_of_matches[] = { + { + .compatible = "invensense,icm42600", + .data = (void *)INV_CHIP_ICM42600, + }, { + .compatible = "invensense,icm42602", + .data = (void *)INV_CHIP_ICM42602, + }, { + .compatible = "invensense,icm42605", + .data = (void *)INV_CHIP_ICM42605, + }, { + .compatible = "invensense,icm42622", + .data = (void *)INV_CHIP_ICM42622, + }, + {} +}; +MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); + +static struct i2c_driver inv_icm42600_driver = { + .driver = { + .name = "inv-icm42600-i2c", + .of_match_table = inv_icm42600_of_matches, + .pm = _icm42600_pm_ops, + }, + .probe_new = inv_icm42600_probe, +}; +module_i2c_driver(inv_icm42600_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-426xx I2C driver"); +MODULE_LICENSE("GPL"); -- 2.17.1
[PATCH v4 00/13] iio: imu: new inv_icm42600 driver
Changelog v1 -initial patch submission v2 - formatting reworks, missing headers, code cleanup ... - delete all debug traces - add commentaries for better explanation of suspend/resume, timestamp, ... - delete i2c/spi table ids keeping only of, and use I2C probe_new function - switch calibbias to SI units and add calibias_available attribute - use DMA-safe buffer for all regmap_bulk_* calls - delete iio trigger usage and setup/handle interrupt in core module - add open-drain interrupt support - add FIFO on reference counter and buffer postenable/predisable to replace iio trigger usage - check that temperature data is present before copying in buffer - add temperature sensor off when fifo is turned off - delete timestamp channel reading - move timestamp state in IIO device private data - allow only 1 ODR change in a batch of data - add driver-open-drain in devicetree YAML and delete spi options v3 - delete const pointer cast for iio_device_get_drvdata - change gyro and accel init to return the allocated iio_dev structure - delete manual parent device assignment - correct style and improve readability - add commentaries about IIO buffer and watermark complex computation - add timestamp alignment in IIO buffer structure - wrap lines 80 columns for dt bindings - add ABI documentation for calibbias values in SI units v4 - return high resolution 16 bits temperature as raw data when polled with the corresponding scale and offset. - for data buffer return temperature in the same 16 bits using the same scale and offset. Convert low resolution temperature FIFO data to high resolution format. - explicitely zero out data buffer before copying to iio buffer. This series add a new driver for managing InvenSense ICM-426xx 6-axis IMUs. This next generation of chips includes new generations of 3-axis gyroscope and 3-axis accelerometer, support of I3C in addition to I2C and SPI, and intelligent MotionTracking features like pedometer, tilt detection, and tap detection. This series is delivering a driver supporting gyroscope, accelerometer and temperature data, with polling and buffering using hwfifo and watermark, on I2C and SPI busses. Gyroscope and accelerometer sensors are completely independent and can have different ODRs. Since there is only a single FIFO a specific value is used to mark invalid data. For keeping the device standard we are de-multiplexing data from the FIFO to 2 IIO devices with 2 buffers, 1 for the accelerometer and 1 for the gyroscope. This architecture also enables to easily turn each sensor on/off without impacting the other. The device interrupt is used to read the FIFO and launch parsing of accelerometer and gyroscope data. A complex timestamping mechanism is added to handle correctly FIFO watermark and dynamic changes of settings. Jean-Baptiste Maneyrol (13): iio: imu: inv_icm42600: add core of new inv_icm42600 driver iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver iio: imu: inv_icm42600: add SPI driver for inv_icm42600 driver iio: imu: inv_icm42600: add gyroscope IIO device iio: imu: inv_icm42600: add accelerometer IIO device iio: imu: inv_icm42600: add temperature sensor support iio: imu: add Kconfig and Makefile for inv_icm42600 driver Documentation: ABI: add specific icm42600 documentation iio: imu: inv_icm42600: add device interrupt iio: imu: inv_icm42600: add buffer support in iio devices iio: imu: inv_icm42600: add accurate timestamping dt-bindings: iio: imu: Add inv_icm42600 documentation MAINTAINERS: add entry for inv_icm42600 6-axis imu sensor .../ABI/testing/sysfs-bus-iio-icm42600| 20 + .../bindings/iio/imu/invensense,icm42600.yaml | 90 ++ MAINTAINERS | 8 + drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42600/Kconfig | 29 + drivers/iio/imu/inv_icm42600/Makefile | 15 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 395 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 787 + .../imu/inv_icm42600/inv_icm42600_buffer.c| 601 + .../imu/inv_icm42600/inv_icm42600_buffer.h| 98 +++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 786 + .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 798 ++ .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 101 +++ .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 100 +++ .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 84 ++ .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 30 + .../imu/inv_icm42600/inv_icm42600_timestamp.c | 195 + .../imu/inv_icm42600/inv_icm42600_timestamp.h | 85 ++ 19 files changed, 4224 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-icm42600 create mode 100644 Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml create mode 100644 drivers/iio
Re: [PATCH v3 06/13] iio: imu: inv_icm42600: add temperature sensor support
Hi Jonathan, no problem, I can rework temperature to have the same raw output for both cases (with just decreased resolution for the FIFO case). v4 series is coming soon with the fix. Thanks, JB From: Jonathan Cameron Sent: Saturday, June 20, 2020 17:57 To: Jean-Baptiste Maneyrol Cc: Lars-Peter Clausen ; robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH v3 06/13] iio: imu: inv_icm42600: add temperature sensor support 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 Sun, 14 Jun 2020 20:35:13 + Jean-Baptiste Maneyrol wrote: > Hello Lars, > > for the temperature data, the problem is that temperature in the FIFO (used > in buffer) is not in the same format than when reading the register. > > Reading the temperature register return a full precision value on 16 bits. I > am using a PROCESSED attribute for it. > Temperature data in buffer (coming from the FIFO) is on 8 bits in lower > precision. It is reported as raw data, thus the need of the offset and scale > values. > > So offset and scale values are only for transforming the temperature data > from the buffer, and direct read is a full precision already processed in m°C. That is a problem. We have no means of describing it in IIO. If the channel is processed via sysfs the assumption would normally be that it is processed in the buffer as well. We don't really have any means of describing the two separately. In cases where we've seen this before the way around it was to change the data in the fifo so that the scaling was the same as the sysfs channel (usually it's just a bit of padding). Can we do that here? Looks like the ratio is 1:64 so should be possible. > > Thanks for the review, > JB > > From: Lars-Peter Clausen > Sent: Sunday, June 14, 2020 17:10 > To: Jean-Baptiste Maneyrol ; ji...@kernel.org > ; robh...@kernel.org ; r...@kernel.org > ; mchehab+hua...@kernel.org ; > da...@davemloft.net ; gre...@linuxfoundation.org > > Cc: linux-...@vger.kernel.org ; > devicet...@vger.kernel.org ; > linux-kernel@vger.kernel.org > Subject: Re: [PATCH v3 06/13] iio: imu: inv_icm42600: add temperature sensor > support > > 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 6/8/20 10:42 PM, Jean-Baptiste Maneyrol wrote: > > + case IIO_CHAN_INFO_PROCESSED: > > + ret = iio_device_claim_direct_mode(indio_dev); > > + if (ret) > > + return ret; > > + ret = inv_icm42600_temp_read(st, ); > > + iio_device_release_direct_mode(indio_dev); > > + if (ret) > > + return ret; > > + *val = temp; > > + return IIO_VAL_INT; > > + case IIO_CHAN_INFO_SCALE: > > + *val = 483; > > + *val2 = 91787; > > + return IIO_VAL_INT_PLUS_MICRO; > > + case IIO_CHAN_INFO_OFFSET: > > + *val = 25000; > > + return IIO_VAL_INT; > > If the data is returned processed there is no need to specify scale and > offset. > > But since the transformation to turn the data into standard units is a > simple linear transform the preferred way to handle this is to return > RAW data and specify scale and offset.
Re: [PATCH v3 06/13] iio: imu: inv_icm42600: add temperature sensor support
Hello Lars, for the temperature data, the problem is that temperature in the FIFO (used in buffer) is not in the same format than when reading the register. Reading the temperature register return a full precision value on 16 bits. I am using a PROCESSED attribute for it. Temperature data in buffer (coming from the FIFO) is on 8 bits in lower precision. It is reported as raw data, thus the need of the offset and scale values. So offset and scale values are only for transforming the temperature data from the buffer, and direct read is a full precision already processed in m°C. Thanks for the review, JB From: Lars-Peter Clausen Sent: Sunday, June 14, 2020 17:10 To: Jean-Baptiste Maneyrol ; ji...@kernel.org ; robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org Cc: linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH v3 06/13] iio: imu: inv_icm42600: add temperature sensor support 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 6/8/20 10:42 PM, Jean-Baptiste Maneyrol wrote: > + case IIO_CHAN_INFO_PROCESSED: > + ret = iio_device_claim_direct_mode(indio_dev); > + if (ret) > + return ret; > + ret = inv_icm42600_temp_read(st, ); > + iio_device_release_direct_mode(indio_dev); > + if (ret) > + return ret; > + *val = temp; > + return IIO_VAL_INT; > + case IIO_CHAN_INFO_SCALE: > + *val = 483; > + *val2 = 91787; > + return IIO_VAL_INT_PLUS_MICRO; > + case IIO_CHAN_INFO_OFFSET: > + *val = 25000; > + return IIO_VAL_INT; If the data is returned processed there is no need to specify scale and offset. But since the transformation to turn the data into standard units is a simple linear transform the preferred way to handle this is to return RAW data and specify scale and offset.
[PATCH v3 10/13] iio: imu: inv_icm42600: add buffer support in iio devices
Add all FIFO parsing and reading functions. Add accel and gyro kfifo buffer and FIFO data parsing. Use device interrupt for reading data FIFO and launching accel and gyro parsing. Support hwfifo watermark by multiplexing gyro and accel settings. Support hwfifo flush. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/Kconfig | 1 + drivers/iio/imu/inv_icm42600/Makefile | 1 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 164 - .../imu/inv_icm42600/inv_icm42600_buffer.c| 573 ++ .../imu/inv_icm42600/inv_icm42600_buffer.h| 98 +++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 30 + .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 164 - 8 files changed, 1037 insertions(+), 2 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig index 22390a72f0a3..50cbcfcb6cf1 100644 --- a/drivers/iio/imu/inv_icm42600/Kconfig +++ b/drivers/iio/imu/inv_icm42600/Kconfig @@ -2,6 +2,7 @@ config INV_ICM42600 tristate + select IIO_BUFFER config INV_ICM42600_I2C tristate "InvenSense ICM-426xx I2C driver" diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile index 48965824f00c..0f49f6df3647 100644 --- a/drivers/iio/imu/inv_icm42600/Makefile +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -5,6 +5,7 @@ inv-icm42600-y += inv_icm42600_core.o inv-icm42600-y += inv_icm42600_gyro.o inv-icm42600-y += inv_icm42600_accel.o inv-icm42600-y += inv_icm42600_temp.o +inv-icm42600-y += inv_icm42600_buffer.o obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o inv-icm42600-i2c-y += inv_icm42600_i2c.o diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 148894c888cc..7b52d92739c3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -14,6 +14,8 @@ #include #include +#include "inv_icm42600_buffer.h" + enum inv_icm42600_chip { INV_CHIP_ICM42600, INV_CHIP_ICM42602, @@ -123,6 +125,7 @@ struct inv_icm42600_suspended { * @indio_gyro: gyroscope IIO device. * @indio_accel: accelerometer IIO device. * @buffer: data transfer buffer aligned for DMA. + * @fifo: FIFO management structure. */ struct inv_icm42600_state { struct mutex lock; @@ -137,6 +140,7 @@ struct inv_icm42600_state { struct iio_dev *indio_gyro; struct iio_dev *indio_accel; uint8_t buffer[2] cacheline_aligned; + struct inv_icm42600_fifo fifo; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ @@ -377,6 +381,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st); +int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev); + struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st); +int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev); + #endif diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 3f214df44093..77cdad99de91 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -11,9 +11,12 @@ #include #include #include +#include +#include #include "inv_icm42600.h" #include "inv_icm42600_temp.h" +#include "inv_icm42600_buffer.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -64,6 +67,79 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), }; +/* + * IIO buffer data: size must be a power of 2 + * 8 bytes: 7 bytes data (accel 6 + temp 1) + 1 byte padding + */ +struct inv_icm42600_accel_buffer { + struct inv_icm42600_fifo_sensor_data accel; + int8_t temp; + uint8_t padding; +}; + +#define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \ + (BIT(INV_ICM42600_ACCEL_SCAN_X) | \ + BIT(INV_ICM42600_ACCEL_SCAN_Y) |\ + BIT(INV_ICM42600_ACCEL_SCAN_Z)) + +#define INV_ICM42600_SCAN_MASK_TEMPBIT(INV_ICM42600_ACCEL_SCAN_TEMP) + +static const unsigned long inv_icm42600_accel_scan_masks[] = { + /* 3-axis accel + temperature */ + INV_ICM42600_SCAN_MASK_ACCEL_3AXIS | INV_ICM42600_SCAN_MASK_TEMP, + 0, +}; + +/* enable accelerometer sensor and FIFO write */ +static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, +
[PATCH v3 02/13] iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver
Add I2C driver for InvenSense ICM-426xxx devices. Configure bus signal slew rates as indicated in the datasheet. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 100 ++ 1 file changed, 100 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c new file mode 100644 index ..4789cead23b3 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 InvenSense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st) +{ + unsigned int mask, val; + int ret; + + /* setup interface registers */ + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6, +INV_ICM42600_INTF_CONFIG6_MASK, +INV_ICM42600_INTF_CONFIG6_I3C_EN); + if (ret) + return ret; + + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, +INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0); + if (ret) + return ret; + + /* set slew rates for I2C and SPI */ + mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK | + INV_ICM42600_DRIVE_CONFIG_SPI_MASK; + val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_12_36NS) | + INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_12_36NS); + ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG, +mask, val); + if (ret) + return ret; + + /* disable SPI bus */ + return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS); +} + +static int inv_icm42600_probe(struct i2c_client *client) +{ + const void *match; + enum inv_icm42600_chip chip; + struct regmap *regmap; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENOTSUPP; + + match = device_get_match_data(>dev); + if (!match) + return -EINVAL; + chip = (enum inv_icm42600_chip)match; + + regmap = devm_regmap_init_i2c(client, _icm42600_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return inv_icm42600_core_probe(regmap, chip, inv_icm42600_i2c_bus_setup); +} + +static const struct of_device_id inv_icm42600_of_matches[] = { + { + .compatible = "invensense,icm42600", + .data = (void *)INV_CHIP_ICM42600, + }, { + .compatible = "invensense,icm42602", + .data = (void *)INV_CHIP_ICM42602, + }, { + .compatible = "invensense,icm42605", + .data = (void *)INV_CHIP_ICM42605, + }, { + .compatible = "invensense,icm42622", + .data = (void *)INV_CHIP_ICM42622, + }, + {} +}; +MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); + +static struct i2c_driver inv_icm42600_driver = { + .driver = { + .name = "inv-icm42600-i2c", + .of_match_table = inv_icm42600_of_matches, + .pm = _icm42600_pm_ops, + }, + .probe_new = inv_icm42600_probe, +}; +module_i2c_driver(inv_icm42600_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-426xx I2C driver"); +MODULE_LICENSE("GPL"); -- 2.17.1
[PATCH v3 12/13] dt-bindings: iio: imu: Add inv_icm42600 documentation
Document the ICM-426xxx devices devicetree bindings. Signed-off-by: Jean-Baptiste Maneyrol --- .../bindings/iio/imu/invensense,icm42600.yaml | 90 +++ 1 file changed, 90 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml new file mode 100644 index ..abd8d25e1136 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/imu/invensense,icm42600.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: InvenSense ICM-426xx Inertial Measurement Unit + +maintainers: + - Jean-Baptiste Maneyrol + +description: | + 6-axis MotionTracking device that combines a 3-axis gyroscope and a 3-axis + accelerometer. + + It has a configurable host interface that supports I3C, I2C and SPI serial + communication, features a 2kB FIFO and 2 programmable interrupts with + ultra-low-power wake-on-motion support to minimize system power consumption. + + Other industry-leading features include InvenSense on-chip APEX Motion + Processing engine for gesture recognition, activity classification, and + pedometer, along with programmable digital filters, and an embedded + temperature sensor. + + https://invensense.tdk.com/wp-content/uploads/2020/03/DS-000292-ICM-42605-v1.4.pdf + +properties: + compatible: +enum: + - invensense,icm42600 + - invensense,icm42602 + - invensense,icm42605 + - invensense,icm42622 + + reg: +maxItems: 1 + + interrupts: +maxItems: 1 + + drive-open-drain: +type: boolean + + vdd-supply: +description: Regulator that provides power to the sensor + + vddio-supply: +description: Regulator that provides power to the bus + +required: + - compatible + - reg + - interrupts + +examples: + - | +#include +#include +i2c0 { +#address-cells = <1>; +#size-cells = <0>; + +icm42605@68 { + compatible = "invensense,icm42605"; + reg = <0x68>; + interrupt-parent = <>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <>; + vddio-supply = <>; +}; +}; + - | +#include +#include +spi0 { +#address-cells = <1>; +#size-cells = <0>; + +icm42602@0 { + compatible = "invensense,icm42602"; + reg = <0>; + spi-max-frequency = <2400>; + spi-cpha; + spi-cpol; + interrupt-parent = <>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <>; + vddio-supply = <>; +}; +}; -- 2.17.1
[PATCH v3 04/13] iio: imu: inv_icm42600: add gyroscope IIO device
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 --- 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 | 603 ++ 3 files changed, 613 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..d155470d770a 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); +struct iio_dev *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 2eb25c5f77f8..84e9ff320b3b 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -509,6 +509,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, if (ret) return ret; + st->indio_gyro = inv_icm42600_gyro_init(st); + if (IS_ERR(st->indio_gyro)) + return PTR_ERR(st->indio_gyro); + /* 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 ..3875ecbee67e --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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_icm4
[PATCH v3 03/13] iio: imu: inv_icm42600: add SPI driver for inv_icm42600 driver
Add SPI driver for InvenSense ICM-426xxx devices. Configure bus signal slew rates as indicated in the datasheet. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 99 +++ 1 file changed, 99 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c new file mode 100644 index ..a9c5e2fdbe2a --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 InvenSense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +static int inv_icm42600_spi_bus_setup(struct inv_icm42600_state *st) +{ + unsigned int mask, val; + int ret; + + /* setup interface registers */ + val = INV_ICM42600_INTF_CONFIG6_I3C_EN | + INV_ICM42600_INTF_CONFIG6_I3C_SDR_EN | + INV_ICM42600_INTF_CONFIG6_I3C_DDR_EN; + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6, +INV_ICM42600_INTF_CONFIG6_MASK, val); + if (ret) + return ret; + + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, +INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0); + if (ret) + return ret; + + /* set slew rates for I2C and SPI */ + mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK | + INV_ICM42600_DRIVE_CONFIG_SPI_MASK; + val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_20_60NS) | + INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_INF_2NS); + ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG, +mask, val); + if (ret) + return ret; + + /* disable i2c bus */ + return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS); +} + +static int inv_icm42600_probe(struct spi_device *spi) +{ + const void *match; + enum inv_icm42600_chip chip; + struct regmap *regmap; + + match = device_get_match_data(>dev); + if (!match) + return -EINVAL; + chip = (enum inv_icm42600_chip)match; + + regmap = devm_regmap_init_spi(spi, _icm42600_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return inv_icm42600_core_probe(regmap, chip, inv_icm42600_spi_bus_setup); +} + +static const struct of_device_id inv_icm42600_of_matches[] = { + { + .compatible = "invensense,icm42600", + .data = (void *)INV_CHIP_ICM42600, + }, { + .compatible = "invensense,icm42602", + .data = (void *)INV_CHIP_ICM42602, + }, { + .compatible = "invensense,icm42605", + .data = (void *)INV_CHIP_ICM42605, + }, { + .compatible = "invensense,icm42622", + .data = (void *)INV_CHIP_ICM42622, + }, + {} +}; +MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); + +static struct spi_driver inv_icm42600_driver = { + .driver = { + .name = "inv-icm42600-spi", + .of_match_table = inv_icm42600_of_matches, + .pm = _icm42600_pm_ops, + }, + .probe = inv_icm42600_probe, +}; +module_spi_driver(inv_icm42600_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-426xx SPI driver"); +MODULE_LICENSE("GPL"); -- 2.17.1
[PATCH v3 00/13] iio: imu: new inv_icm42600 driver
Changelog v1 -initial patch submission v2 - formatting reworks, missing headers, code cleanup ... - delete all debug traces - add commentaries for better explanation of suspend/resume, timestamp, ... - delete i2c/spi table ids keeping only of, and use I2C probe_new function - switch calibbias to SI units and add calibias_available attribute - use DMA-safe buffer for all regmap_bulk_* calls - delete iio trigger usage and setup/handle interrupt in core module - add open-drain interrupt support - add FIFO on reference counter and buffer postenable/predisable to replace iio trigger usage - check that temperature data is present before copying in buffer - add temperature sensor off when fifo is turned off - delete timestamp channel reading - move timestamp state in IIO device private data - allow only 1 ODR change in a batch of data - add driver-open-drain in devicetree YAML and delete spi options v3 - delete const pointer cast for iio_device_get_drvdata - change gyro and accel init to return the allocated iio_dev structure - delete manual parent device assignment - correct style and improve readability - add commentaries about IIO buffer and watermark complex computation - add timestamp alignment in IIO buffer structure - wrap lines 80 columns for dt bindings - add ABI documentation for calibbias values in SI units This series add a new driver for managing InvenSense ICM-426xx 6-axis IMUs. This next generation of chips includes new generations of 3-axis gyroscope and 3-axis accelerometer, support of I3C in addition to I2C and SPI, and intelligent MotionTracking features like pedometer, tilt detection, and tap detection. This series is delivering a driver supporting gyroscope, accelerometer and temperature data, with polling and buffering using hwfifo and watermark, on I2C and SPI busses. Gyroscope and accelerometer sensors are completely independent and can have different ODRs. Since there is only a single FIFO a specific value is used to mark invalid data. For keeping the device standard we are de-multiplexing data from the FIFO to 2 IIO devices with 2 buffers, 1 for the accelerometer and 1 for the gyroscope. This architecture also enables to easily turn each sensor on/off without impacting the other. The device interrupt is used to read the FIFO and launch parsing of accelerometer and gyroscope data. A complex timestamping mechanism is added to handle correctly FIFO watermark and dynamic changes of settings. Jean-Baptiste Maneyrol (13): iio: imu: inv_icm42600: add core of new inv_icm42600 driver iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver iio: imu: inv_icm42600: add SPI driver for inv_icm42600 driver iio: imu: inv_icm42600: add gyroscope IIO device iio: imu: inv_icm42600: add accelerometer IIO device iio: imu: inv_icm42600: add temperature sensor support iio: imu: add Kconfig and Makefile for inv_icm42600 driver Documentation: ABI: add specific icm42600 documentation iio: imu: inv_icm42600: add device interrupt iio: imu: inv_icm42600: add buffer support in iio devices iio: imu: inv_icm42600: add accurate timestamping dt-bindings: iio: imu: Add inv_icm42600 documentation MAINTAINERS: add entry for inv_icm42600 6-axis imu sensor .../ABI/testing/sysfs-bus-iio-icm42600| 20 + .../bindings/iio/imu/invensense,icm42600.yaml | 90 ++ MAINTAINERS | 8 + drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42600/Kconfig | 29 + drivers/iio/imu/inv_icm42600/Makefile | 15 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 395 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 789 + .../imu/inv_icm42600/inv_icm42600_buffer.c| 601 + .../imu/inv_icm42600/inv_icm42600_buffer.h| 98 +++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 786 + .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 800 ++ .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 101 +++ .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 100 +++ .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 87 ++ .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 30 + .../imu/inv_icm42600/inv_icm42600_timestamp.c | 195 + .../imu/inv_icm42600/inv_icm42600_timestamp.h | 85 ++ 19 files changed, 4231 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-icm42600 create mode 100644 Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml create mode 100644 drivers/iio/imu/inv_icm42600/Kconfig create mode 100644 drivers/iio/imu/inv_icm42600/Makefile create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
[PATCH v3 09/13] iio: imu: inv_icm42600: add device interrupt
Add INT1 interrupt support. Support interrupt edge and level, active high or low. Push-pull or open-drain configurations. Interrupt will be used to read data from the FIFO. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 2 +- .../iio/imu/inv_icm42600/inv_icm42600_core.c | 101 +- .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 3 +- .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 3 +- 4 files changed, 105 insertions(+), 4 deletions(-) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 3b190461a2b6..148894c888cc 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -372,7 +372,7 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable, int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval); -int inv_icm42600_core_probe(struct regmap *regmap, int chip, +int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, inv_icm42600_bus_setup bus_setup); struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index a35ff21f50bb..95b2a6d91e5b 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -9,8 +9,11 @@ #include #include #include +#include +#include #include #include +#include #include #include @@ -408,6 +411,82 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st, return inv_icm42600_set_conf(st, hw->conf); } +static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data) +{ + struct inv_icm42600_state *st = _data; + struct device *dev = regmap_get_device(st->map); + unsigned int status; + int ret; + + mutex_lock(>lock); + + ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, ); + if (ret) + goto out_unlock; + + /* FIFO full */ + if (status & INV_ICM42600_INT_STATUS_FIFO_FULL) + dev_warn(dev, "FIFO full data lost!\n"); + +out_unlock: + mutex_unlock(>lock); + return IRQ_HANDLED; +} + +/** + * inv_icm42600_irq_init() - initialize int pin and interrupt handler + * @st:driver internal state + * @irq: irq number + * @irq_type: irq trigger type + * @open_drain:true if irq is open drain, false for push-pull + * + * Returns 0 on success, a negative error code otherwise. + */ +static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq, +int irq_type, bool open_drain) +{ + struct device *dev = regmap_get_device(st->map); + unsigned int val; + int ret; + + /* configure INT1 interrupt: default is active low on edge */ + switch (irq_type) { + case IRQF_TRIGGER_RISING: + case IRQF_TRIGGER_HIGH: + val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH; + break; + default: + val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW; + break; + } + + switch (irq_type) { + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_HIGH: + val |= INV_ICM42600_INT_CONFIG_INT1_LATCHED; + break; + default: + break; + } + + if (!open_drain) + val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL; + + ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val); + if (ret) + return ret; + + /* Deassert async reset for proper INT pin operation (cf datasheet) */ + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1, +INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0); + if (ret) + return ret; + + return devm_request_threaded_irq(dev, irq, NULL, +inv_icm42600_irq_handler, irq_type, +"inv_icm42600", st); +} + static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st) { int ret; @@ -452,11 +531,14 @@ static void inv_icm42600_disable_pm(void *_data) pm_runtime_disable(dev); } -int inv_icm42600_core_probe(struct regmap *regmap, int chip, +int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, inv_icm42600_bus_setup bus_setup) { struct device *dev = regmap_get_device(regmap); struct inv_icm42600_state *st; + struct irq_data *irq_desc; + int irq_type; + bool open_drain; int ret; if (chip < 0 || chip >= INV_CHIP_NB) { @@ -464,6 +546,19 @@ int inv_icm42600_core_probe(struct reg
[PATCH v3 08/13] Documentation: ABI: add specific icm42600 documentation
Hardware offset available as calibscale sysfs attributes are real physical values exprimed in SI units. calibscale_available sysfs attributes represents the range of acceptable values. Signed-off-by: Jean-Baptiste Maneyrol --- .../ABI/testing/sysfs-bus-iio-icm42600| 20 +++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-icm42600 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-icm42600 b/Documentation/ABI/testing/sysfs-bus-iio-icm42600 new file mode 100644 index ..0bf1fd4f5bf1 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-icm42600 @@ -0,0 +1,20 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias +KernelVersion: 5.8 +Contact:linux-...@vger.kernel.org +Description: + Hardware applied calibration offset (assumed to fix production + inaccuracies). Values represent a real physical offset expressed + in SI units (m/s^2 for accelerometer and rad/s for gyroscope). + +What: /sys/bus/iio/devices/iio:deviceX/in_accel_calibbias_available +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_calibbias_available +KernelVersion: 5.8 +Contact:linux-...@vger.kernel.org +Description: + Range of available values for hardware offset. Values in SI + units (m/s^2 for accelerometer and rad/s for gyroscope). -- 2.17.1
[PATCH v3 05/13] iio: imu: inv_icm42600: add accelerometer IIO device
Add IIO device for accelerometer sensor with data polling interface. Attributes: raw, scale, sampling_frequency, calibbias. Accelerometer in low noise mode. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 4 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 592 ++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 4 + 3 files changed, 600 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index d155470d770a..3b190461a2b6 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -121,6 +121,7 @@ struct inv_icm42600_suspended { * @conf: chip sensors configurations. * @suspended:suspended sensors configuration. * @indio_gyro: gyroscope IIO device. + * @indio_accel: accelerometer IIO device. * @buffer: data transfer buffer aligned for DMA. */ struct inv_icm42600_state { @@ -134,6 +135,7 @@ struct inv_icm42600_state { struct inv_icm42600_conf conf; struct inv_icm42600_suspended suspended; struct iio_dev *indio_gyro; + struct iio_dev *indio_accel; uint8_t buffer[2] cacheline_aligned; }; @@ -375,4 +377,6 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st); +struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st); + #endif diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c new file mode 100644 index ..717c6b0869fc --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -0,0 +1,592 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +#define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ + { \ + .type = IIO_ACCEL, \ + .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_accel_scan { + INV_ICM42600_ACCEL_SCAN_X, + INV_ICM42600_ACCEL_SCAN_Y, + INV_ICM42600_ACCEL_SCAN_Z, +}; + +static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42600_get_mount_matrix), + {}, +}; + +static const struct iio_chan_spec inv_icm42600_accel_channels[] = { + INV_ICM42600_ACCEL_CHAN(IIO_MOD_X, INV_ICM42600_ACCEL_SCAN_X, + inv_icm42600_accel_ext_infos), + INV_ICM42600_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42600_ACCEL_SCAN_Y, + inv_icm42600_accel_ext_infos), + INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, + inv_icm42600_accel_ext_infos), +}; + +static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st, + struct iio_chan_spec const *chan, + int16_t *val) +{ + struct device *dev = regmap_get_devi
[PATCH v3 06/13] iio: imu: inv_icm42600: add temperature sensor support
Add temperature channel in gyroscope and accelerometer devices. Temperature is available in full 16 bits resolution as a processed channel. Scale and offset attributes are also provided for the low 8 bits resolution raw temperature found in the FIFO. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 11 ++- .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 11 ++- .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 87 +++ .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 30 +++ 4 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 717c6b0869fc..3f214df44093 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -13,6 +13,7 @@ #include #include "inv_icm42600.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -45,6 +46,7 @@ enum inv_icm42600_accel_scan { INV_ICM42600_ACCEL_SCAN_X, INV_ICM42600_ACCEL_SCAN_Y, INV_ICM42600_ACCEL_SCAN_Z, + INV_ICM42600_ACCEL_SCAN_TEMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { @@ -59,6 +61,7 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { inv_icm42600_accel_ext_infos), INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, inv_icm42600_accel_ext_infos), + INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), }; static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st, @@ -450,8 +453,14 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev, int16_t data; int ret; - if (chan->type != IIO_ACCEL) + switch (chan->type) { + case IIO_ACCEL: + break; + case IIO_TEMP: + return inv_icm42600_temp_read_raw(indio_dev, chan, val, val2, mask); + default: return -EINVAL; + } switch (mask) { case IIO_CHAN_INFO_RAW: diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index 3875ecbee67e..6a0e7661fa48 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -13,6 +13,7 @@ #include #include "inv_icm42600.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \ { \ @@ -45,6 +46,7 @@ enum inv_icm42600_gyro_scan { INV_ICM42600_GYRO_SCAN_X, INV_ICM42600_GYRO_SCAN_Y, INV_ICM42600_GYRO_SCAN_Z, + INV_ICM42600_GYRO_SCAN_TEMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_gyro_ext_infos[] = { @@ -59,6 +61,7 @@ static const struct iio_chan_spec inv_icm42600_gyro_channels[] = { inv_icm42600_gyro_ext_infos), INV_ICM42600_GYRO_CHAN(IIO_MOD_Z, INV_ICM42600_GYRO_SCAN_Z, inv_icm42600_gyro_ext_infos), + INV_ICM42600_TEMP_CHAN(INV_ICM42600_GYRO_SCAN_TEMP), }; static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st, @@ -461,8 +464,14 @@ static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev, int16_t data; int ret; - if (chan->type != IIO_ANGL_VEL) + switch (chan->type) { + case IIO_ANGL_VEL: + break; + case IIO_TEMP: + return inv_icm42600_temp_read_raw(indio_dev, chan, val, val2, mask); + default: return -EINVAL; + } switch (mask) { case IIO_CHAN_INFO_RAW: diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c new file mode 100644 index ..b0871352fe39 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" +#include "inv_icm42600_temp.h" + +static int inv_icm42600_temp_read(struct inv_icm42600_state *st, int32_t *temp) +{ + struct device *dev = regmap_get_device(st->map); + int64_t data; + __be16 *raw; + int16_t val; + int ret; + + pm_runtime_get_sync(dev); + mutex_lock(>lock); + + ret = inv_icm42600_set_temp_conf(st, true, NULL); +
[PATCH v3 13/13] MAINTAINERS: add entry for inv_icm42600 6-axis imu sensor
Add MAINTAINERS entry for InvenSense ICM-426xx IMU device. Signed-off-by: Jean-Baptiste Maneyrol --- MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 60ed2963efaa..cd8b5fece94d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8861,6 +8861,14 @@ F: include/dt-bindings/interconnect/ F: include/linux/interconnect-provider.h F: include/linux/interconnect.h +INVENSENSE ICM-426xx IMU DRIVER +M: Jean-Baptiste Maneyrol +L: linux-...@vger.kernel.org +S: Maintained +W https://invensense.tdk.com/ +F: Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +F: drivers/iio/imu/inv_icm42600/ + INVENSENSE MPU-3050 GYROSCOPE DRIVER M: Linus Walleij L: linux-...@vger.kernel.org -- 2.17.1
[PATCH v3 07/13] iio: imu: add Kconfig and Makefile for inv_icm42600 driver
Add 3 modules: inv-icm42600, inv-icm42600-i2c, inv-icm42600-spi. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42600/Kconfig | 28 +++ drivers/iio/imu/inv_icm42600/Makefile | 13 + 4 files changed, 43 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/Kconfig create mode 100644 drivers/iio/imu/inv_icm42600/Makefile diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index fc4123d518bc..f02883b08480 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -91,6 +91,7 @@ config KMX61 To compile this driver as module, choose M here: the module will be called kmx61. +source "drivers/iio/imu/inv_icm42600/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" source "drivers/iio/imu/st_lsm6dsx/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 88b2c4555230..13e9ff442b11 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_FXOS8700) += fxos8700_core.o obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o +obj-y += inv_icm42600/ obj-y += inv_mpu6050/ obj-$(CONFIG_KMX61) += kmx61.o diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig new file mode 100644 index ..22390a72f0a3 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/Kconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config INV_ICM42600 + tristate + +config INV_ICM42600_I2C + tristate "InvenSense ICM-426xx I2C driver" + depends on I2C + select INV_ICM42600 + select REGMAP_I2C + help + This driver supports the InvenSense ICM-426xx motion tracking + devices over I2C. + + This driver can be built as a module. The module will be called + inv-icm42600-i2c. + +config INV_ICM42600_SPI + tristate "InvenSense ICM-426xx SPI driver" + depends on SPI_MASTER + select INV_ICM42600 + select REGMAP_SPI + help + This driver supports the InvenSense ICM-426xx motion tracking + devices over SPI. + + This driver can be built as a module. The module will be called + inv-icm42600-spi. diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile new file mode 100644 index ..48965824f00c --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-$(CONFIG_INV_ICM42600) += inv-icm42600.o +inv-icm42600-y += inv_icm42600_core.o +inv-icm42600-y += inv_icm42600_gyro.o +inv-icm42600-y += inv_icm42600_accel.o +inv-icm42600-y += inv_icm42600_temp.o + +obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o +inv-icm42600-i2c-y += inv_icm42600_i2c.o + +obj-$(CONFIG_INV_ICM42600_SPI) += inv-icm42600-spi.o +inv-icm42600-spi-y += inv_icm42600_spi.o -- 2.17.1
[PATCH v3 11/13] iio: imu: inv_icm42600: add accurate timestamping
Add a timestamping mechanism for buffer that provides accurate event timestamps when using watermark. This mechanism estimates device internal clock by comparing FIFO interrupts delta time and device elapsed time computed by parsing FIFO data. Take interrupt timestamp in hard irq handler and add IIO device specific timestamp structures in device private allocation. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/Makefile | 1 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 5 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 40 +++- .../imu/inv_icm42600/inv_icm42600_buffer.c| 28 +++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 17 +- .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 40 +++- .../imu/inv_icm42600/inv_icm42600_timestamp.c | 195 ++ .../imu/inv_icm42600/inv_icm42600_timestamp.h | 85 8 files changed, 396 insertions(+), 15 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.h diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile index 0f49f6df3647..291714d9aa54 100644 --- a/drivers/iio/imu/inv_icm42600/Makefile +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -6,6 +6,7 @@ inv-icm42600-y += inv_icm42600_gyro.o inv-icm42600-y += inv_icm42600_accel.o inv-icm42600-y += inv_icm42600_temp.o inv-icm42600-y += inv_icm42600_buffer.o +inv-icm42600-y += inv_icm42600_timestamp.o obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o inv-icm42600-i2c-y += inv_icm42600_i2c.o diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 7b52d92739c3..c0f5059b13b3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -126,6 +126,7 @@ struct inv_icm42600_suspended { * @indio_accel: accelerometer IIO device. * @buffer: data transfer buffer aligned for DMA. * @fifo: FIFO management structure. + * @timestamp:interrupt timestamps. */ struct inv_icm42600_state { struct mutex lock; @@ -141,6 +142,10 @@ struct inv_icm42600_state { struct iio_dev *indio_accel; uint8_t buffer[2] cacheline_aligned; struct inv_icm42600_fifo fifo; + struct { + int64_t gyro; + int64_t accel; + } timestamp; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 77cdad99de91..e51e15029116 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -17,6 +17,7 @@ #include "inv_icm42600.h" #include "inv_icm42600_temp.h" #include "inv_icm42600_buffer.h" +#include "inv_icm42600_timestamp.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -50,6 +51,7 @@ enum inv_icm42600_accel_scan { INV_ICM42600_ACCEL_SCAN_Y, INV_ICM42600_ACCEL_SCAN_Z, INV_ICM42600_ACCEL_SCAN_TEMP, + INV_ICM42600_ACCEL_SCAN_TIMESTAMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { @@ -65,16 +67,18 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, inv_icm42600_accel_ext_infos), INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), + IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42600_ACCEL_SCAN_TIMESTAMP), }; /* - * IIO buffer data: size must be a power of 2 - * 8 bytes: 7 bytes data (accel 6 + temp 1) + 1 byte padding + * IIO buffer data: size must be a power of 2 and timestamp aligned + * 16 bytes: 7 bytes data (accel 6 + temp 1) + 1 byte padding + 8 bytes timestamp */ struct inv_icm42600_accel_buffer { struct inv_icm42600_fifo_sensor_data accel; int8_t temp; uint8_t padding; + int64_t timestamp __aligned(8); }; #define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \ @@ -95,6 +99,7 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_timestamp *ts = iio_priv(indio_dev); struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; unsigned int fifo_en = 0; unsigned int sleep_temp = 0; @@ -122,6 +127,7 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, } /* update data FIFO write */ + inv_icm42600_times
[PATCH v3 01/13] iio: imu: inv_icm42600: add core of new inv_icm42600 driver
Core component of a new driver for InvenSense ICM-426xx devices. It includes registers definition, main probe/setup, and device utility functions. ICM-426xx devices are latest generation of 6-axis IMU, gyroscope+accelerometer and temperature sensor. This device includes a 2K FIFO, supports I2C/I3C/SPI, and provides intelligent motion features like pedometer, tilt detection, and tap detection. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 372 ++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 634 ++ 2 files changed, 1006 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h new file mode 100644 index ..14c8ef152418 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#ifndef INV_ICM42600_H_ +#define INV_ICM42600_H_ + +#include +#include +#include +#include +#include +#include +#include + +enum inv_icm42600_chip { + INV_CHIP_ICM42600, + INV_CHIP_ICM42602, + INV_CHIP_ICM42605, + INV_CHIP_ICM42622, + INV_CHIP_NB, +}; + +/* serial bus slew rates */ +enum inv_icm42600_slew_rate { + INV_ICM42600_SLEW_RATE_20_60NS, + INV_ICM42600_SLEW_RATE_12_36NS, + INV_ICM42600_SLEW_RATE_6_18NS, + INV_ICM42600_SLEW_RATE_4_12NS, + INV_ICM42600_SLEW_RATE_2_6NS, + INV_ICM42600_SLEW_RATE_INF_2NS, +}; + +enum inv_icm42600_sensor_mode { + INV_ICM42600_SENSOR_MODE_OFF, + INV_ICM42600_SENSOR_MODE_STANDBY, + INV_ICM42600_SENSOR_MODE_LOW_POWER, + INV_ICM42600_SENSOR_MODE_LOW_NOISE, + INV_ICM42600_SENSOR_MODE_NB, +}; + +/* gyroscope fullscale values */ +enum inv_icm42600_gyro_fs { + INV_ICM42600_GYRO_FS_2000DPS, + INV_ICM42600_GYRO_FS_1000DPS, + INV_ICM42600_GYRO_FS_500DPS, + INV_ICM42600_GYRO_FS_250DPS, + INV_ICM42600_GYRO_FS_125DPS, + INV_ICM42600_GYRO_FS_62_5DPS, + INV_ICM42600_GYRO_FS_31_25DPS, + INV_ICM42600_GYRO_FS_15_625DPS, + INV_ICM42600_GYRO_FS_NB, +}; + +/* accelerometer fullscale values */ +enum inv_icm42600_accel_fs { + INV_ICM42600_ACCEL_FS_16G, + INV_ICM42600_ACCEL_FS_8G, + INV_ICM42600_ACCEL_FS_4G, + INV_ICM42600_ACCEL_FS_2G, + INV_ICM42600_ACCEL_FS_NB, +}; + +/* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */ +enum inv_icm42600_odr { + INV_ICM42600_ODR_8KHZ_LN = 3, + INV_ICM42600_ODR_4KHZ_LN, + INV_ICM42600_ODR_2KHZ_LN, + INV_ICM42600_ODR_1KHZ_LN, + INV_ICM42600_ODR_200HZ, + INV_ICM42600_ODR_100HZ, + INV_ICM42600_ODR_50HZ, + INV_ICM42600_ODR_25HZ, + INV_ICM42600_ODR_12_5HZ, + INV_ICM42600_ODR_6_25HZ_LP, + INV_ICM42600_ODR_3_125HZ_LP, + INV_ICM42600_ODR_1_5625HZ_LP, + INV_ICM42600_ODR_500HZ, + INV_ICM42600_ODR_NB, +}; + +enum inv_icm42600_filter { + /* Low-Noise mode sensor data filter (3rd order filter by default) */ + INV_ICM42600_FILTER_BW_ODR_DIV_2, + + /* Low-Power mode sensor data filter (averaging) */ + INV_ICM42600_FILTER_AVG_1X = 1, + INV_ICM42600_FILTER_AVG_16X = 6, +}; + +struct inv_icm42600_sensor_conf { + int mode; + int fs; + int odr; + int filter; +}; +#define INV_ICM42600_SENSOR_CONF_INIT {-1, -1, -1, -1} + +struct inv_icm42600_conf { + struct inv_icm42600_sensor_conf gyro; + struct inv_icm42600_sensor_conf accel; + bool temp_en; +}; + +struct inv_icm42600_suspended { + enum inv_icm42600_sensor_mode gyro; + enum inv_icm42600_sensor_mode accel; + bool temp; +}; + +/** + * struct inv_icm42600_state - driver state variables + * @lock: lock for serializing multiple registers access. + * @chip: chip identifier. + * @name: chip name. + * @map: regmap pointer. + * @vdd_supply: VDD voltage regulator for the chip. + * @vddio_supply: I/O voltage regulator for the chip. + * @orientation: sensor chip orientation relative to main hardware. + * @conf: chip sensors configurations. + * @suspended:suspended sensors configuration. + */ +struct inv_icm42600_state { + struct mutex lock; + enum inv_icm42600_chip chip; + const char *name; + struct regmap *map; + struct regulator *vdd_supply; + struct regulator *vddio_supply; + struct iio_mount_matrix orientation; + struct inv_icm42600_conf conf; + struct inv_icm42600_suspended suspended; +}; + +/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ + +/* Bank selection register, available in all banks */ +#define
Re: --[[SPOOF or PHISHING]]--Re: [PATCH v2 09/12] iio: imu: inv_icm42600: add buffer support in iio devices
Hi Jonathan, something I forgot, about the __packed attribute for the sensor data structure struct inv_icm42600_fifo_sensor_data located inside inv_icm42600_buffer.h. I added it because this structure is used for decoding the FIFO data frame which can be unaligned. It is also used for storing data in other modules, but __packed attribute should not change anything here. Thanks, JB From: linux-iio-ow...@vger.kernel.org on behalf of Jean-Baptiste Maneyrol Sent: Tuesday, June 2, 2020 14:57 To: Jonathan Cameron Cc: robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: --[[SPOOF or PHISHING]]--Re: [PATCH v2 09/12] iio: imu: inv_icm42600: add buffer support in iio devices 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. Hi Jonathan, I agree that this multiplexed watermark computation value is anything except simple and clear to understand. I will add more documentation about it. And it also triggered a kbuild robot issue, because it is using 64 bits modulo without using math64 macros. For buffer preenable/postenable/..., the sequence I am using currently is: - preenable -> turn chip on (pm_runtime_get) - update_scan_mode -> set FIFO en bits configuration (which sensor data is going into the fifo) - hwfifo_watermark -> compute and set watermark value - postenable -> turn FIFO on (and multiplexed with a FIFO on counter since used by accel & gyro) - predisable -> turn FIFO off (multiplexed with counter) - postdisable -> turn chip off (pm_runtime_put) This setting is working well. Good to note that if there is an error when enabling the buffer, postdisable will always get called after preenable. So it ensures pm_runtime reference counter to be always OK. Another way would be to only store configuration in internal state with update_scan_mode and hwfifo_watermark, and do everything in postenable/predisable. This is a possibility, but makes things a little more complex. For hwfifo flush, this is an interesting feature when there is a need to have data immediately. Or when there is a need to do a clean change of configuration. In Android systems, Android framework is mainly using FIFO flush to change the sensor configuration (ODR, watermark) in a clean way. For our case with the FIFO interleaved this is a not an issue. If there are samples from the 2 sensors, it means the 2 buffers are enabled. And if data is coming to the iio buffer sooner than expected, that should not be a problem. The limitation I see when the 2 sensors are runnings, is that we will return less data than should have been possible. I limit FIFO reading to the provided n bytes, so we could read less than n samples of 1 sensor. Something I have in mind, that would be really interesting to be able to set/change watermark value when the buffer is enabled. Otherwise, we are always loosing events by turning sensor off when we want to change the value. Is there any limitation to work this way, or should it be possible to implement this feature in the future ? Thanks, JB From: Jonathan Cameron Sent: Sunday, May 31, 2020 14:56 To: Jean-Baptiste Maneyrol Cc: robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH v2 09/12] iio: imu: inv_icm42600: add buffer support in iio devices 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:08 +0200 Jean-Baptiste Maneyrol wrote: > Add all FIFO parsing and reading functions. Add accel and gyro > kfifo buffer and FIFO data parsing. Use device interrupt for > reading data FIFO and launching accel and gyro parsing. > > Support hwfifo watermark by multiplexing gyro and accel settings. > Support hwfifo flush. Both of these are complex given the interactions of the two sensors types and to be honest I couldn't figure out exactly what the intent was. Needs more docs! Thanks, Jonathan > > Signed-off-by: Jean-Baptiste Maneyrol > --- > drivers/iio/imu/inv_icm42600/Kconfig | 1 + > drivers/iio/imu/inv_icm42600/Makefile | 1 + > drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 + > .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 160 - > .../imu/inv_icm42600/inv_icm42600_buffer.c | 555 ++ > .../imu/inv_icm42600/inv_icm42600_buffer.h | 98 >
Re: [PATCH v2 09/12] iio: imu: inv_icm42600: add buffer support in iio devices
Hi Jonathan, I agree that this multiplexed watermark computation value is anything except simple and clear to understand. I will add more documentation about it. And it also triggered a kbuild robot issue, because it is using 64 bits modulo without using math64 macros. For buffer preenable/postenable/..., the sequence I am using currently is: - preenable -> turn chip on (pm_runtime_get) - update_scan_mode -> set FIFO en bits configuration (which sensor data is going into the fifo) - hwfifo_watermark -> compute and set watermark value - postenable -> turn FIFO on (and multiplexed with a FIFO on counter since used by accel & gyro) - predisable -> turn FIFO off (multiplexed with counter) - postdisable -> turn chip off (pm_runtime_put) This setting is working well. Good to note that if there is an error when enabling the buffer, postdisable will always get called after preenable. So it ensures pm_runtime reference counter to be always OK. Another way would be to only store configuration in internal state with update_scan_mode and hwfifo_watermark, and do everything in postenable/predisable. This is a possibility, but makes things a little more complex. For hwfifo flush, this is an interesting feature when there is a need to have data immediately. Or when there is a need to do a clean change of configuration. In Android systems, Android framework is mainly using FIFO flush to change the sensor configuration (ODR, watermark) in a clean way. For our case with the FIFO interleaved this is a not an issue. If there are samples from the 2 sensors, it means the 2 buffers are enabled. And if data is coming to the iio buffer sooner than expected, that should not be a problem. The limitation I see when the 2 sensors are runnings, is that we will return less data than should have been possible. I limit FIFO reading to the provided n bytes, so we could read less than n samples of 1 sensor. Something I have in mind, that would be really interesting to be able to set/change watermark value when the buffer is enabled. Otherwise, we are always loosing events by turning sensor off when we want to change the value. Is there any limitation to work this way, or should it be possible to implement this feature in the future ? Thanks, JB From: Jonathan Cameron Sent: Sunday, May 31, 2020 14:56 To: Jean-Baptiste Maneyrol Cc: robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH v2 09/12] iio: imu: inv_icm42600: add buffer support in iio devices 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:08 +0200 Jean-Baptiste Maneyrol wrote: > Add all FIFO parsing and reading functions. Add accel and gyro > kfifo buffer and FIFO data parsing. Use device interrupt for > reading data FIFO and launching accel and gyro parsing. > > Support hwfifo watermark by multiplexing gyro and accel settings. > Support hwfifo flush. Both of these are complex given the interactions of the two sensors types and to be honest I couldn't figure out exactly what the intent was. Needs more docs! Thanks, Jonathan > > Signed-off-by: Jean-Baptiste Maneyrol > --- > drivers/iio/imu/inv_icm42600/Kconfig | 1 + > drivers/iio/imu/inv_icm42600/Makefile | 1 + > drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 + > .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 160 - > .../imu/inv_icm42600/inv_icm42600_buffer.c | 555 ++ > .../imu/inv_icm42600/inv_icm42600_buffer.h | 98 > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 30 + > .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 160 - > 8 files changed, 1011 insertions(+), 2 deletions(-) > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h > > diff --git a/drivers/iio/imu/inv_icm42600/Kconfig > b/drivers/iio/imu/inv_icm42600/Kconfig > index 22390a72f0a3..50cbcfcb6cf1 100644 > --- a/drivers/iio/imu/inv_icm42600/Kconfig > +++ b/drivers/iio/imu/inv_icm42600/Kconfig > @@ -2,6 +2,7 @@ > > config INV_ICM42600 > tristate > + select IIO_BUFFER > > config INV_ICM42600_I2C > tristate "InvenSense ICM-426xx I2C driver" > diff --git a/drivers/iio/imu/inv_icm42600/Makefile > b/drivers/iio/imu/inv_icm42600/Makefile > index 48965824f00c..0f49f6df3647 100644 > --- a/drivers/iio/imu/inv_icm42600/Makefile > +++ b/drivers/iio/imu/inv_icm42600/Makefile > @@ -5,6 +5,7 @@ inv-icm42600-y += inv_icm42
Re: [PATCH v2 04/12] iio: imu: inv_icm42600: add gyroscope IIO device
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. Thanks, JB From: Jonathan Cameron Sent: Sunday, May 31, 2020 13:54 To: Jean-Baptiste Maneyrol Cc: robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org 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 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 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 ..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 > +#include > +#include > +#include > +#include > +#include > +#
Re: [PATCH v2 01/12] iio: imu: inv_icm42600: add core of new inv_icm42600 driver
Hi Jonathan, I've given my review tag for the const change of iio_device_get_drvdata(). Would be perfect to have this cleaned up for the v3. For vddio regulator you are missing something. In all suspend callbacks (system and runtime) I am calling directly regulator_disable to shut vddio off at then end. And in all resume callbacks I am calling inv_icm42600_enable_regulator_vddio() that is turning vddio regulator back on and is sleeping to wait a little for the supply ramp. Indeed this doesn't look symmetric, but I was not very happy to add a inv_icm42600_disable_regulator_vddio() that would just do regulator_disable, or copy/paste the sleeping value in all resume handlers. Tell me what you prefer. Thanks, JB From: linux-iio-ow...@vger.kernel.org on behalf of Jonathan Cameron Sent: Sunday, May 31, 2020 13:34 To: Jean-Baptiste Maneyrol Cc: robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH v2 01/12] iio: imu: inv_icm42600: add core of new inv_icm42600 driver 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:00 +0200 Jean-Baptiste Maneyrol wrote: > Core component of a new driver for InvenSense ICM-426xx devices. > It includes registers definition, main probe/setup, and device > utility functions. > > ICM-426xx devices are latest generation of 6-axis IMU, > gyroscope+accelerometer and temperature sensor. This device > includes a 2K FIFO, supports I2C/I3C/SPI, and provides > intelligent motion features like pedometer, tilt detection, > and tap detection. > > Signed-off-by: Jean-Baptiste Maneyrol A few things inline. Either I'm missing something or I'm guessing vddio is not controllable on your test board. > --- > drivers/iio/imu/inv_icm42600/inv_icm42600.h | 372 ++ > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 635 ++ > 2 files changed, 1007 insertions(+) > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c > ... > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c > b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c > new file mode 100644 > index ..81b171d6782c > --- /dev/null > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c > +const struct iio_mount_matrix * > +inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev, > + const struct iio_chan_spec *chan) > +{ > + const struct inv_icm42600_state *st = > + iio_device_get_drvdata((struct iio_dev *)indio_dev); If you review my patch to the core, I can get that applied and we can drop the ugly cast from here! Just waiting for someone to sanity check it. > + > + return >orientation; > +} ... > +/* Runtime suspend will turn off sensors that are enabled by iio devices. */ > +static int __maybe_unused inv_icm42600_runtime_suspend(struct device *dev) > +{ > + struct inv_icm42600_state *st = dev_get_drvdata(dev); > + int ret; > + > + mutex_lock(>lock); > + > + /* disable all sensors */ > + ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF, > + INV_ICM42600_SENSOR_MODE_OFF, false, > + NULL); > + if (ret) > + goto error_unlock; > + > + regulator_disable(st->vddio_supply); Don't seem to turn this on again in runtime_resume.. Why? Definitely needs at least a comment. > + > +error_unlock: > + mutex_unlock(>lock); > + return ret; > +} > + > +/* Sensors are enabled by iio devices, no need to turn them back on here. */ > +static int __maybe_unused inv_icm42600_runtime_resume(struct device *dev) > +{ > + struct inv_icm42600_state *st = dev_get_drvdata(dev); > + int ret; > + > + mutex_lock(>lock); > + > + ret = inv_icm42600_enable_regulator_vddio(st); > + > + mutex_unlock(>lock); > + return ret; > +} > + > +const struct dev_pm_ops inv_icm42600_pm_ops = { > + SET_SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume) > + SET_RUNTIME_PM_OPS(inv_icm42600_runtime_suspend, > + inv_icm42600_runtime_resume, NULL) > +}; > +EXPORT_SYMBOL_GPL(inv_icm42600_pm_ops); > + > +MODULE_AUTHOR("InvenSense, Inc."); > +MODULE_DESCRIPTION("InvenSense ICM-426xx device driver"); > +MODULE_LICENSE("GPL");
[PATCH v2 11/12] dt-bindings: iio: imu: Add inv_icm42600 documentation
Document the ICM-426xxx devices devicetree bindings. Signed-off-by: Jean-Baptiste Maneyrol --- .../bindings/iio/imu/invensense,icm42600.yaml | 86 +++ 1 file changed, 86 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml new file mode 100644 index ..c5b046e0ce36 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/imu/invensense,icm42600.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: InvenSense ICM-426xx Inertial Measurement Unit + +maintainers: + - Jean-Baptiste Maneyrol + +description: | + 6-axis MotionTracking device that combines a 3-axis gyroscope and a 3-axis accelerometer. + + It has a configurable host interface that supports I3C, I2C and SPI serial communication, features a 2kB FIFO and + 2 programmable interrupts with ultra-low-power wake-on-motion support to minimize system power consumption. + + Other industry-leading features include InvenSense on-chip APEX Motion Processing engine for gesture recognition, + activity classification, and pedometer, along with programmable digital filters, and an embedded temperature sensor. + + https://invensense.tdk.com/wp-content/uploads/2020/03/DS-000292-ICM-42605-v1.4.pdf + +properties: + compatible: +enum: + - invensense,icm42600 + - invensense,icm42602 + - invensense,icm42605 + - invensense,icm42622 + + reg: +maxItems: 1 + + interrupts: +maxItems: 1 + + drive-open-drain: +type: boolean + + vdd-supply: +description: Regulator that provides power to the sensor + + vddio-supply: +description: Regulator that provides power to the bus + +required: + - compatible + - reg + - interrupts + +examples: + - | +#include +#include +i2c0 { +#address-cells = <1>; +#size-cells = <0>; + +icm42605@68 { + compatible = "invensense,icm42605"; + reg = <0x68>; + interrupt-parent = <>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <>; + vddio-supply = <>; +}; +}; + - | +#include +#include +spi0 { +#address-cells = <1>; +#size-cells = <0>; + +icm42602@0 { + compatible = "invensense,icm42602"; + reg = <0>; + spi-max-frequency = <2400>; + spi-cpha; + spi-cpol; + interrupt-parent = <>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <>; + vddio-supply = <>; +}; +}; -- 2.17.1
[PATCH v2 12/12] MAINTAINERS: add entry for inv_icm42600 6-axis imu sensor
Add MAINTAINERS entry for InvenSense ICM-426xx IMU device. Signed-off-by: Jean-Baptiste Maneyrol --- MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 60ed2963efaa..cd8b5fece94d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8861,6 +8861,14 @@ F: include/dt-bindings/interconnect/ F: include/linux/interconnect-provider.h F: include/linux/interconnect.h +INVENSENSE ICM-426xx IMU DRIVER +M: Jean-Baptiste Maneyrol +L: linux-...@vger.kernel.org +S: Maintained +W https://invensense.tdk.com/ +F: Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +F: drivers/iio/imu/inv_icm42600/ + INVENSENSE MPU-3050 GYROSCOPE DRIVER M: Linus Walleij L: linux-...@vger.kernel.org -- 2.17.1
[PATCH v2 09/12] iio: imu: inv_icm42600: add buffer support in iio devices
Add all FIFO parsing and reading functions. Add accel and gyro kfifo buffer and FIFO data parsing. Use device interrupt for reading data FIFO and launching accel and gyro parsing. Support hwfifo watermark by multiplexing gyro and accel settings. Support hwfifo flush. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/Kconfig | 1 + drivers/iio/imu/inv_icm42600/Makefile | 1 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 160 - .../imu/inv_icm42600/inv_icm42600_buffer.c| 555 ++ .../imu/inv_icm42600/inv_icm42600_buffer.h| 98 .../iio/imu/inv_icm42600/inv_icm42600_core.c | 30 + .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 160 - 8 files changed, 1011 insertions(+), 2 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig index 22390a72f0a3..50cbcfcb6cf1 100644 --- a/drivers/iio/imu/inv_icm42600/Kconfig +++ b/drivers/iio/imu/inv_icm42600/Kconfig @@ -2,6 +2,7 @@ config INV_ICM42600 tristate + select IIO_BUFFER config INV_ICM42600_I2C tristate "InvenSense ICM-426xx I2C driver" diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile index 48965824f00c..0f49f6df3647 100644 --- a/drivers/iio/imu/inv_icm42600/Makefile +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -5,6 +5,7 @@ inv-icm42600-y += inv_icm42600_core.o inv-icm42600-y += inv_icm42600_gyro.o inv-icm42600-y += inv_icm42600_accel.o inv-icm42600-y += inv_icm42600_temp.o +inv-icm42600-y += inv_icm42600_buffer.o obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o inv-icm42600-i2c-y += inv_icm42600_i2c.o diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 43749f56426c..4d5811562a61 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -14,6 +14,8 @@ #include #include +#include "inv_icm42600_buffer.h" + enum inv_icm42600_chip { INV_CHIP_ICM42600, INV_CHIP_ICM42602, @@ -123,6 +125,7 @@ struct inv_icm42600_suspended { * @indio_gyro: gyroscope IIO device. * @indio_accel: accelerometer IIO device. * @buffer: data transfer buffer aligned for DMA. + * @fifo: FIFO management structure. */ struct inv_icm42600_state { struct mutex lock; @@ -137,6 +140,7 @@ struct inv_icm42600_state { struct iio_dev *indio_gyro; struct iio_dev *indio_accel; uint8_t buffer[2] cacheline_aligned; + struct inv_icm42600_fifo fifo; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ @@ -377,6 +381,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, int inv_icm42600_gyro_init(struct inv_icm42600_state *st); +int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev); + int inv_icm42600_accel_init(struct inv_icm42600_state *st); +int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev); + #endif diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 6a615d7ffb24..c73ce204efc6 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -11,9 +11,12 @@ #include #include #include +#include +#include #include "inv_icm42600.h" #include "inv_icm42600_temp.h" +#include "inv_icm42600_buffer.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -64,6 +67,76 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), }; +/* IIO buffer data: 8 bytes */ +struct inv_icm42600_accel_buffer { + struct inv_icm42600_fifo_sensor_data accel; + int8_t temp; + uint8_t padding; +}; + +#define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \ + (BIT(INV_ICM42600_ACCEL_SCAN_X) | \ + BIT(INV_ICM42600_ACCEL_SCAN_Y) |\ + BIT(INV_ICM42600_ACCEL_SCAN_Z)) + +#define INV_ICM42600_SCAN_MASK_TEMPBIT(INV_ICM42600_ACCEL_SCAN_TEMP) + +static const unsigned long inv_icm42600_accel_scan_masks[] = { + /* 3-axis accel + temperature */ + INV_ICM42600_SCAN_MASK_ACCEL_3AXIS | INV_ICM42600_SCAN_MASK_TEMP, + 0, +}; + +/* enable accelerometer sensor and FIFO write */ +static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct inv_icm
[PATCH v2 03/12] iio: imu: inv_icm42600: add SPI driver for inv_icm42600 driver
Add SPI driver for InvenSense ICM-426xxx devices. Configure bus signal slew rates as indicated in the datasheet. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 99 +++ 1 file changed, 99 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c new file mode 100644 index ..a9c5e2fdbe2a --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 InvenSense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +static int inv_icm42600_spi_bus_setup(struct inv_icm42600_state *st) +{ + unsigned int mask, val; + int ret; + + /* setup interface registers */ + val = INV_ICM42600_INTF_CONFIG6_I3C_EN | + INV_ICM42600_INTF_CONFIG6_I3C_SDR_EN | + INV_ICM42600_INTF_CONFIG6_I3C_DDR_EN; + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6, +INV_ICM42600_INTF_CONFIG6_MASK, val); + if (ret) + return ret; + + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, +INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0); + if (ret) + return ret; + + /* set slew rates for I2C and SPI */ + mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK | + INV_ICM42600_DRIVE_CONFIG_SPI_MASK; + val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_20_60NS) | + INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_INF_2NS); + ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG, +mask, val); + if (ret) + return ret; + + /* disable i2c bus */ + return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS); +} + +static int inv_icm42600_probe(struct spi_device *spi) +{ + const void *match; + enum inv_icm42600_chip chip; + struct regmap *regmap; + + match = device_get_match_data(>dev); + if (!match) + return -EINVAL; + chip = (enum inv_icm42600_chip)match; + + regmap = devm_regmap_init_spi(spi, _icm42600_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return inv_icm42600_core_probe(regmap, chip, inv_icm42600_spi_bus_setup); +} + +static const struct of_device_id inv_icm42600_of_matches[] = { + { + .compatible = "invensense,icm42600", + .data = (void *)INV_CHIP_ICM42600, + }, { + .compatible = "invensense,icm42602", + .data = (void *)INV_CHIP_ICM42602, + }, { + .compatible = "invensense,icm42605", + .data = (void *)INV_CHIP_ICM42605, + }, { + .compatible = "invensense,icm42622", + .data = (void *)INV_CHIP_ICM42622, + }, + {} +}; +MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); + +static struct spi_driver inv_icm42600_driver = { + .driver = { + .name = "inv-icm42600-spi", + .of_match_table = inv_icm42600_of_matches, + .pm = _icm42600_pm_ops, + }, + .probe = inv_icm42600_probe, +}; +module_spi_driver(inv_icm42600_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-426xx SPI driver"); +MODULE_LICENSE("GPL"); -- 2.17.1
[PATCH v2 01/12] iio: imu: inv_icm42600: add core of new inv_icm42600 driver
Core component of a new driver for InvenSense ICM-426xx devices. It includes registers definition, main probe/setup, and device utility functions. ICM-426xx devices are latest generation of 6-axis IMU, gyroscope+accelerometer and temperature sensor. This device includes a 2K FIFO, supports I2C/I3C/SPI, and provides intelligent motion features like pedometer, tilt detection, and tap detection. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 372 ++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 635 ++ 2 files changed, 1007 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h new file mode 100644 index ..14c8ef152418 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#ifndef INV_ICM42600_H_ +#define INV_ICM42600_H_ + +#include +#include +#include +#include +#include +#include +#include + +enum inv_icm42600_chip { + INV_CHIP_ICM42600, + INV_CHIP_ICM42602, + INV_CHIP_ICM42605, + INV_CHIP_ICM42622, + INV_CHIP_NB, +}; + +/* serial bus slew rates */ +enum inv_icm42600_slew_rate { + INV_ICM42600_SLEW_RATE_20_60NS, + INV_ICM42600_SLEW_RATE_12_36NS, + INV_ICM42600_SLEW_RATE_6_18NS, + INV_ICM42600_SLEW_RATE_4_12NS, + INV_ICM42600_SLEW_RATE_2_6NS, + INV_ICM42600_SLEW_RATE_INF_2NS, +}; + +enum inv_icm42600_sensor_mode { + INV_ICM42600_SENSOR_MODE_OFF, + INV_ICM42600_SENSOR_MODE_STANDBY, + INV_ICM42600_SENSOR_MODE_LOW_POWER, + INV_ICM42600_SENSOR_MODE_LOW_NOISE, + INV_ICM42600_SENSOR_MODE_NB, +}; + +/* gyroscope fullscale values */ +enum inv_icm42600_gyro_fs { + INV_ICM42600_GYRO_FS_2000DPS, + INV_ICM42600_GYRO_FS_1000DPS, + INV_ICM42600_GYRO_FS_500DPS, + INV_ICM42600_GYRO_FS_250DPS, + INV_ICM42600_GYRO_FS_125DPS, + INV_ICM42600_GYRO_FS_62_5DPS, + INV_ICM42600_GYRO_FS_31_25DPS, + INV_ICM42600_GYRO_FS_15_625DPS, + INV_ICM42600_GYRO_FS_NB, +}; + +/* accelerometer fullscale values */ +enum inv_icm42600_accel_fs { + INV_ICM42600_ACCEL_FS_16G, + INV_ICM42600_ACCEL_FS_8G, + INV_ICM42600_ACCEL_FS_4G, + INV_ICM42600_ACCEL_FS_2G, + INV_ICM42600_ACCEL_FS_NB, +}; + +/* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */ +enum inv_icm42600_odr { + INV_ICM42600_ODR_8KHZ_LN = 3, + INV_ICM42600_ODR_4KHZ_LN, + INV_ICM42600_ODR_2KHZ_LN, + INV_ICM42600_ODR_1KHZ_LN, + INV_ICM42600_ODR_200HZ, + INV_ICM42600_ODR_100HZ, + INV_ICM42600_ODR_50HZ, + INV_ICM42600_ODR_25HZ, + INV_ICM42600_ODR_12_5HZ, + INV_ICM42600_ODR_6_25HZ_LP, + INV_ICM42600_ODR_3_125HZ_LP, + INV_ICM42600_ODR_1_5625HZ_LP, + INV_ICM42600_ODR_500HZ, + INV_ICM42600_ODR_NB, +}; + +enum inv_icm42600_filter { + /* Low-Noise mode sensor data filter (3rd order filter by default) */ + INV_ICM42600_FILTER_BW_ODR_DIV_2, + + /* Low-Power mode sensor data filter (averaging) */ + INV_ICM42600_FILTER_AVG_1X = 1, + INV_ICM42600_FILTER_AVG_16X = 6, +}; + +struct inv_icm42600_sensor_conf { + int mode; + int fs; + int odr; + int filter; +}; +#define INV_ICM42600_SENSOR_CONF_INIT {-1, -1, -1, -1} + +struct inv_icm42600_conf { + struct inv_icm42600_sensor_conf gyro; + struct inv_icm42600_sensor_conf accel; + bool temp_en; +}; + +struct inv_icm42600_suspended { + enum inv_icm42600_sensor_mode gyro; + enum inv_icm42600_sensor_mode accel; + bool temp; +}; + +/** + * struct inv_icm42600_state - driver state variables + * @lock: lock for serializing multiple registers access. + * @chip: chip identifier. + * @name: chip name. + * @map: regmap pointer. + * @vdd_supply: VDD voltage regulator for the chip. + * @vddio_supply: I/O voltage regulator for the chip. + * @orientation: sensor chip orientation relative to main hardware. + * @conf: chip sensors configurations. + * @suspended:suspended sensors configuration. + */ +struct inv_icm42600_state { + struct mutex lock; + enum inv_icm42600_chip chip; + const char *name; + struct regmap *map; + struct regulator *vdd_supply; + struct regulator *vddio_supply; + struct iio_mount_matrix orientation; + struct inv_icm42600_conf conf; + struct inv_icm42600_suspended suspended; +}; + +/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ + +/* Bank selection register, available in all banks */ +#define
[PATCH v2 08/12] iio: imu: inv_icm42600: add device interrupt
Add INT1 interrupt support. Support interrupt edge and level, active high or low. Push-pull or open-drain configurations. Interrupt will be used to read data from the FIFO. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 2 +- .../iio/imu/inv_icm42600/inv_icm42600_core.c | 96 ++- .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 3 +- .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 3 +- 4 files changed, 100 insertions(+), 4 deletions(-) diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index c534acae0308..43749f56426c 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -372,7 +372,7 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable, int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval); -int inv_icm42600_core_probe(struct regmap *regmap, int chip, +int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, inv_icm42600_bus_setup bus_setup); int inv_icm42600_gyro_init(struct inv_icm42600_state *st); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index e7f7835aca9b..246c1eb52231 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -9,8 +9,11 @@ #include #include #include +#include +#include #include #include +#include #include #include @@ -409,6 +412,79 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st, return inv_icm42600_set_conf(st, hw->conf); } +static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data) +{ + struct inv_icm42600_state *st = _data; + struct device *dev = regmap_get_device(st->map); + unsigned int status; + int ret; + + mutex_lock(>lock); + + ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, ); + if (ret) + goto out_unlock; + + /* FIFO full */ + if (status & INV_ICM42600_INT_STATUS_FIFO_FULL) + dev_warn(dev, "FIFO full data lost!\n"); + +out_unlock: + mutex_unlock(>lock); + return IRQ_HANDLED; +} + +/** + * inv_icm42600_irq_init() - initialize int pin and interrupt handler + * @st:driver internal state + * @irq: irq number + * @irq_type: irq trigger type + * @open_drain:true if irq is open drain, false for push-pull + * + * Returns 0 on success, a negative error code otherwise. + */ +static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq, +int irq_type, bool open_drain) +{ + struct device *dev = regmap_get_device(st->map); + unsigned int val; + int ret; + + /* configure INT1 interrupt: default is active low on edge */ + switch (irq_type) { + case IRQF_TRIGGER_RISING: + case IRQF_TRIGGER_HIGH: + val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH; + break; + default: + val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW; + break; + } + switch (irq_type) { + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_HIGH: + val |= INV_ICM42600_INT_CONFIG_INT1_LATCHED; + break; + default: + break; + } + if (!open_drain) + val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL; + ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val); + if (ret) + return ret; + + /* Deassert async reset for proper INT pin operation (cf datasheet) */ + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1, +INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0); + if (ret) + return ret; + + return devm_request_threaded_irq(dev, irq, NULL, +inv_icm42600_irq_handler, irq_type, +"inv_icm42600", st); +} + static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st) { int ret; @@ -453,11 +529,14 @@ static void inv_icm42600_disable_pm(void *_data) pm_runtime_disable(dev); } -int inv_icm42600_core_probe(struct regmap *regmap, int chip, +int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, inv_icm42600_bus_setup bus_setup) { struct device *dev = regmap_get_device(regmap); struct inv_icm42600_state *st; + struct irq_data *irq_desc; + int irq_type; + bool open_drain; int ret; if (chip < 0 || chip >= INV_CHIP_NB) { @@ -465,6 +544,17 @@ int inv_icm42600_core_probe(struct reg
[PATCH v2 07/12] iio: imu: add Kconfig and Makefile for inv_icm42600 driver
Add 3 modules: inv-icm42600, inv-icm42600-i2c, inv-icm42600-spi. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42600/Kconfig | 28 +++ drivers/iio/imu/inv_icm42600/Makefile | 13 + 4 files changed, 43 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/Kconfig create mode 100644 drivers/iio/imu/inv_icm42600/Makefile diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index fc4123d518bc..f02883b08480 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -91,6 +91,7 @@ config KMX61 To compile this driver as module, choose M here: the module will be called kmx61. +source "drivers/iio/imu/inv_icm42600/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" source "drivers/iio/imu/st_lsm6dsx/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 88b2c4555230..13e9ff442b11 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_FXOS8700) += fxos8700_core.o obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o +obj-y += inv_icm42600/ obj-y += inv_mpu6050/ obj-$(CONFIG_KMX61) += kmx61.o diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig new file mode 100644 index ..22390a72f0a3 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/Kconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config INV_ICM42600 + tristate + +config INV_ICM42600_I2C + tristate "InvenSense ICM-426xx I2C driver" + depends on I2C + select INV_ICM42600 + select REGMAP_I2C + help + This driver supports the InvenSense ICM-426xx motion tracking + devices over I2C. + + This driver can be built as a module. The module will be called + inv-icm42600-i2c. + +config INV_ICM42600_SPI + tristate "InvenSense ICM-426xx SPI driver" + depends on SPI_MASTER + select INV_ICM42600 + select REGMAP_SPI + help + This driver supports the InvenSense ICM-426xx motion tracking + devices over SPI. + + This driver can be built as a module. The module will be called + inv-icm42600-spi. diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile new file mode 100644 index ..48965824f00c --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-$(CONFIG_INV_ICM42600) += inv-icm42600.o +inv-icm42600-y += inv_icm42600_core.o +inv-icm42600-y += inv_icm42600_gyro.o +inv-icm42600-y += inv_icm42600_accel.o +inv-icm42600-y += inv_icm42600_temp.o + +obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o +inv-icm42600-i2c-y += inv_icm42600_i2c.o + +obj-$(CONFIG_INV_ICM42600_SPI) += inv-icm42600-spi.o +inv-icm42600-spi-y += inv_icm42600_spi.o -- 2.17.1
[PATCH v2 04/12] iio: imu: inv_icm42600: add gyroscope IIO device
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 --- 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 ..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 +#include +#include +#include +#include +#include +#include +#include + +#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_mo
[PATCH v2 00/12] iio: imu: new inv_icm42600 driver
Changelog v1 -initial patch submission v2 - formatting reworks, missing headers, code cleanup ... - delete all debug traces - add commentaries for better explanation of suspend/resume, timestamp, ... - delete i2c/spi table ids keeping only of, and use I2C probe_new function - switch calibbias to SI units and add calibias_available attribute - use DMA-safe buffer for all regmap_bulk_* calls - delete iio trigger usage and setup/handle interrupt in core module - add open-drain interrupt support - add FIFO on reference counter and buffer postenable/predisable to replace iio trigger usage - check that temperature data is present before copying in buffer - add temperature sensor off when fifo is turned off - delete timestamp channel reading - move timestamp state in IIO device private data - allow only 1 ODR change in a batch of data - add driver-open-drain in devicetree YAML and delete spi options This series add a new driver for managing InvenSense ICM-426xx 6-axis IMUs. This next generation of chips includes new generations of 3-axis gyroscope and 3-axis accelerometer, support of I3C in addition to I2C and SPI, and intelligent MotionTracking features like pedometer, tilt detection, and tap detection. This series is delivering a driver supporting gyroscope, accelerometer and temperature data, with polling and buffering using hwfifo and watermark, on I2C and SPI busses. Gyroscope and accelerometer sensors are completely independent and can have different ODRs. Since there is only a single FIFO a specific value is used to mark invalid data. For keeping the device standard we are de-multiplexing data from the FIFO to 2 IIO devices with 2 buffers, 1 for the accelerometer and 1 for the gyroscope. This architecture also enables to easily turn each sensor on/off without impacting the other. The device interrupt is used to read the FIFO and launch parsing of accelerometer and gyroscope data. A complex timestamping mechanism is added to handle correctly FIFO watermark and dynamic changes of settings. Jean-Baptiste Maneyrol (12): iio: imu: inv_icm42600: add core of new inv_icm42600 driver iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver iio: imu: inv_icm42600: add SPI driver for inv_icm42600 driver iio: imu: inv_icm42600: add gyroscope IIO device iio: imu: inv_icm42600: add accelerometer IIO device iio: imu: inv_icm42600: add temperature sensor support iio: imu: add Kconfig and Makefile for inv_icm42600 driver iio: imu: inv_icm42600: add device interrupt iio: imu: inv_icm42600: add buffer support in iio devices iio: imu: inv_icm42600: add accurate timestamping dt-bindings: iio: imu: Add inv_icm42600 documentation MAINTAINERS: add entry for inv_icm42600 6-axis imu sensor .../bindings/iio/imu/invensense,icm42600.yaml | 86 ++ MAINTAINERS | 8 + drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42600/Kconfig | 29 + drivers/iio/imu/inv_icm42600/Makefile | 15 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 395 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 784 + .../imu/inv_icm42600/inv_icm42600_buffer.c| 583 + .../imu/inv_icm42600/inv_icm42600_buffer.h| 98 +++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 782 + .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 795 ++ .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 101 +++ .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 100 +++ .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 87 ++ .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 30 + .../imu/inv_icm42600/inv_icm42600_timestamp.c | 195 + .../imu/inv_icm42600/inv_icm42600_timestamp.h | 85 ++ 18 files changed, 4175 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml create mode 100644 drivers/iio/imu/inv_icm42600/Kconfig create mode 100644 drivers/iio/imu/inv_icm42600/Makefile create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.h -- 2.17.1
[PATCH v2 10/12] iio: imu: inv_icm42600: add accurate timestamping
Add a timestamping mechanism for buffer that provides accurate event timestamps when using watermark. This mechanism estimates device internal clock by comparing FIFO interrupts delta time and device elapsed time computed by parsing FIFO data. Take interrupt timestamp in hard irq handler and add IIO device specific timestamp structures in device private allocation. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/Makefile | 1 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 5 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 40 +++- .../imu/inv_icm42600/inv_icm42600_buffer.c| 28 +++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 17 +- .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 40 +++- .../imu/inv_icm42600/inv_icm42600_timestamp.c | 195 ++ .../imu/inv_icm42600/inv_icm42600_timestamp.h | 85 8 files changed, 398 insertions(+), 13 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.h diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile index 0f49f6df3647..291714d9aa54 100644 --- a/drivers/iio/imu/inv_icm42600/Makefile +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -6,6 +6,7 @@ inv-icm42600-y += inv_icm42600_gyro.o inv-icm42600-y += inv_icm42600_accel.o inv-icm42600-y += inv_icm42600_temp.o inv-icm42600-y += inv_icm42600_buffer.o +inv-icm42600-y += inv_icm42600_timestamp.o obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o inv-icm42600-i2c-y += inv_icm42600_i2c.o diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 4d5811562a61..2de0dd7675fb 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -126,6 +126,7 @@ struct inv_icm42600_suspended { * @indio_accel: accelerometer IIO device. * @buffer: data transfer buffer aligned for DMA. * @fifo: FIFO management structure. + * @timestamp:interrupt timestamps. */ struct inv_icm42600_state { struct mutex lock; @@ -141,6 +142,10 @@ struct inv_icm42600_state { struct iio_dev *indio_accel; uint8_t buffer[2] cacheline_aligned; struct inv_icm42600_fifo fifo; + struct { + int64_t gyro; + int64_t accel; + } timestamp; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index c73ce204efc6..ec1d124c1471 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -17,6 +17,7 @@ #include "inv_icm42600.h" #include "inv_icm42600_temp.h" #include "inv_icm42600_buffer.h" +#include "inv_icm42600_timestamp.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -50,6 +51,7 @@ enum inv_icm42600_accel_scan { INV_ICM42600_ACCEL_SCAN_Y, INV_ICM42600_ACCEL_SCAN_Z, INV_ICM42600_ACCEL_SCAN_TEMP, + INV_ICM42600_ACCEL_SCAN_TIMESTAMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { @@ -65,13 +67,15 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, inv_icm42600_accel_ext_infos), INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), + IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42600_ACCEL_SCAN_TIMESTAMP), }; -/* IIO buffer data: 8 bytes */ +/* IIO buffer data: 16 bytes */ struct inv_icm42600_accel_buffer { struct inv_icm42600_fifo_sensor_data accel; int8_t temp; uint8_t padding; + int64_t timestamp; }; #define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \ @@ -92,6 +96,7 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_timestamp *ts = iio_priv(indio_dev); struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; unsigned int fifo_en = 0; unsigned int sleep_temp = 0; @@ -119,6 +124,7 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, } /* update data FIFO write */ + inv_icm42600_timestamp_apply_odr(ts, 0, 0, 0); ret = inv_icm42600_buffer_set_fifo_en(st, fifo_en | st->fifo.en); if (ret) goto out_unlock; @@ -299,9 +305,11 @@ static int inv_icm42600_accel_read_odr(struct inv_icm42600_state
[PATCH v2 02/12] iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver
Add I2C driver for InvenSense ICM-426xxx devices. Configure bus signal slew rates as indicated in the datasheet. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 100 ++ 1 file changed, 100 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c new file mode 100644 index ..4789cead23b3 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 InvenSense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st) +{ + unsigned int mask, val; + int ret; + + /* setup interface registers */ + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6, +INV_ICM42600_INTF_CONFIG6_MASK, +INV_ICM42600_INTF_CONFIG6_I3C_EN); + if (ret) + return ret; + + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, +INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0); + if (ret) + return ret; + + /* set slew rates for I2C and SPI */ + mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK | + INV_ICM42600_DRIVE_CONFIG_SPI_MASK; + val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_12_36NS) | + INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_12_36NS); + ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG, +mask, val); + if (ret) + return ret; + + /* disable SPI bus */ + return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, + INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS); +} + +static int inv_icm42600_probe(struct i2c_client *client) +{ + const void *match; + enum inv_icm42600_chip chip; + struct regmap *regmap; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENOTSUPP; + + match = device_get_match_data(>dev); + if (!match) + return -EINVAL; + chip = (enum inv_icm42600_chip)match; + + regmap = devm_regmap_init_i2c(client, _icm42600_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return inv_icm42600_core_probe(regmap, chip, inv_icm42600_i2c_bus_setup); +} + +static const struct of_device_id inv_icm42600_of_matches[] = { + { + .compatible = "invensense,icm42600", + .data = (void *)INV_CHIP_ICM42600, + }, { + .compatible = "invensense,icm42602", + .data = (void *)INV_CHIP_ICM42602, + }, { + .compatible = "invensense,icm42605", + .data = (void *)INV_CHIP_ICM42605, + }, { + .compatible = "invensense,icm42622", + .data = (void *)INV_CHIP_ICM42622, + }, + {} +}; +MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); + +static struct i2c_driver inv_icm42600_driver = { + .driver = { + .name = "inv-icm42600-i2c", + .of_match_table = inv_icm42600_of_matches, + .pm = _icm42600_pm_ops, + }, + .probe_new = inv_icm42600_probe, +}; +module_i2c_driver(inv_icm42600_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-426xx I2C driver"); +MODULE_LICENSE("GPL"); -- 2.17.1
[PATCH v2 05/12] iio: imu: inv_icm42600: add accelerometer IIO device
Add IIO device for accelerometer sensor with data polling interface. Attributes: raw, scale, sampling_frequency, calibbias. Accelerometer in low noise mode. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 4 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 589 ++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 4 + 3 files changed, 597 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index c1023d59b37b..c534acae0308 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -121,6 +121,7 @@ struct inv_icm42600_suspended { * @conf: chip sensors configurations. * @suspended:suspended sensors configuration. * @indio_gyro: gyroscope IIO device. + * @indio_accel: accelerometer IIO device. * @buffer: data transfer buffer aligned for DMA. */ struct inv_icm42600_state { @@ -134,6 +135,7 @@ struct inv_icm42600_state { struct inv_icm42600_conf conf; struct inv_icm42600_suspended suspended; struct iio_dev *indio_gyro; + struct iio_dev *indio_accel; uint8_t buffer[2] cacheline_aligned; }; @@ -375,4 +377,6 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int inv_icm42600_gyro_init(struct inv_icm42600_state *st); +int inv_icm42600_accel_init(struct inv_icm42600_state *st); + #endif diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c new file mode 100644 index ..7620ce1958e0 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -0,0 +1,589 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +#define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ + { \ + .type = IIO_ACCEL, \ + .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_accel_scan { + INV_ICM42600_ACCEL_SCAN_X, + INV_ICM42600_ACCEL_SCAN_Y, + INV_ICM42600_ACCEL_SCAN_Z, +}; + +static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42600_get_mount_matrix), + {}, +}; + +static const struct iio_chan_spec inv_icm42600_accel_channels[] = { + INV_ICM42600_ACCEL_CHAN(IIO_MOD_X, INV_ICM42600_ACCEL_SCAN_X, + inv_icm42600_accel_ext_infos), + INV_ICM42600_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42600_ACCEL_SCAN_Y, + inv_icm42600_accel_ext_infos), + INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, + inv_icm42600_accel_ext_infos), +}; + +static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st, + struct iio_chan_spec const *chan, + int16_t *val) +{ + struct device *dev = regmap_get_device(st->map); +
[PATCH v2 06/12] iio: imu: inv_icm42600: add temperature sensor support
Add temperature channel in gyroscope and accelerometer devices. Temperature is available in full 16 bits resolution as a processed channel. Scale and offset attributes are also provided for the low 8 bits resolution raw temperature found in the FIFO. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 11 ++- .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 11 ++- .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 87 +++ .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 30 +++ 4 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 7620ce1958e0..6a615d7ffb24 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -13,6 +13,7 @@ #include #include "inv_icm42600.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -45,6 +46,7 @@ enum inv_icm42600_accel_scan { INV_ICM42600_ACCEL_SCAN_X, INV_ICM42600_ACCEL_SCAN_Y, INV_ICM42600_ACCEL_SCAN_Z, + INV_ICM42600_ACCEL_SCAN_TEMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { @@ -59,6 +61,7 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { inv_icm42600_accel_ext_infos), INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, inv_icm42600_accel_ext_infos), + INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), }; static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st, @@ -450,8 +453,14 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev, int16_t data; int ret; - if (chan->type != IIO_ACCEL) + switch (chan->type) { + case IIO_ACCEL: + break; + case IIO_TEMP: + return inv_icm42600_temp_read_raw(indio_dev, chan, val, val2, mask); + default: return -EINVAL; + } switch (mask) { case IIO_CHAN_INFO_RAW: diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index 9d9672989b23..38654e0d217b 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -13,6 +13,7 @@ #include #include "inv_icm42600.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \ { \ @@ -45,6 +46,7 @@ enum inv_icm42600_gyro_scan { INV_ICM42600_GYRO_SCAN_X, INV_ICM42600_GYRO_SCAN_Y, INV_ICM42600_GYRO_SCAN_Z, + INV_ICM42600_GYRO_SCAN_TEMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_gyro_ext_infos[] = { @@ -59,6 +61,7 @@ static const struct iio_chan_spec inv_icm42600_gyro_channels[] = { inv_icm42600_gyro_ext_infos), INV_ICM42600_GYRO_CHAN(IIO_MOD_Z, INV_ICM42600_GYRO_SCAN_Z, inv_icm42600_gyro_ext_infos), + INV_ICM42600_TEMP_CHAN(INV_ICM42600_GYRO_SCAN_TEMP), }; static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st, @@ -461,8 +464,14 @@ static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev, int16_t data; int ret; - if (chan->type != IIO_ANGL_VEL) + switch (chan->type) { + case IIO_ANGL_VEL: + break; + case IIO_TEMP: + return inv_icm42600_temp_read_raw(indio_dev, chan, val, val2, mask); + default: return -EINVAL; + } switch (mask) { case IIO_CHAN_INFO_RAW: diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c new file mode 100644 index ..b0871352fe39 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" +#include "inv_icm42600_temp.h" + +static int inv_icm42600_temp_read(struct inv_icm42600_state *st, int32_t *temp) +{ + struct device *dev = regmap_get_device(st->map); + int64_t data; + __be16 *raw; + int16_t val; + int ret; + + pm_runtime_get_sync(dev); + mutex_lock(>lock); + + ret = inv_icm42600_set_temp_conf(st, true, NULL); +
Re: [PATCH 10/12] iio: imu: inv_icm42600: add accurate timestamping
Hi Jonathan, reading timestamp register is here mainly because we can do it, and this is the only way to have the full 20 bits resolution. But it is not very useful indeed. I will delete it. I am not using timestamp stored inside the FIFO, because it is only present when having both accel and gyro on. There is no timestamp data for a single sensor, which is really too bad. That would have been helpful. I will add more documentation about it. It is not that tricky, but need more deep explanations. New series V2 is in preparation. And again my apologizes for ruining the mail text formatting. Thanks, JB From: Jonathan Cameron Sent: Friday, May 8, 2020 16:42 To: Jean-Baptiste Maneyrol Cc: ji...@kernel.org ; robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH 10/12] iio: imu: inv_icm42600: add accurate timestamping 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 Thu, 7 May 2020 16:42:20 +0200 Jean-Baptiste Maneyrol wrote: > Add a timestamp channel with processed value that returns full > precision 20 bits timestamp. > > Add a timestamping mechanism for buffer that provides accurate > event timestamps when using watermark. This mechanism estimates > device internal clock by comparing FIFO interrupts delta time and > corresponding device elapsed time computed by parsing FIFO data. Yikes. That is complex. Hmm. I always get lost in the maths in these timestamp patches so my review may be a little superficial. However a bit more in the way of docs would be good here. The sysfs read of timestamp is unusual and I'm not really sure what it is for. The delays in a sysfs read of that value are likely to be enough that it's that useful for anything. Also, do we make use of the timestamps within the fifo records? J > > Signed-off-by: Jean-Baptiste Maneyrol > --- > drivers/iio/imu/inv_icm42600/Makefile | 1 + > drivers/iio/imu/inv_icm42600/inv_icm42600.h | 10 +- > .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 32 ++- > .../imu/inv_icm42600/inv_icm42600_buffer.c | 28 +- > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 6 + > .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 32 ++- > .../imu/inv_icm42600/inv_icm42600_timestamp.c | 246 ++ > .../imu/inv_icm42600/inv_icm42600_timestamp.h | 82 ++ > 8 files changed, 421 insertions(+), 16 deletions(-) > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.h > > diff --git a/drivers/iio/imu/inv_icm42600/Makefile > b/drivers/iio/imu/inv_icm42600/Makefile > index d6732118010c..1197b545a682 100644 > --- a/drivers/iio/imu/inv_icm42600/Makefile > +++ b/drivers/iio/imu/inv_icm42600/Makefile > @@ -7,6 +7,7 @@ inv-icm42600-y += inv_icm42600_accel.o > inv-icm42600-y += inv_icm42600_temp.o > inv-icm42600-y += inv_icm42600_trigger.o > inv-icm42600-y += inv_icm42600_buffer.o > +inv-icm42600-y += inv_icm42600_timestamp.o > > obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o > inv-icm42600-i2c-y += inv_icm42600_i2c.o > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h > b/drivers/iio/imu/inv_icm42600/inv_icm42600.h > index 947ca4dd245b..e15eddafe009 100644 > --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h > @@ -16,6 +16,7 @@ > #include > > #include "inv_icm42600_buffer.h" > +#include "inv_icm42600_timestamp.h" > > enum inv_icm42600_chip { > INV_CHIP_ICM42600, > @@ -127,6 +128,7 @@ struct inv_icm42600_suspended { > * @indio_accel: accelerometer IIO device. > * @trigger: device internal interrupt trigger > * @fifo: FIFO management structure. > + * @timestamp: timestamp management structure. > */ > struct inv_icm42600_state { > struct mutex lock; > @@ -142,6 +144,10 @@ struct inv_icm42600_state { > struct iio_dev *indio_accel; > struct iio_trigger *trigger; > struct inv_icm42600_fifo fifo; > + struct { > + struct inv_icm42600_timestamp gyro; > + struct inv_icm42600_timestamp accel; > + } timestamp; > }; > > /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB >*/ > @@ -382,11 +388,11 @@ int inv_icm42600_core_probe(struct regmap *regm
Re: [PATCH 08/12] iio: imu: inv_icm42600: add device interrupt trigger
Hi Jonathan, you're right, making a trigger is not very useful. I will move this code to the buffer file or rename the file, and replace the triggered buffer setup in iio devices. Thanks, JB From: Jonathan Cameron Sent: Friday, May 8, 2020 16:22 To: Jean-Baptiste Maneyrol Cc: ji...@kernel.org ; robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH 08/12] iio: imu: inv_icm42600: add device interrupt trigger 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 Thu, 7 May 2020 16:42:18 +0200 Jean-Baptiste Maneyrol wrote: > Add INT1 interrupt support and use it as an iio trigger. > Support interrupt edge and level, active high or low. > Push-pull configuration only. > > Trigger enables FIFO and will be useful with buffer support. > > Signed-off-by: Jean-Baptiste Maneyrol So it's an odd trigger... But you check its only used for the device itself which stops that being visible to anyone. The open question in my mind is why we need a trigger at all? If there is no advantage we don't need to expose that. Can just directly call the buffer functions from the interrupt handler. It's perfectly acceptable to not have a trigger exposed if: * It would only be useful for the device providing it. * You don't need to use it to select between various options. For some of the other fifo devices IIRC we do support other triggers but if you don't provide one the local fifo is used. Here I don't think we actually support other triggers though we don't prevent them being used? So even simpler. With the complex interleaved fifo I suspect it would be hard to support other triggers anyway except in a trivial poll like mode so probably not of interest to anyone... J > --- > drivers/iio/imu/inv_icm42600/Kconfig | 1 + > drivers/iio/imu/inv_icm42600/Makefile | 1 + > drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 +- > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 19 +- > .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 2 +- > .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 2 +- > .../imu/inv_icm42600/inv_icm42600_trigger.c | 177 ++ > 7 files changed, 206 insertions(+), 4 deletions(-) > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_trigger.c > > diff --git a/drivers/iio/imu/inv_icm42600/Kconfig > b/drivers/iio/imu/inv_icm42600/Kconfig > index 22390a72f0a3..7b3eaeb2aa4a 100644 > --- a/drivers/iio/imu/inv_icm42600/Kconfig > +++ b/drivers/iio/imu/inv_icm42600/Kconfig > @@ -2,6 +2,7 @@ > > config INV_ICM42600 > tristate > + select IIO_TRIGGER > > config INV_ICM42600_I2C > tristate "InvenSense ICM-426xx I2C driver" > diff --git a/drivers/iio/imu/inv_icm42600/Makefile > b/drivers/iio/imu/inv_icm42600/Makefile > index 48965824f00c..e1f2aacbe888 100644 > --- a/drivers/iio/imu/inv_icm42600/Makefile > +++ b/drivers/iio/imu/inv_icm42600/Makefile > @@ -5,6 +5,7 @@ inv-icm42600-y += inv_icm42600_core.o > inv-icm42600-y += inv_icm42600_gyro.o > inv-icm42600-y += inv_icm42600_accel.o > inv-icm42600-y += inv_icm42600_temp.o > +inv-icm42600-y += inv_icm42600_trigger.o > > obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o > inv-icm42600-i2c-y += inv_icm42600_i2c.o > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h > b/drivers/iio/imu/inv_icm42600/inv_icm42600.h > index bc963b3d1800..175c1f67faee 100644 > --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h > @@ -13,6 +13,7 @@ > #include > #include > #include > +#include > > enum inv_icm42600_chip { > INV_CHIP_ICM42600, > @@ -122,6 +123,7 @@ struct inv_icm42600_suspended { > * @suspended: suspended sensors configuration. > * @indio_gyro: gyroscope IIO device. > * @indio_accel: accelerometer IIO device. > + * @trigger: device internal interrupt trigger > */ > struct inv_icm42600_state { > struct mutex lock; > @@ -135,6 +137,7 @@ struct inv_icm42600_state { > struct inv_icm42600_suspended suspended; > struct iio_dev *indio_gyro; > struct iio_dev *indio_accel; > + struct iio_trigger *trigger; > }; > > /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB >*/ > @@ -370,11 +373,14 @@ int inv_icm42600_set_temp_conf(stru
Re: [PATCH 04/12] iio: imu: inv_icm42600: add gyroscope IIO device
Hi Jonathan, I agree with all comments. For regmap_bulk_read, by looking at source code it doesn't seem to requires specific alignment, except if bus read callback is expecting that. But I can see numerous drivers calling regmap_bulk_read with a data buffer on the stack and not particularly aligned. And we definitely can read calibration offset registers while running, the lock is indeed not needed. Thanks, JB From: Jonathan Cameron Sent: Friday, May 8, 2020 16:01 To: Jean-Baptiste Maneyrol Cc: ji...@kernel.org ; robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH 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 Thu, 7 May 2020 16:42:14 +0200 Jean-Baptiste Maneyrol 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 Few trivial things and questions inline. J > --- > drivers/iio/imu/inv_icm42600/inv_icm42600.h | 4 + > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 5 + > .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 549 ++ > 3 files changed, 558 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 8da4c8249aed..ca41a9d6404a 100644 > --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h > @@ -120,6 +120,7 @@ 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. > */ > struct inv_icm42600_state { > struct mutex lock; > @@ -131,6 +132,7 @@ struct inv_icm42600_state { > struct iio_mount_matrix orientation; > struct inv_icm42600_conf conf; > struct inv_icm42600_suspended suspended; > + struct iio_dev *indio_gyro; > }; > > /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB >*/ > @@ -369,4 +371,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 35bdf4f9d31e..151257652ce6 100644 > --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c > @@ -503,6 +503,11 @@ int inv_icm42600_core_probe(struct regmap *regmap, int > chip, > if (ret) > return ret; > > + /* create and init gyroscope iio device */ 'Kind' of obvious from function name? Maybe drop the comment? > + 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 ..74aa2b5fa611 > --- /dev/null > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c > @@ -0,0 +1,549 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (C) 2020 Invensense, Inc. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "inv_icm42600.h" > + > +#define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \ > + { \ > + .type = IIO_ANGL_VEL, \ > + .modified = 1, \ > + .channel2 = _modifier, \ > + .info_mask_separate =
Re: [PATCH 09/12] iio: imu: inv_icm42600: add buffer support in iio devices
Hi Jonathan, no problem with the comments. fifo_decode_packet will move to source code, For the following sleep comment: > + if (sleep_gyro > sleep_temp) > + sleep = sleep_gyro; > + else > + sleep = sleep_temp; > + if (sleep) > + msleep(sleep); if (sleep_gyro > sleep_temp) msleep(sleep_gyro); else msleep(sleep_temp); I am using an intermediate local variable to avoid a call to msleep(0) which is in fact sleeping for real for 1 jiffies as far as I understand. So is it OK to keep it as is? Thanks, JB From: Jonathan Cameron Sent: Friday, May 8, 2020 16:19 To: Jean-Baptiste Maneyrol Cc: ji...@kernel.org ; robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH 09/12] iio: imu: inv_icm42600: add buffer support in iio devices 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 Thu, 7 May 2020 16:42:19 +0200 Jean-Baptiste Maneyrol wrote: > Use triggered buffer by parsing FIFO data read in device trigger. > Support hwfifo watermark by multiplexing gyro and accel settings. > Support hwfifo flush. > > Simply use interrupt timestamp first. > > Signed-off-by: Jean-Baptiste Maneyrol > --- > drivers/iio/imu/inv_icm42600/Kconfig | 3 +- > drivers/iio/imu/inv_icm42600/Makefile | 1 + > drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 + > .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 183 + > .../imu/inv_icm42600/inv_icm42600_buffer.c | 353 ++ > .../imu/inv_icm42600/inv_icm42600_buffer.h | 162 > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 23 ++ > .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 183 + > .../imu/inv_icm42600/inv_icm42600_trigger.c | 15 +- > 9 files changed, 928 insertions(+), 3 deletions(-) > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h > > diff --git a/drivers/iio/imu/inv_icm42600/Kconfig > b/drivers/iio/imu/inv_icm42600/Kconfig > index 7b3eaeb2aa4a..8c0969319c49 100644 > --- a/drivers/iio/imu/inv_icm42600/Kconfig > +++ b/drivers/iio/imu/inv_icm42600/Kconfig > @@ -2,7 +2,8 @@ > > config INV_ICM42600 > tristate > - select IIO_TRIGGER > + select IIO_BUFFER > + select IIO_TRIGGERED_BUFFER > > config INV_ICM42600_I2C > tristate "InvenSense ICM-426xx I2C driver" > diff --git a/drivers/iio/imu/inv_icm42600/Makefile > b/drivers/iio/imu/inv_icm42600/Makefile > index e1f2aacbe888..d6732118010c 100644 > --- a/drivers/iio/imu/inv_icm42600/Makefile > +++ b/drivers/iio/imu/inv_icm42600/Makefile > @@ -6,6 +6,7 @@ inv-icm42600-y += inv_icm42600_gyro.o > inv-icm42600-y += inv_icm42600_accel.o > inv-icm42600-y += inv_icm42600_temp.o > inv-icm42600-y += inv_icm42600_trigger.o > +inv-icm42600-y += inv_icm42600_buffer.o > > obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o > inv-icm42600-i2c-y += inv_icm42600_i2c.o > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h > b/drivers/iio/imu/inv_icm42600/inv_icm42600.h > index 175c1f67faee..947ca4dd245b 100644 > --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h > @@ -15,6 +15,8 @@ > #include > #include > > +#include "inv_icm42600_buffer.h" > + > enum inv_icm42600_chip { > INV_CHIP_ICM42600, > INV_CHIP_ICM42602, > @@ -124,6 +126,7 @@ struct inv_icm42600_suspended { > * @indio_gyro: gyroscope IIO device. > * @indio_accel: accelerometer IIO device. > * @trigger: device internal interrupt trigger > + * @fifo: FIFO management structure. > */ > struct inv_icm42600_state { > struct mutex lock; > @@ -138,6 +141,7 @@ struct inv_icm42600_state { > struct iio_dev *indio_gyro; > struct iio_dev *indio_accel; > struct iio_trigger *trigger; > + struct inv_icm42600_fifo fifo; > }; > > /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB >*/ > @@ -378,8 +382,12 @@ int inv_icm42600_core_probe(struct regmap *regmap, int > chip, int irq, > > int inv_icm42600_gyro_init(struct inv_icm42600_state *st); > > +
Re: [PATCH 02/12] iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver
Hi Jonathan, I am using generic device_get_match_data because I was thinking it was now the way to go. But since only of is supported with the driver, I can switch to using of_device_get_match_data instead. Tell me what do you think is better. I could definitely use the new probe interface indeed, good idea. Thanks, JB From: Jonathan Cameron Sent: Friday, May 8, 2020 15:44 To: Jean-Baptiste Maneyrol Cc: ji...@kernel.org ; robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH 02/12] iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver 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 Thu, 7 May 2020 16:42:12 +0200 Jean-Baptiste Maneyrol wrote: > Add I2C driver for InvenSense ICM-426xxx devices. > > Configure bus signal slew rates as indicated in the datasheet. > > Signed-off-by: Jean-Baptiste Maneyrol Some incoherent rambling inline. + a few comments Jonathan > --- > .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 117 ++ > 1 file changed, 117 insertions(+) > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c > > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c > b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c > new file mode 100644 > index ..b61f993beacf > --- /dev/null > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c > @@ -0,0 +1,117 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (C) 2020 InvenSense, Inc. > + */ > + > +#include > +#include > +#include > +#include > +#include Why? Looks like you need the table and the device property stuff neither of which are in that file. linux/mod_devicetable.h linux/property.h > + > +#include "inv_icm42600.h" > + > +static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st) > +{ > + unsigned int mask, val; > + int ret; > + > + /* setup interface registers */ > + mask = INV_ICM42600_INTF_CONFIG6_MASK; > + val = INV_ICM42600_INTF_CONFIG6_I3C_EN; > + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6, > + mask, val); I'd put the values inline where they are simple like these rather than using local variables. > + if (ret) > + return ret; > + > + mask = INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY; > + val = 0; > + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, > + mask, val); > + if (ret) > + return ret; > + > + /* set slew rates for I2C and SPI */ > + mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK | > + INV_ICM42600_DRIVE_CONFIG_SPI_MASK; > + val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_12_36NS) | > + INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_12_36NS); > + ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG, > + mask, val); > + if (ret) > + return ret; > + > + /* disable SPI bus */ > + mask = INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK; > + val = INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS; > + return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, > + mask, val); > +} > + > +static int inv_icm42600_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + const void *match; > + enum inv_icm42600_chip chip; > + struct regmap *regmap; > + > + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) > + return -ENOTSUPP; > + > + match = device_get_match_data(>dev); Hmm. Annoyingly if one were to call the of specific option of i2c_of_match_device it would handle the old style i2c match just fine without needing special handling. However, it would fail to handle PRP0001 ACPI. Rather feels like there should be something similar for device_get_match_data so we could use the probe_new version of i2c device probing. Oh well. I guess thats a separate question for another day ;) Mind you can we actually probe this driver via the sysfs route? If not why do we need to handle the non firmware case at all? > + if (match) > + chip = (enum inv_icm42600_chip)match; > +
Re: [PATCH 01/12] iio: imu: inv_icm42600: add core of new inv_icm42600 driver
Hi Jonathan, thanks for the feedbacks, I'm sorry but I will not be able to have a correct email formatting to respond you inline. No problem with all the comments. For iio_device_get_drvdata, it would make more sense to use a const struct iio_dev * as argument. I am obliged to do the pointer conversion since iio_get_mount_matrix requires the use of a const struct iio_dev *. For resume/suspend, I will add commentaries to explain what it is really doing and for which purpose. Sensor states save and restore will remain in this patch, since it makes more sense to have it as a core functionnality, as much as gyro/accel turn on/off. Thanks. JB From: linux-iio-ow...@vger.kernel.org on behalf of Jonathan Cameron Sent: Friday, May 8, 2020 15:28 To: Jean-Baptiste Maneyrol Cc: ji...@kernel.org ; robh...@kernel.org ; r...@kernel.org ; mchehab+hua...@kernel.org ; da...@davemloft.net ; gre...@linuxfoundation.org ; linux-...@vger.kernel.org ; devicet...@vger.kernel.org ; linux-kernel@vger.kernel.org Subject: Re: [PATCH 01/12] iio: imu: inv_icm42600: add core of new inv_icm42600 driver 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 Thu, 7 May 2020 16:42:11 +0200 Jean-Baptiste Maneyrol wrote: > Core component of a new driver for InvenSense ICM-426xx devices. > It includes registers definition, main probe/setup, and device > utility functions. > > ICM-426xx devices are latest generation of 6-axis IMU, > gyroscope+accelerometer and temperature sensor. This device > includes a 2K FIFO, supports I2C/I3C/SPI, and provides > intelligent motion features like pedometer, tilt detection, > and tap detection. > > Signed-off-by: Jean-Baptiste Maneyrol Hi Jean-Baptiste, A few minor things inline. Thanks, Jonathan > --- > drivers/iio/imu/inv_icm42600/inv_icm42600.h | 372 +++ > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 618 ++ > 2 files changed, 990 insertions(+) > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h > create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c > > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h > b/drivers/iio/imu/inv_icm42600/inv_icm42600.h > new file mode 100644 > index ..8da4c8249aed > --- /dev/null > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h > @@ -0,0 +1,372 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * Copyright (C) 2020 Invensense, Inc. > + */ > + > +#ifndef INV_ICM42600_H_ > +#define INV_ICM42600_H_ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +enum inv_icm42600_chip { > + INV_CHIP_ICM42600, > + INV_CHIP_ICM42602, > + INV_CHIP_ICM42605, > + INV_CHIP_ICM42622, > + INV_CHIP_NB, > +}; > + > +/* serial bus slew rates */ > +enum inv_icm42600_slew_rate { > + INV_ICM42600_SLEW_RATE_20_60NS, > + INV_ICM42600_SLEW_RATE_12_36NS, > + INV_ICM42600_SLEW_RATE_6_18NS, > + INV_ICM42600_SLEW_RATE_4_12NS, > + INV_ICM42600_SLEW_RATE_2_6NS, > + INV_ICM42600_SLEW_RATE_INF_2NS, > +}; > + > +enum inv_icm42600_sensor_mode { > + INV_ICM42600_SENSOR_MODE_OFF, > + INV_ICM42600_SENSOR_MODE_STANDBY, > + INV_ICM42600_SENSOR_MODE_LOW_POWER, > + INV_ICM42600_SENSOR_MODE_LOW_NOISE, > + INV_ICM42600_SENSOR_MODE_NB, > +}; > + > +/* gyroscope fullscale values */ > +enum inv_icm42600_gyro_fs { > + INV_ICM42600_GYRO_FS_2000DPS, > + INV_ICM42600_GYRO_FS_1000DPS, > + INV_ICM42600_GYRO_FS_500DPS, > + INV_ICM42600_GYRO_FS_250DPS, > + INV_ICM42600_GYRO_FS_125DPS, > + INV_ICM42600_GYRO_FS_62_5DPS, > + INV_ICM42600_GYRO_FS_31_25DPS, > + INV_ICM42600_GYRO_FS_15_625DPS, > + INV_ICM42600_GYRO_FS_NB, > +}; > + > +/* accelerometer fullscale values */ > +enum inv_icm42600_accel_fs { > + INV_ICM42600_ACCEL_FS_16G, > + INV_ICM42600_ACCEL_FS_8G, > + INV_ICM42600_ACCEL_FS_4G, > + INV_ICM42600_ACCEL_FS_2G, > + INV_ICM42600_ACCEL_FS_NB, > +}; > + > +/* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */ > +enum inv_icm42600_odr { > + INV_ICM42600_ODR_8KHZ_LN = 3, > + INV_ICM42600_ODR_4KHZ_LN, > + INV_ICM42600_ODR_2KHZ_LN, > + INV_ICM42600_ODR_1KHZ_LN, > + INV_ICM42600_ODR_200HZ, > + INV_ICM42600_ODR_100HZ, > + INV_ICM42600_ODR_50HZ, > + INV_ICM42600_ODR_25HZ, > + INV_ICM42600_ODR_12
[PATCH 03/12] iio: imu: inv_icm42600: add SPI driver for inv_icm42600 driver
Add SPI driver for InvenSense ICM-426xxx devices. Configure bus signal slew rates as indicated in the datasheet. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 117 ++ 1 file changed, 117 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c new file mode 100644 index ..835ced68a3a3 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 InvenSense, Inc. + */ + +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +static int inv_icm42600_spi_bus_setup(struct inv_icm42600_state *st) +{ + unsigned int mask, val; + int ret; + + /* setup interface registers */ + mask = INV_ICM42600_INTF_CONFIG6_MASK; + val = INV_ICM42600_INTF_CONFIG6_I3C_EN | + INV_ICM42600_INTF_CONFIG6_I3C_SDR_EN | + INV_ICM42600_INTF_CONFIG6_I3C_DDR_EN; + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6, +mask, val); + if (ret) + return ret; + + mask = INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY; + val = 0; + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, +mask, val); + if (ret) + return ret; + + /* set slew rates for I2C and SPI */ + mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK | + INV_ICM42600_DRIVE_CONFIG_SPI_MASK; + val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_20_60NS) | + INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_INF_2NS); + ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG, +mask, val); + if (ret) + return ret; + + /* disable i2c bus */ + mask = INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK; + val = INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS; + return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, + mask, val); +} + +static int inv_icm42600_probe(struct spi_device *spi) +{ + const void *match; + const struct spi_device_id *spi_id; + enum inv_icm42600_chip chip; + struct regmap *regmap; + + match = device_get_match_data(>dev); + spi_id = spi_get_device_id(spi); + if (match) + chip = (enum inv_icm42600_chip)match; + else if (spi_id) + chip = (enum inv_icm42600_chip)spi_id->driver_data; + else + return -EINVAL; + + regmap = devm_regmap_init_spi(spi, _icm42600_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return inv_icm42600_core_probe(regmap, chip, + inv_icm42600_spi_bus_setup); +} + +static const struct of_device_id inv_icm42600_of_matches[] = { + { + .compatible = "invensense,icm42600", + .data = (void *)INV_CHIP_ICM42600, + }, { + .compatible = "invensense,icm42602", + .data = (void *)INV_CHIP_ICM42602, + }, { + .compatible = "invensense,icm42605", + .data = (void *)INV_CHIP_ICM42605, + }, { + .compatible = "invensense,icm42622", + .data = (void *)INV_CHIP_ICM42622, + }, + {} +}; +MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); + +static const struct spi_device_id inv_icm42600_ids[] = { + {"icm42600", INV_CHIP_ICM42600}, + {"icm42602", INV_CHIP_ICM42602}, + {"icm42605", INV_CHIP_ICM42605}, + {"icm42622", INV_CHIP_ICM42622}, + {} +}; +MODULE_DEVICE_TABLE(spi, inv_icm42600_ids); + +static struct spi_driver inv_icm42600_driver = { + .probe = inv_icm42600_probe, + .id_table = inv_icm42600_ids, + .driver = { + .of_match_table = inv_icm42600_of_matches, + .name = "inv-icm42600-spi", + .pm = _icm42600_pm_ops, + }, +}; +module_spi_driver(inv_icm42600_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-426xx SPI driver"); +MODULE_LICENSE("GPL"); -- 2.17.1
[PATCH 05/12] iio: imu: inv_icm42600: add accelerometer IIO device
Add IIO device for accelerometer sensor with data polling interface. Attributes: raw, scale, sampling_frequency, calibbias. Accelerometer in low noise mode. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 4 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 537 ++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 5 + 3 files changed, 546 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index ca41a9d6404a..bc963b3d1800 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -121,6 +121,7 @@ struct inv_icm42600_suspended { * @conf: chip sensors configurations. * @suspended:suspended sensors configuration. * @indio_gyro: gyroscope IIO device. + * @indio_accel: accelerometer IIO device. */ struct inv_icm42600_state { struct mutex lock; @@ -133,6 +134,7 @@ struct inv_icm42600_state { struct inv_icm42600_conf conf; struct inv_icm42600_suspended suspended; struct iio_dev *indio_gyro; + struct iio_dev *indio_accel; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ @@ -373,4 +375,6 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int inv_icm42600_gyro_init(struct inv_icm42600_state *st); +int inv_icm42600_accel_init(struct inv_icm42600_state *st); + #endif diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c new file mode 100644 index ..397e3d0fd42b --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -0,0 +1,537 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +#define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ + { \ + .type = IIO_ACCEL, \ + .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), \ + .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, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ + .ext_info = _ext_info, \ + } + +enum inv_icm42600_accel_scan { + INV_ICM42600_ACCEL_SCAN_X, + INV_ICM42600_ACCEL_SCAN_Y, + INV_ICM42600_ACCEL_SCAN_Z, +}; + +static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42600_get_mount_matrix), + {}, +}; + +static const struct iio_chan_spec inv_icm42600_accel_channels[] = { + INV_ICM42600_ACCEL_CHAN(IIO_MOD_X, INV_ICM42600_ACCEL_SCAN_X, + inv_icm42600_accel_ext_infos), + INV_ICM42600_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42600_ACCEL_SCAN_Y, + inv_icm42600_accel_ext_infos), + INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, + inv_icm42600_accel_ext_infos), +}; + +static int inv_icm42600_accel_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_sen
[PATCH 09/12] iio: imu: inv_icm42600: add buffer support in iio devices
Use triggered buffer by parsing FIFO data read in device trigger. Support hwfifo watermark by multiplexing gyro and accel settings. Support hwfifo flush. Simply use interrupt timestamp first. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/Kconfig | 3 +- drivers/iio/imu/inv_icm42600/Makefile | 1 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 183 + .../imu/inv_icm42600/inv_icm42600_buffer.c| 353 ++ .../imu/inv_icm42600/inv_icm42600_buffer.h| 162 .../iio/imu/inv_icm42600/inv_icm42600_core.c | 23 ++ .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 183 + .../imu/inv_icm42600/inv_icm42600_trigger.c | 15 +- 9 files changed, 928 insertions(+), 3 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig index 7b3eaeb2aa4a..8c0969319c49 100644 --- a/drivers/iio/imu/inv_icm42600/Kconfig +++ b/drivers/iio/imu/inv_icm42600/Kconfig @@ -2,7 +2,8 @@ config INV_ICM42600 tristate - select IIO_TRIGGER + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER config INV_ICM42600_I2C tristate "InvenSense ICM-426xx I2C driver" diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile index e1f2aacbe888..d6732118010c 100644 --- a/drivers/iio/imu/inv_icm42600/Makefile +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -6,6 +6,7 @@ inv-icm42600-y += inv_icm42600_gyro.o inv-icm42600-y += inv_icm42600_accel.o inv-icm42600-y += inv_icm42600_temp.o inv-icm42600-y += inv_icm42600_trigger.o +inv-icm42600-y += inv_icm42600_buffer.o obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o inv-icm42600-i2c-y += inv_icm42600_i2c.o diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 175c1f67faee..947ca4dd245b 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -15,6 +15,8 @@ #include #include +#include "inv_icm42600_buffer.h" + enum inv_icm42600_chip { INV_CHIP_ICM42600, INV_CHIP_ICM42602, @@ -124,6 +126,7 @@ struct inv_icm42600_suspended { * @indio_gyro: gyroscope IIO device. * @indio_accel: accelerometer IIO device. * @trigger: device internal interrupt trigger + * @fifo: FIFO management structure. */ struct inv_icm42600_state { struct mutex lock; @@ -138,6 +141,7 @@ struct inv_icm42600_state { struct iio_dev *indio_gyro; struct iio_dev *indio_accel; struct iio_trigger *trigger; + struct inv_icm42600_fifo fifo; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ @@ -378,8 +382,12 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, int inv_icm42600_gyro_init(struct inv_icm42600_state *st); +int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev, int64_t ts); + int inv_icm42600_accel_init(struct inv_icm42600_state *st); +int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev, int64_t ts); + int inv_icm42600_trigger_init(struct inv_icm42600_state *st, int irq, int irq_type); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 74dac5f283d4..4206be54d057 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -10,9 +10,13 @@ #include #include #include +#include +#include +#include #include "inv_icm42600.h" #include "inv_icm42600_temp.h" +#include "inv_icm42600_buffer.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -46,6 +50,7 @@ enum inv_icm42600_accel_scan { INV_ICM42600_ACCEL_SCAN_Y, INV_ICM42600_ACCEL_SCAN_Z, INV_ICM42600_ACCEL_SCAN_TEMP, + INV_ICM42600_ACCEL_SCAN_TIMESTAMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { @@ -61,8 +66,100 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, inv_icm42600_accel_ext_infos), INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), + IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42600_ACCEL_SCAN_TIMESTAMP), }; +/* IIO buffer data */ +struct inv_icm42600_accel_buffer { + struct inv_icm42600_fifo_sensor_data accel; + int8_t temp; + int64_t timestamp; +}; + +#define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS
[PATCH 08/12] iio: imu: inv_icm42600: add device interrupt trigger
Add INT1 interrupt support and use it as an iio trigger. Support interrupt edge and level, active high or low. Push-pull configuration only. Trigger enables FIFO and will be useful with buffer support. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/Kconfig | 1 + drivers/iio/imu/inv_icm42600/Makefile | 1 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 +- .../iio/imu/inv_icm42600/inv_icm42600_core.c | 19 +- .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 2 +- .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 2 +- .../imu/inv_icm42600/inv_icm42600_trigger.c | 177 ++ 7 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_trigger.c diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig index 22390a72f0a3..7b3eaeb2aa4a 100644 --- a/drivers/iio/imu/inv_icm42600/Kconfig +++ b/drivers/iio/imu/inv_icm42600/Kconfig @@ -2,6 +2,7 @@ config INV_ICM42600 tristate + select IIO_TRIGGER config INV_ICM42600_I2C tristate "InvenSense ICM-426xx I2C driver" diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile index 48965824f00c..e1f2aacbe888 100644 --- a/drivers/iio/imu/inv_icm42600/Makefile +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -5,6 +5,7 @@ inv-icm42600-y += inv_icm42600_core.o inv-icm42600-y += inv_icm42600_gyro.o inv-icm42600-y += inv_icm42600_accel.o inv-icm42600-y += inv_icm42600_temp.o +inv-icm42600-y += inv_icm42600_trigger.o obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o inv-icm42600-i2c-y += inv_icm42600_i2c.o diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index bc963b3d1800..175c1f67faee 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -13,6 +13,7 @@ #include #include #include +#include enum inv_icm42600_chip { INV_CHIP_ICM42600, @@ -122,6 +123,7 @@ struct inv_icm42600_suspended { * @suspended:suspended sensors configuration. * @indio_gyro: gyroscope IIO device. * @indio_accel: accelerometer IIO device. + * @trigger: device internal interrupt trigger */ struct inv_icm42600_state { struct mutex lock; @@ -135,6 +137,7 @@ struct inv_icm42600_state { struct inv_icm42600_suspended suspended; struct iio_dev *indio_gyro; struct iio_dev *indio_accel; + struct iio_trigger *trigger; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ @@ -370,11 +373,14 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable, int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval); -int inv_icm42600_core_probe(struct regmap *regmap, int chip, +int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, inv_icm42600_bus_setup bus_setup); int inv_icm42600_gyro_init(struct inv_icm42600_state *st); int inv_icm42600_accel_init(struct inv_icm42600_state *st); +int inv_icm42600_trigger_init(struct inv_icm42600_state *st, int irq, + int irq_type); + #endif diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c index 4e33f263d3ea..1102c54396e3 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -447,11 +447,13 @@ static void inv_icm42600_disable_pm(void *_data) pm_runtime_disable(dev); } -int inv_icm42600_core_probe(struct regmap *regmap, int chip, +int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, inv_icm42600_bus_setup bus_setup) { struct device *dev = regmap_get_device(regmap); struct inv_icm42600_state *st; + struct irq_data *irq_desc; + int irq_type; int ret; BUILD_BUG_ON(ARRAY_SIZE(inv_icm42600_hw) != INV_CHIP_NB); @@ -460,6 +462,16 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, return -ENODEV; } + /* get irq data, set trigger falling by default */ + irq_desc = irq_get_irq_data(irq); + if (!irq_desc) { + dev_err(dev, "could not find IRQ %d\n", irq); + return -EINVAL; + } + irq_type = irqd_get_trigger_type(irq_desc); + if (!irq_type) + irq_type = IRQF_TRIGGER_FALLING; + st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); if (!st) return -ENOMEM; @@ -503,6 +515,11 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, if (ret) return ret; + /* setup interrupt trigger */ + ret = inv_icm42600_trigger_in
[PATCH 02/12] iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver
Add I2C driver for InvenSense ICM-426xxx devices. Configure bus signal slew rates as indicated in the datasheet. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 117 ++ 1 file changed, 117 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c new file mode 100644 index ..b61f993beacf --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 InvenSense, Inc. + */ + +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" + +static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st) +{ + unsigned int mask, val; + int ret; + + /* setup interface registers */ + mask = INV_ICM42600_INTF_CONFIG6_MASK; + val = INV_ICM42600_INTF_CONFIG6_I3C_EN; + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6, +mask, val); + if (ret) + return ret; + + mask = INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY; + val = 0; + ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4, +mask, val); + if (ret) + return ret; + + /* set slew rates for I2C and SPI */ + mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK | + INV_ICM42600_DRIVE_CONFIG_SPI_MASK; + val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_12_36NS) | + INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_12_36NS); + ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG, +mask, val); + if (ret) + return ret; + + /* disable SPI bus */ + mask = INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK; + val = INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS; + return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, + mask, val); +} + +static int inv_icm42600_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const void *match; + enum inv_icm42600_chip chip; + struct regmap *regmap; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENOTSUPP; + + match = device_get_match_data(>dev); + if (match) + chip = (enum inv_icm42600_chip)match; + else if (id) + chip = (enum inv_icm42600_chip)id->driver_data; + else + return -EINVAL; + + regmap = devm_regmap_init_i2c(client, _icm42600_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return inv_icm42600_core_probe(regmap, chip, + inv_icm42600_i2c_bus_setup); +} + +static const struct of_device_id inv_icm42600_of_matches[] = { + { + .compatible = "invensense,icm42600", + .data = (void *)INV_CHIP_ICM42600, + }, { + .compatible = "invensense,icm42602", + .data = (void *)INV_CHIP_ICM42602, + }, { + .compatible = "invensense,icm42605", + .data = (void *)INV_CHIP_ICM42605, + }, { + .compatible = "invensense,icm42622", + .data = (void *)INV_CHIP_ICM42622, + }, + {} +}; +MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches); + +static const struct i2c_device_id inv_icm42600_ids[] = { + {"icm42600", INV_CHIP_ICM42600}, + {"icm42602", INV_CHIP_ICM42602}, + {"icm42605", INV_CHIP_ICM42605}, + {"icm42622", INV_CHIP_ICM42622}, + {} +}; +MODULE_DEVICE_TABLE(i2c, inv_icm42600_ids); + +static struct i2c_driver inv_icm42600_driver = { + .probe = inv_icm42600_probe, + .id_table = inv_icm42600_ids, + .driver = { + .of_match_table = inv_icm42600_of_matches, + .name = "inv-icm42600-i2c", + .pm = _icm42600_pm_ops, + }, +}; +module_i2c_driver(inv_icm42600_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense ICM-426xx I2C driver"); +MODULE_LICENSE("GPL"); -- 2.17.1
[PATCH 00/12] iio: imu: new inv_icm42600 driver
This series add a new driver for managing InvenSense ICM-426xx 6-axis IMUs. This next generation of chips includes new generations of 3-axis gyroscope and 3-axis accelerometer, support of I3C in addition to I2C and SPI, and intelligent MotionTracking features like pedometer, tilt detection, and tap detection. This series is delivering a driver supporting gyroscope, accelerometer and temperature data, with polling and buffering using hwfifo and watermark, on I2C and SPI busses. Gyroscope and accelerometer sensors are completely independent and can have different ODRs. Since there is only a single FIFO a specific value is used to mark invalid data. For keeping the device standard we are de-multiplexing data from the FIFO to 2 IIO devices with 2 buffers, 1 for the accelerometer and 1 for the gyroscope. This architecture also enables to easily turn each sensor on/off without impacting the other. The IIO devices are using triggered buffer as sub-interrupts of the device iio trigger using the interrupt pin. A complex timestamping mechanism is added to handle correctly FIFO watermark and dynamic changes. Jean-Baptiste Maneyrol (12): iio: imu: inv_icm42600: add core of new inv_icm42600 driver iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver iio: imu: inv_icm42600: add SPI driver for inv_icm42600 driver iio: imu: inv_icm42600: add gyroscope IIO device iio: imu: inv_icm42600: add accelerometer IIO device iio: imu: inv_icm42600: add temperature sensor support iio: imu: add Kconfig and Makefile for inv_icm42600 driver iio: imu: inv_icm42600: add device interrupt trigger iio: imu: inv_icm42600: add buffer support in iio devices iio: imu: inv_icm42600: add accurate timestamping dt-bindings: iio: imu: Add inv_icm42600 documentation MAINTAINERS: add entry for inv_icm42600 6-axis imu sensor .../bindings/iio/imu/invensense,icm42600.yaml | 90 +++ MAINTAINERS | 8 + drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42600/Kconfig | 30 + drivers/iio/imu/inv_icm42600/Makefile | 16 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 400 + .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 752 + .../imu/inv_icm42600/inv_icm42600_buffer.c| 373 + .../imu/inv_icm42600/inv_icm42600_buffer.h| 162 .../iio/imu/inv_icm42600/inv_icm42600_core.c | 674 +++ .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 764 ++ .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 117 +++ .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 117 +++ .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 86 ++ .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 32 + .../imu/inv_icm42600/inv_icm42600_timestamp.c | 246 ++ .../imu/inv_icm42600/inv_icm42600_timestamp.h | 82 ++ .../imu/inv_icm42600/inv_icm42600_trigger.c | 188 + 19 files changed, 4139 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml create mode 100644 drivers/iio/imu/inv_icm42600/Kconfig create mode 100644 drivers/iio/imu/inv_icm42600/Makefile create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_trigger.c -- 2.17.1
[PATCH 06/12] iio: imu: inv_icm42600: add temperature sensor support
Add temperature channel in gyroscope and accelerometer devices. Temperature is available in full 16 bits resolution as a processed channel. Scale and offset attributes are also provided for the low 8 bits resolution raw temperature found in the FIFO. Signed-off-by: Jean-Baptiste Maneyrol --- .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 12 ++- .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 12 ++- .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 86 +++ .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 32 +++ 4 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 397e3d0fd42b..74dac5f283d4 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -12,6 +12,7 @@ #include #include "inv_icm42600.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -44,6 +45,7 @@ enum inv_icm42600_accel_scan { INV_ICM42600_ACCEL_SCAN_X, INV_ICM42600_ACCEL_SCAN_Y, INV_ICM42600_ACCEL_SCAN_Z, + INV_ICM42600_ACCEL_SCAN_TEMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { @@ -58,6 +60,7 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { inv_icm42600_accel_ext_infos), INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, inv_icm42600_accel_ext_infos), + INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), }; static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st, @@ -394,8 +397,15 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev, int16_t data; int ret; - if (chan->type != IIO_ACCEL) + switch (chan->type) { + case IIO_ACCEL: + break; + case IIO_TEMP: + return inv_icm42600_temp_read_raw(indio_dev, chan, val, val2, + mask); + default: return -EINVAL; + } switch (mask) { case IIO_CHAN_INFO_RAW: diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c index 74aa2b5fa611..c0164ab2830e 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -12,6 +12,7 @@ #include #include "inv_icm42600.h" +#include "inv_icm42600_temp.h" #define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \ { \ @@ -44,6 +45,7 @@ enum inv_icm42600_gyro_scan { INV_ICM42600_GYRO_SCAN_X, INV_ICM42600_GYRO_SCAN_Y, INV_ICM42600_GYRO_SCAN_Z, + INV_ICM42600_GYRO_SCAN_TEMP, }; static const struct iio_chan_spec_ext_info inv_icm42600_gyro_ext_infos[] = { @@ -58,6 +60,7 @@ static const struct iio_chan_spec inv_icm42600_gyro_channels[] = { inv_icm42600_gyro_ext_infos), INV_ICM42600_GYRO_CHAN(IIO_MOD_Z, INV_ICM42600_GYRO_SCAN_Z, inv_icm42600_gyro_ext_infos), + INV_ICM42600_TEMP_CHAN(INV_ICM42600_GYRO_SCAN_TEMP), }; static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st, @@ -406,8 +409,15 @@ static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev, int16_t data; int ret; - if (chan->type != IIO_ANGL_VEL) + switch (chan->type) { + case IIO_ANGL_VEL: + break; + case IIO_TEMP: + return inv_icm42600_temp_read_raw(indio_dev, chan, val, val2, + mask); + default: return -EINVAL; + } switch (mask) { case IIO_CHAN_INFO_RAW: diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c new file mode 100644 index ..e5407b17c407 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "inv_icm42600.h" +#include "inv_icm42600_temp.h" + +static int inv_icm42600_temp_read(struct inv_icm42600_state *st, int32_t *temp) +{ + struct device *dev = regmap_get_device(st->map); + __be16 raw; + int16_t val; + int64_t data; + int ret; + + pm_runtime_get_sync(dev); + m
[PATCH 11/12] dt-bindings: iio: imu: Add inv_icm42600 documentation
Document the ICM-426xxx devices devicetree bindings. Signed-off-by: Jean-Baptiste Maneyrol --- .../bindings/iio/imu/invensense,icm42600.yaml | 90 +++ 1 file changed, 90 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml new file mode 100644 index ..a7175f6543fa --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/imu/invensense,icm42600.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: InvenSense ICM-426xx Inertial Measurement Unit + +maintainers: + - Jean-Baptiste Maneyrol + +description: | + 6-axis MotionTracking device that combines a 3-axis gyroscope and a 3-axis accelerometer. + + It has a configurable host interface that supports I3C, I2C and SPI serial communication, features a 2kB FIFO and + 2 programmable interrupts with ultra-low-power wake-on-motion support to minimize system power consumption. + + Other industry-leading features include InvenSense on-chip APEX Motion Processing engine for gesture recognition, + activity classification, and pedometer, along with programmable digital filters, and an embedded temperature sensor. + + https://invensense.tdk.com/wp-content/uploads/2020/03/DS-000292-ICM-42605-v1.4.pdf + +properties: + compatible: +enum: + - invensense,icm42600 + - invensense,icm42602 + - invensense,icm42605 + - invensense,icm42622 + + reg: +maxItems: 1 + + interrupts: +maxItems: 1 + + spi-cpha: true + + spi-cpol: true + + spi-max-frequency: +maxItems: 1 + + vdd-supply: +description: Regulator that provides power to the sensor + + vddio-supply: +description: Regulator that provides power to the bus + +required: + - compatible + - reg + - interrupts + +examples: + - | +#include +#include +i2c0 { +#address-cells = <1>; +#size-cells = <0>; + +icm42605@68 { + compatible = "invensense,icm42605"; + reg = <0x68>; + interrupt-parent = <>; + interrupts = <7 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <>; + vddio-supply = <>; +}; +}; + - | +#include +#include +spi0 { +#address-cells = <1>; +#size-cells = <0>; + +icm42602@0 { + compatible = "invensense,icm42602"; + reg = <0>; + spi-max-frequency = <2400>; + spi-cpha; + spi-cpol; + interrupt-parent = <>; + interrupts = <2 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <>; + vddio-supply = <>; +}; +}; -- 2.17.1
[PATCH 10/12] iio: imu: inv_icm42600: add accurate timestamping
Add a timestamp channel with processed value that returns full precision 20 bits timestamp. Add a timestamping mechanism for buffer that provides accurate event timestamps when using watermark. This mechanism estimates device internal clock by comparing FIFO interrupts delta time and corresponding device elapsed time computed by parsing FIFO data. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/Makefile | 1 + drivers/iio/imu/inv_icm42600/inv_icm42600.h | 10 +- .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 32 ++- .../imu/inv_icm42600/inv_icm42600_buffer.c| 28 +- .../iio/imu/inv_icm42600/inv_icm42600_core.c | 6 + .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 32 ++- .../imu/inv_icm42600/inv_icm42600_timestamp.c | 246 ++ .../imu/inv_icm42600/inv_icm42600_timestamp.h | 82 ++ 8 files changed, 421 insertions(+), 16 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.h diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile index d6732118010c..1197b545a682 100644 --- a/drivers/iio/imu/inv_icm42600/Makefile +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -7,6 +7,7 @@ inv-icm42600-y += inv_icm42600_accel.o inv-icm42600-y += inv_icm42600_temp.o inv-icm42600-y += inv_icm42600_trigger.o inv-icm42600-y += inv_icm42600_buffer.o +inv-icm42600-y += inv_icm42600_timestamp.o obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o inv-icm42600-i2c-y += inv_icm42600_i2c.o diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h index 947ca4dd245b..e15eddafe009 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -16,6 +16,7 @@ #include #include "inv_icm42600_buffer.h" +#include "inv_icm42600_timestamp.h" enum inv_icm42600_chip { INV_CHIP_ICM42600, @@ -127,6 +128,7 @@ struct inv_icm42600_suspended { * @indio_accel: accelerometer IIO device. * @trigger: device internal interrupt trigger * @fifo: FIFO management structure. + * @timestamp:timestamp management structure. */ struct inv_icm42600_state { struct mutex lock; @@ -142,6 +144,10 @@ struct inv_icm42600_state { struct iio_dev *indio_accel; struct iio_trigger *trigger; struct inv_icm42600_fifo fifo; + struct { + struct inv_icm42600_timestamp gyro; + struct inv_icm42600_timestamp accel; + } timestamp; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ @@ -382,11 +388,11 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, int inv_icm42600_gyro_init(struct inv_icm42600_state *st); -int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev, int64_t ts); +int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev); int inv_icm42600_accel_init(struct inv_icm42600_state *st); -int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev, int64_t ts); +int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev); int inv_icm42600_trigger_init(struct inv_icm42600_state *st, int irq, int irq_type); diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c index 4206be54d057..ac140c824c03 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c @@ -17,6 +17,7 @@ #include "inv_icm42600.h" #include "inv_icm42600_temp.h" #include "inv_icm42600_buffer.h" +#include "inv_icm42600_timestamp.h" #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ { \ @@ -66,7 +67,7 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = { INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, inv_icm42600_accel_ext_infos), INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), - IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42600_ACCEL_SCAN_TIMESTAMP), + INV_ICM42600_TIMESTAMP_CHAN(INV_ICM42600_ACCEL_SCAN_TIMESTAMP), }; /* IIO buffer data */ @@ -94,14 +95,20 @@ static irqreturn_t inv_icm42600_accel_handler(int irq, void *_data) struct iio_poll_func *pf = _data; struct iio_dev *indio_dev = pf->indio_dev; struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); + struct inv_icm42600_timestamp *ts = >timestamp.accel; const size_t fifo_nb = st->fifo.nb.total; + const size_t accel_nb = st->fifo.nb.accel; + const uint32_t fifo_period = st->fifo.period; int ret; /* exit if no sample */ if (fifo_nb == 0)
[PATCH 01/12] iio: imu: inv_icm42600: add core of new inv_icm42600 driver
Core component of a new driver for InvenSense ICM-426xx devices. It includes registers definition, main probe/setup, and device utility functions. ICM-426xx devices are latest generation of 6-axis IMU, gyroscope+accelerometer and temperature sensor. This device includes a 2K FIFO, supports I2C/I3C/SPI, and provides intelligent motion features like pedometer, tilt detection, and tap detection. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 372 +++ .../iio/imu/inv_icm42600/inv_icm42600_core.c | 618 ++ 2 files changed, 990 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h new file mode 100644 index ..8da4c8249aed --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#ifndef INV_ICM42600_H_ +#define INV_ICM42600_H_ + +#include +#include +#include +#include +#include +#include +#include + +enum inv_icm42600_chip { + INV_CHIP_ICM42600, + INV_CHIP_ICM42602, + INV_CHIP_ICM42605, + INV_CHIP_ICM42622, + INV_CHIP_NB, +}; + +/* serial bus slew rates */ +enum inv_icm42600_slew_rate { + INV_ICM42600_SLEW_RATE_20_60NS, + INV_ICM42600_SLEW_RATE_12_36NS, + INV_ICM42600_SLEW_RATE_6_18NS, + INV_ICM42600_SLEW_RATE_4_12NS, + INV_ICM42600_SLEW_RATE_2_6NS, + INV_ICM42600_SLEW_RATE_INF_2NS, +}; + +enum inv_icm42600_sensor_mode { + INV_ICM42600_SENSOR_MODE_OFF, + INV_ICM42600_SENSOR_MODE_STANDBY, + INV_ICM42600_SENSOR_MODE_LOW_POWER, + INV_ICM42600_SENSOR_MODE_LOW_NOISE, + INV_ICM42600_SENSOR_MODE_NB, +}; + +/* gyroscope fullscale values */ +enum inv_icm42600_gyro_fs { + INV_ICM42600_GYRO_FS_2000DPS, + INV_ICM42600_GYRO_FS_1000DPS, + INV_ICM42600_GYRO_FS_500DPS, + INV_ICM42600_GYRO_FS_250DPS, + INV_ICM42600_GYRO_FS_125DPS, + INV_ICM42600_GYRO_FS_62_5DPS, + INV_ICM42600_GYRO_FS_31_25DPS, + INV_ICM42600_GYRO_FS_15_625DPS, + INV_ICM42600_GYRO_FS_NB, +}; + +/* accelerometer fullscale values */ +enum inv_icm42600_accel_fs { + INV_ICM42600_ACCEL_FS_16G, + INV_ICM42600_ACCEL_FS_8G, + INV_ICM42600_ACCEL_FS_4G, + INV_ICM42600_ACCEL_FS_2G, + INV_ICM42600_ACCEL_FS_NB, +}; + +/* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */ +enum inv_icm42600_odr { + INV_ICM42600_ODR_8KHZ_LN = 3, + INV_ICM42600_ODR_4KHZ_LN, + INV_ICM42600_ODR_2KHZ_LN, + INV_ICM42600_ODR_1KHZ_LN, + INV_ICM42600_ODR_200HZ, + INV_ICM42600_ODR_100HZ, + INV_ICM42600_ODR_50HZ, + INV_ICM42600_ODR_25HZ, + INV_ICM42600_ODR_12_5HZ, + INV_ICM42600_ODR_6_25HZ_LP, + INV_ICM42600_ODR_3_125HZ_LP, + INV_ICM42600_ODR_1_5625HZ_LP, + INV_ICM42600_ODR_500HZ, + INV_ICM42600_ODR_NB, +}; + +enum inv_icm42600_filter { + /* Low-Noise mode sensor data filter (3rd order filter by default) */ + INV_ICM42600_FILTER_BW_ODR_DIV_2, + + /* Low-Power mode sensor data filter (averaging) */ + INV_ICM42600_FILTER_AVG_1X = 1, + INV_ICM42600_FILTER_AVG_16X = 6, +}; + +struct inv_icm42600_sensor_conf { + int mode; + int fs; + int odr; + int filter; +}; +#define INV_ICM42600_SENSOR_CONF_INIT {-1, -1, -1, -1} + +struct inv_icm42600_conf { + struct inv_icm42600_sensor_conf gyro; + struct inv_icm42600_sensor_conf accel; + bool temp_en; +}; + +struct inv_icm42600_suspended { + enum inv_icm42600_sensor_mode gyro; + enum inv_icm42600_sensor_mode accel; + bool temp; +}; + +/* + * struct inv_icm42600_state - driver state variables + * @lock: chip access lock. + * @chip: chip identifier. + * @name: chip name. + * @map: regmap pointer. + * @vdd_supply: VDD voltage regulator for the chip. + * @vddio_supply: I/O voltage regulator for the chip. + * @orientation: sensor chip orientation relative to main hardware. + * @conf: chip sensors configurations. + * @suspended:suspended sensors configuration. + */ +struct inv_icm42600_state { + struct mutex lock; + enum inv_icm42600_chip chip; + const char *name; + struct regmap *map; + struct regulator *vdd_supply; + struct regulator *vddio_supply; + struct iio_mount_matrix orientation; + struct inv_icm42600_conf conf; + struct inv_icm42600_suspended suspended; +}; + +/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ + +/* Bank selection register, available in all banks */ +#define INV_ICM42600_REG_BANK_SEL
[PATCH 12/12] MAINTAINERS: add entry for inv_icm42600 6-axis imu sensor
Add MAINTAINERS entry for InvenSense ICM-426xx IMU device. Signed-off-by: Jean-Baptiste Maneyrol --- MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 10eb348c801c..1714390e2721 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8864,6 +8864,14 @@ F: include/dt-bindings/interconnect/ F: include/linux/interconnect-provider.h F: include/linux/interconnect.h +INVENSENSE ICM-426xx IMU DRIVER +M: Jean-Baptiste Maneyrol +L: linux-...@vger.kernel.org +S: Maintained +W https://invensense.tdk.com/ +F: Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +F: drivers/iio/imu/inv_icm42600/ + INVENSENSE MPU-3050 GYROSCOPE DRIVER M: Linus Walleij L: linux-...@vger.kernel.org -- 2.17.1
[PATCH 07/12] iio: imu: add Kconfig and Makefile for inv_icm42600 driver
Add 3 modules: inv-icm42600, inv-icm42600-i2c, inv-icm42600-spi. Signed-off-by: Jean-Baptiste Maneyrol --- drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42600/Kconfig | 28 +++ drivers/iio/imu/inv_icm42600/Makefile | 13 + 4 files changed, 43 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42600/Kconfig create mode 100644 drivers/iio/imu/inv_icm42600/Makefile diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index fc4123d518bc..f02883b08480 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -91,6 +91,7 @@ config KMX61 To compile this driver as module, choose M here: the module will be called kmx61. +source "drivers/iio/imu/inv_icm42600/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig" source "drivers/iio/imu/st_lsm6dsx/Kconfig" diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 88b2c4555230..13e9ff442b11 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_FXOS8700) += fxos8700_core.o obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o +obj-y += inv_icm42600/ obj-y += inv_mpu6050/ obj-$(CONFIG_KMX61) += kmx61.o diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig new file mode 100644 index ..22390a72f0a3 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/Kconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config INV_ICM42600 + tristate + +config INV_ICM42600_I2C + tristate "InvenSense ICM-426xx I2C driver" + depends on I2C + select INV_ICM42600 + select REGMAP_I2C + help + This driver supports the InvenSense ICM-426xx motion tracking + devices over I2C. + + This driver can be built as a module. The module will be called + inv-icm42600-i2c. + +config INV_ICM42600_SPI + tristate "InvenSense ICM-426xx SPI driver" + depends on SPI_MASTER + select INV_ICM42600 + select REGMAP_SPI + help + This driver supports the InvenSense ICM-426xx motion tracking + devices over SPI. + + This driver can be built as a module. The module will be called + inv-icm42600-spi. diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile new file mode 100644 index ..48965824f00c --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-$(CONFIG_INV_ICM42600) += inv-icm42600.o +inv-icm42600-y += inv_icm42600_core.o +inv-icm42600-y += inv_icm42600_gyro.o +inv-icm42600-y += inv_icm42600_accel.o +inv-icm42600-y += inv_icm42600_temp.o + +obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o +inv-icm42600-i2c-y += inv_icm42600_i2c.o + +obj-$(CONFIG_INV_ICM42600_SPI) += inv-icm42600-spi.o +inv-icm42600-spi-y += inv_icm42600_spi.o -- 2.17.1
[PATCH 04/12] iio: imu: inv_icm42600: add gyroscope IIO device
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 --- drivers/iio/imu/inv_icm42600/inv_icm42600.h | 4 + .../iio/imu/inv_icm42600/inv_icm42600_core.c | 5 + .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 549 ++ 3 files changed, 558 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 8da4c8249aed..ca41a9d6404a 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h @@ -120,6 +120,7 @@ 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. */ struct inv_icm42600_state { struct mutex lock; @@ -131,6 +132,7 @@ struct inv_icm42600_state { struct iio_mount_matrix orientation; struct inv_icm42600_conf conf; struct inv_icm42600_suspended suspended; + struct iio_dev *indio_gyro; }; /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ @@ -369,4 +371,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 35bdf4f9d31e..151257652ce6 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c @@ -503,6 +503,11 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, if (ret) return ret; + /* create and init gyroscope iio device */ + 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 ..74aa2b5fa611 --- /dev/null +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c @@ -0,0 +1,549 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 Invensense, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#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), \ + .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, \ + .shift = 0, \ + .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
Re: ICM20602 buffer issues with the inv_mpu6050 driver
Hi Andreea, I understand the issue now. The problem is that temperature data are always present in the FIFO. Even when the attribute is disabled. This is a limitation of this chip and cannot be changed on the hardware side. When temp attribute is disabled while accel and gyro are on, the iio buffer is expecting to have 12 bytes with accel + gyro data. But the driver will still provides 14 bytes with temperature in the middle since the FIFO will contain that. Always enabling temperature attribute on userspace will solve this issue, but that's certainly not the best. A correct solution would be to enforce temperature data in iio buffer by having the temp attribute always enabled and read-only in userspace. That would reflect correctly the chip capabilities. But I don't know if this is feasible. A workaround would be to add data post-processing in the driver and delete temp data when it is disabled. But I don't like this kind of workaround because that goes against iio buffer design principle. Hope this help you. Best regards, Jean-Baptiste Maneyrol From: Andreea Lutac Sent: Thursday, May 23, 2019 11:44 To: Jean-Baptiste Maneyrol Cc: stev...@skydio.com; ji...@kernel.org; knaac...@gmx.de; l...@metafoo.de; pme...@pmeerw.net; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org Subject: Re: ICM20602 buffer issues with the inv_mpu6050 driver 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. Hi Jean-Baptiste and Stepan, Thanks so much for the replies and the advice. I've dug a bit deeper into this and added a few printk statements to the driver, as suggested by Stepan. It looks like the device is getting recognized correctly as ICM20602 and the buffer is being filled with 14 bytes as expected. But I've identified some strange behaviour regarding the temperature channeI. If I manually enable all 7 scan elements and read 14 bytes from the device file, the readings appear correct and change accordingly when I move the chip around. However, if I set in_temp_en set to 0 (with everything else still enabled) and read 12 bytes, the buffer doesn't seem to acknowledge this change and shift the gyro values up, instead getting only the first 12 bytes (accel_x, accel_y, accel_z, temp, gyro_x, gyro_y), without gyro_z. So this is why it looks as if temp is replacing gyro_x. I made a pastebin here with some of the (unconverted) values I got while testing these cases: https://urldefense.proofpoint.com/v2/url?u=https-3A__pastebin.com_BYVqDNch=DwIFaQ=WoJWtq5JV8YrKnzRxvD8NxmTP_1wxfE0prPmo0NeZwg=4jiDX_1brsSWfCjfA6Ovj1d4h9MF8q7Xk5aBwG28mVk=sbkHiUlsj8pOWjf2iTq5CXEFvv-MNyqBKOqCjxOj9kc=Pmb23R-DoTj9hDwYk3qqiUfOCUWbtfpVQjUZ1lajeFI= Attempting the same reads with my C++ program via libiio always results in only the first 12 bytes being read, as for some strange reason libiio fails to enable the temperature channel, so iio_device_get_sample_size() is always 12 and it's actually gyro_z that I can't get to. I'll try to look through the code that is supposed to enable a channel and see why it's not succeeding via libiio. Do you have any clue as to which bit of code does the adjustment of the buffer values according to which channels are enabled? Is this done in the driver or deeper in the kernel? Thanks once again for the help! Best regards, Andreea On Wednesday, May 22, 2019 16:33 CEST, Jean-Baptiste Maneyrol wrote: > Hello, > > I had a look inside the driver to verify the buffer implementation. It looks > correct to me. I don't see where the problem can come from. I am sorry I > don't have a setup currently to test in live. > > For sure you can have a different result by reading the buffer through the > char device file compared to reading the raw sysfs entry. The buffer is > taking the data from the FIFO and the raw sysfs from the sensor data > registers. > > You can perhaps test value 1 by 1 in the buffer, and verify the correctness > of every attributes. If you can also send a complete buffer log that would be > helpful. > Every data is 2 bytes long and in the following order: accel_x, accel_y, > accel_z, temp, gyro_x, gyro_y, gyro_z > > Best regards, > JB Maneyrol > > From: Andreea Lutac > Sent: Tuesday, May 21, 2019 12:40 > Cc: Jean-Baptiste Maneyrol; stev...@skydio.com; ji...@kernel.org; > knaac...@gmx.de; l...@metafoo.de; pme...@pmeerw.net; > linux-...@vger.kernel.org; linux-kernel@vger.kernel.org > Subject: ICM20602 buffer issues with the inv_mpu6050 driver > > Hello, > > I've been trying to get some data samples from the ICM20602 IMU using the > mpu6050 driver which recently added support for it, but I'm encountering an > issue with the ordering of the data in the FIFO. > According to the specs
Re: ICM20602 buffer issues with the inv_mpu6050 driver
Hello, I had a look inside the driver to verify the buffer implementation. It looks correct to me. I don't see where the problem can come from. I am sorry I don't have a setup currently to test in live. For sure you can have a different result by reading the buffer through the char device file compared to reading the raw sysfs entry. The buffer is taking the data from the FIFO and the raw sysfs from the sensor data registers. You can perhaps test value 1 by 1 in the buffer, and verify the correctness of every attributes. If you can also send a complete buffer log that would be helpful. Every data is 2 bytes long and in the following order: accel_x, accel_y, accel_z, temp, gyro_x, gyro_y, gyro_z Best regards, JB Maneyrol From: Andreea Lutac Sent: Tuesday, May 21, 2019 12:40 Cc: Jean-Baptiste Maneyrol; stev...@skydio.com; ji...@kernel.org; knaac...@gmx.de; l...@metafoo.de; pme...@pmeerw.net; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org Subject: ICM20602 buffer issues with the inv_mpu6050 driver Hello, I've been trying to get some data samples from the ICM20602 IMU using the mpu6050 driver which recently added support for it, but I'm encountering an issue with the ordering of the data in the FIFO. According to the specs of the device, if the accel and gyro XYZ channels are enabled, then the hardware FIFO is filled with 14 bytes corresponding to the following channels: accel_x, accel_y, accel_z, temp, anglvel_x, anglvel_y, anglvel_z. However, when reading out the buffer, the value I get for anglvel_x seems to actually be the temperature. This occurs both when reading with iio_channel_read (via libiio) and also if I read directly from /dev/iio:device with only in_anglvel_x_en set. But in_anglvel_x_raw reports correct values, which made me suspect that maybe somewhere in the driver this interleaved temp channel is not accounted for in the buffer structure. I had a look at the driver code and inv_mpu6050_read_fifo() in particular, but I can't identify anything amiss. I've applied the recent patch that added the extra 2 temperature bytes ( ), but the problem persists. So far I've tried changing the size of the data buffer, defined in inv_mpu_iio.h: /* 6 + 6 round up and plus 8 */ #define INV_MPU6050_OUTPUT_DATA_SIZE 24 from 24 to 32, according to the intuition that 24 corresponds to readings without temperature (i.e. 6 bytes for accel, rounded up to 8 + 6 bytes for gyro, rounded up to 8 + 8 bytes for the timestamp = 24) and thus another 8 bytes would be needed, but that doesn't seem to have solved it. I'm quite new to driver development though, so I think there might be something I'm not getting. I would be really grateful if anyone could shed some light over what's happening here or give some advice as to what I could be doing wrong. Best regards, Andreea Lutac
Re: [PATCH v2] iio: imu: mpu6050: Fix FIFO layout for ICM20602
Hello, overall looks good for me. I would just prefer to change the define name for temperature to INV_ICM20602_SCAN_TEMP. It is the chip temperature that can be used for temperature compensation for both accel and gyro data. But it is really just a details. Best regards, Jean-Baptiste Maneyrol From: Jonathan Cameron Sent: Sunday, April 7, 2019 13:45 To: stev...@skydio.com Cc: Jean-Baptiste Maneyrol; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald-Stadler; Martin Kelly; Jonathan Marek; Brian Masney; Randolph Maaßen; Douglas Fischer; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org Subject: Re: [PATCH v2] iio: imu: mpu6050: Fix FIFO layout for ICM20602 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 Tue, 2 Apr 2019 23:28:56 -0700 stev...@skydio.com wrote: > From: Steve Moskovchenko > > The MPU6050 driver has recently gained support for the > ICM20602 IMU, which is very similar to MPU6xxx. However, > the ICM20602's FIFO data specifically includes temperature > readings, which were not present on MPU6xxx parts. As a > result, the driver will under-read the ICM20602's FIFO > register, causing the same (partial) sample to be returned > for all reads, until the FIFO overflows. > > Fix this by adding a table of scan elements specifically > for the ICM20602, which takes the extra temperature data > into consideration. > > While we're at it, fix the temperature offset and scaling > on ICM20602, since it uses different scale/offset constants > than the rest of the MPU6xxx devices. > > Signed-off-by: Steve Moskovchenko I'd like a reviewed-by or acked-by from Jean-Baptiste on this before I take it. thanks, Jonathan > --- > v2: Read temperature when running in accel-only mode, too. > > drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 46 -- > drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 20 +- > drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 3 ++ > 3 files changed, 64 insertions(+), 5 deletions(-) > > diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c > b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c > index 650de0fefb7b..fedd3f2b0135 100644 > --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c > +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c > @@ -471,7 +471,10 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, > return IIO_VAL_INT_PLUS_MICRO; > case IIO_TEMP: > *val = 0; > - *val2 = INV_MPU6050_TEMP_SCALE; > + if (st->chip_type == INV_ICM20602) > + *val2 = INV_ICM20602_TEMP_SCALE; > + else > + *val2 = INV_MPU6050_TEMP_SCALE; > > return IIO_VAL_INT_PLUS_MICRO; > default: > @@ -480,7 +483,10 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, > case IIO_CHAN_INFO_OFFSET: > switch (chan->type) { > case IIO_TEMP: > - *val = INV_MPU6050_TEMP_OFFSET; > + if (st->chip_type == INV_ICM20602) > + *val = INV_ICM20602_TEMP_OFFSET; > + else > + *val = INV_MPU6050_TEMP_OFFSET; > > return IIO_VAL_INT; > default: > @@ -845,6 +851,32 @@ static const struct iio_chan_spec inv_mpu_channels[] = { > INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), > }; > > +static const struct iio_chan_spec inv_icm20602_channels[] = { > + IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP), > + { > + .type = IIO_TEMP, > + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) > + | BIT(IIO_CHAN_INFO_OFFSET) > + | BIT(IIO_CHAN_INFO_SCALE), > + .scan_index = INV_ICM20602_SCAN_GYRO_TEMP, > + .scan_type = { > + .sign = 's', > + .realbits = 16, > + .storagebits = 16, > + .shift = 0, > + .endianness = IIO_BE, > + }, > + }, > + > + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_ICM20602_SCAN_GYRO_X), > + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_ICM20602_SCAN_GYRO_Y), > + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_ICM20602_SCAN_GYRO_Z), > + > + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_ICM20602_SCAN_ACCL_Y), > + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD
Re: [PATCH] iio: imu: mpu6050: Fix FIFO layout for ICM20602
Hello, it is right that temperature is always put inside the FIFO with this chip. But beware that it should also be the case when accelerometer only is enabled. The FIFO should contain accel data + temp. You can easily verify that by looking at the size of a sample inside the FIFO when only accelerometer is enabled (should be 8 instead of 6). If this is confirmed, you need to modify your code to handle this case correctly. Best regards, Jean-Baptiste Maneyrol From: Jonathan Cameron Sent: Saturday, March 30, 2019 19:29 To: stev...@skydio.com Cc: gai...@gaireg.de; Hartmut Knaack; Lars-Peter Clausen; Peter Meerwald-Stadler; Jean-Baptiste Maneyrol; Martin Kelly; Jonathan Marek; Brian Masney; Rob Herring; Douglas Fischer; linux-...@vger.kernel.org; linux-kernel@vger.kernel.org; Randolph Maaßen Subject: Re: [PATCH] iio: imu: mpu6050: Fix FIFO layout for ICM20602 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 Tue, 26 Mar 2019 02:01:45 -0700 stev...@skydio.com wrote: +CC Randolph, who I think introduced the support. > From: Steve Moskovchenko > > The MPU6050 driver has recently gained support for the > ICM20602 IMU, which is very similar to MPU6xxx. However, > the ICM20602's Gyro data specifically includes temperature > readings, which were not present on MPU6xxx parts. As a > result, the driver will under-read the ICM20602's FIFO > register, causing the same (partial) sample to be returned > for all reads, until the FIFO overflows. > > Fix this by adding a table of scan elements speciically for > the ICM20602, which takes the extra temperature data into > consideration. > > While we're at it, fix the temperature offset and scaling > on ICM20602, since it uses different scale/offset constants > than the rest of the MPU6xxx devices. > > Signed-off-by: Steve Moskovchenko Hi Steve This all looks sensible to me. Ideally should have had a fixes tag. If no one shouts in the next few days I'll pick this up and add one. Give me a poke if I seem to have forgotten it in a week or so. Thanks, Jonathan > --- > drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 46 -- > drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 20 +- > drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c | 8 +++- > 3 files changed, 67 insertions(+), 7 deletions(-) > > diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c > b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c > index 650de0fefb7b..fedd3f2b0135 100644 > --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c > +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c > @@ -471,7 +471,10 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, > return IIO_VAL_INT_PLUS_MICRO; > case IIO_TEMP: > *val = 0; > - *val2 = INV_MPU6050_TEMP_SCALE; > + if (st->chip_type == INV_ICM20602) > + *val2 = INV_ICM20602_TEMP_SCALE; > + else > + *val2 = INV_MPU6050_TEMP_SCALE; > > return IIO_VAL_INT_PLUS_MICRO; > default: > @@ -480,7 +483,10 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, > case IIO_CHAN_INFO_OFFSET: > switch (chan->type) { > case IIO_TEMP: > - *val = INV_MPU6050_TEMP_OFFSET; > + if (st->chip_type == INV_ICM20602) > + *val = INV_ICM20602_TEMP_OFFSET; > + else > + *val = INV_MPU6050_TEMP_OFFSET; > > return IIO_VAL_INT; > default: > @@ -845,6 +851,32 @@ static const struct iio_chan_spec inv_mpu_channels[] = { > INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), > }; > > +static const struct iio_chan_spec inv_icm20602_channels[] = { > + IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP), > + { > + .type = IIO_TEMP, > + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) > + | BIT(IIO_CHAN_INFO_OFFSET) > + | BIT(IIO_CHAN_INFO_SCALE), > + .scan_index = INV_ICM20602_SCAN_GYRO_TEMP, > + .scan_type = { > + .sign = 's', > + .realbits = 16, > + .storagebits = 16, > + .shift = 0, > + .endianness = IIO_BE, > + }, > + }, > + > + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_
Re: [PATCH 2/3] iio: imu: mpu6050: add support for regulator framework
Hello, I really don't like the idea to have regulator handled inside the driver. I know this was done like that before for Nexus 5, but I think now this is something that can be done using dts only. Does anyone know if there is a way with dts to handle regulator automatically and prevent the use in the driver? That would be a good idea to search how this handled for other drivers. Anyway, you are enforcing regulator use in your code. It doesn't seem the code will work when there is no regulator declared in the dts, which is the case for the majority of configurations. We should at least make it optional. Thanks for the contribution. JB From: Brian Masney Sent: Wednesday, July 11, 2018 03:09 To: ji...@kernel.org; robh...@kernel.org; mark.rutl...@arm.com; andy.gr...@linaro.org; david.br...@linaro.org; linux-...@vger.kernel.org; devicet...@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-...@vger.kernel.org; linux-...@vger.kernel.org Cc: jonat...@marek.ca; Jean-Baptiste Maneyrol; knaac...@gmx.de; l...@metafoo.de; pme...@pmeerw.net; mke...@xevo.com; fischerdougl...@gmail.com; bs...@kde.org; ctatlo...@gmail.com; masn...@onstation.org Subject: [PATCH 2/3] iio: imu: mpu6050: add support for regulator framework 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. This patch adds support for the regulator framework to the mpu6050 driver. Signed-off-by: Brian Masney Signed-off-by: Jonathan Marek --- This is a variation of Jonathan Marek's patch from postmarketOS https://gitlab.com/postmarketOS/linux-postmarketos/commit/b8ad1ec1859c8bbcbce94944b3f4dd68f8f9fc37 with the following changes: - Stripped out 6515 variant code. (See my previous patch in this series) - Add the regulator to the mpu core instead of only the i2c variant. - Add error handling. - Release the regulator on suspend, device remove, etc. - Device tree documentation. .../bindings/iio/imu/inv_mpu6050.txt | 1 + drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 57 +-- drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 2 +- drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 3 + drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c | 9 +++ 5 files changed, 66 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt index b7def51c8ad9..d39907b12a46 100644 --- a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt +++ b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt @@ -21,6 +21,7 @@ Required properties: bindings. Optional properties: + - vddio-supply: regulator phandle for VDDIO supply - mount-matrix: an optional 3x3 mounting rotation matrix - i2c-gate node. These devices also support an auxiliary i2c bus. This is simple enough to be described using the i2c-gate binding. See diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 12c1b9507007..ec276b7bcc69 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "inv_mpu_iio.h" /* @@ -926,6 +927,19 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st) return result; } +static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st) +{ + int result; + + result = regulator_enable(st->vddio_supply); + if (result == 0) { + /* Give the device a little bit of time to start up. */ + usleep_range(35000, 7); + } + + return result; +} + int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type) { @@ -990,15 +1004,28 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, return -EINVAL; } + st->vddio_supply = devm_regulator_get_optional(dev, "vddio"); + if (IS_ERR(st->vddio_supply)) { + if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER) + dev_err(dev, "Failed to get vddio regulator %d\n", + (int)PTR_ERR(st->vddio_supply)); + + return PTR_ERR(st->vddio_supply); + } + + result = inv_mpu_core_enable_regulator(st); + if (result) + return result; + /* power is turned on inside check chip type*/ result = inv_check_and_setup_chip(st); if (result) - return result; + goto out_disable_regulator; result = inv_mpu6050_init_config(indio_dev); if (result) { dev_err(dev, "Could not initialize device.\n&q
Re: [PATCH 2/3] iio: imu: mpu6050: add support for regulator framework
Hello, I really don't like the idea to have regulator handled inside the driver. I know this was done like that before for Nexus 5, but I think now this is something that can be done using dts only. Does anyone know if there is a way with dts to handle regulator automatically and prevent the use in the driver? That would be a good idea to search how this handled for other drivers. Anyway, you are enforcing regulator use in your code. It doesn't seem the code will work when there is no regulator declared in the dts, which is the case for the majority of configurations. We should at least make it optional. Thanks for the contribution. JB From: Brian Masney Sent: Wednesday, July 11, 2018 03:09 To: ji...@kernel.org; robh...@kernel.org; mark.rutl...@arm.com; andy.gr...@linaro.org; david.br...@linaro.org; linux-...@vger.kernel.org; devicet...@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-...@vger.kernel.org; linux-...@vger.kernel.org Cc: jonat...@marek.ca; Jean-Baptiste Maneyrol; knaac...@gmx.de; l...@metafoo.de; pme...@pmeerw.net; mke...@xevo.com; fischerdougl...@gmail.com; bs...@kde.org; ctatlo...@gmail.com; masn...@onstation.org Subject: [PATCH 2/3] iio: imu: mpu6050: add support for regulator framework 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. This patch adds support for the regulator framework to the mpu6050 driver. Signed-off-by: Brian Masney Signed-off-by: Jonathan Marek --- This is a variation of Jonathan Marek's patch from postmarketOS https://gitlab.com/postmarketOS/linux-postmarketos/commit/b8ad1ec1859c8bbcbce94944b3f4dd68f8f9fc37 with the following changes: - Stripped out 6515 variant code. (See my previous patch in this series) - Add the regulator to the mpu core instead of only the i2c variant. - Add error handling. - Release the regulator on suspend, device remove, etc. - Device tree documentation. .../bindings/iio/imu/inv_mpu6050.txt | 1 + drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 57 +-- drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 2 +- drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 3 + drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c | 9 +++ 5 files changed, 66 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt index b7def51c8ad9..d39907b12a46 100644 --- a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt +++ b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt @@ -21,6 +21,7 @@ Required properties: bindings. Optional properties: + - vddio-supply: regulator phandle for VDDIO supply - mount-matrix: an optional 3x3 mounting rotation matrix - i2c-gate node. These devices also support an auxiliary i2c bus. This is simple enough to be described using the i2c-gate binding. See diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 12c1b9507007..ec276b7bcc69 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "inv_mpu_iio.h" /* @@ -926,6 +927,19 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st) return result; } +static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st) +{ + int result; + + result = regulator_enable(st->vddio_supply); + if (result == 0) { + /* Give the device a little bit of time to start up. */ + usleep_range(35000, 7); + } + + return result; +} + int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type) { @@ -990,15 +1004,28 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, return -EINVAL; } + st->vddio_supply = devm_regulator_get_optional(dev, "vddio"); + if (IS_ERR(st->vddio_supply)) { + if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER) + dev_err(dev, "Failed to get vddio regulator %d\n", + (int)PTR_ERR(st->vddio_supply)); + + return PTR_ERR(st->vddio_supply); + } + + result = inv_mpu_core_enable_regulator(st); + if (result) + return result; + /* power is turned on inside check chip type*/ result = inv_check_and_setup_chip(st); if (result) - return result; + goto out_disable_regulator; result = inv_mpu6050_init_config(indio_dev); if (result) { dev_err(dev, "Could not initialize device.\n&q