* [v2 00/10] Add support for Bosch BNO055 IMU [not found] <20210715141742.15072-1-andrea.merello@gmail.com> @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 10:18 ` [v2 01/10] utils_macro: introduce find_closest_unsorted() Andrea Merello ` (10 more replies) 0 siblings, 11 replies; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo This series (tries to) add support for Bosch BNO055 IMU to Linux IIO subsystem. It is made up several patches: 1/10: introduces the generic helper find_closest_unsorted() 2/10 to 5/10: add some IIO modifiers, and their documentation, to the IIO core layer, in order to being able to expose the linear acceleration and Euler angles among standard attributes. 6/10 to 8/10: add the core IIO BNO055 driver and its documentation (including documentation for DT bindings) 9/10: adds serdev BNO055 driver to actually use the IMU via serial line 10/10: adds I2C BNO055 driver to actually use the IMU via I2C wiring Differences wrt v1: - Fixed GPL license version, which was wrong due to bad copy-pastes - Make less noise in log and get rid of some dev_dbg()s - Fix deferred probe handing and fix devm_add_action_or_reset() usage - Get rid of unneeded zeroing for driver data and some IIO "val2"s - Get rid of some leftovers of my attempt to support interrupts (which don't fully work unless the IMU firmware gets updated) - Move IIO buffer off stack and make sure its first zeroed not to leak kernel data - Hopefully addressed all maintainers and reviewers stylistic advices; fixed some typos - Take advantage of more kernel helpers. Note: this series depends on Yury Norov bitmap series i.e. "[PATCH 14/16] bitmap: unify find_bit operations" - Make find_closest_unsorted() become an external generic helper - Reworked sysfs ABI as per maintainers advices - Added ABI documentation where needed - Added I2C support - Reworked DT documentation as per maintainers advices. Added I2C example The serial protocol handling have been criticized because it is not very robust, however I couldn't really find any way to improve it; no changes here wrt v1. I think the protocol itself is inherently weak and there is nothing we can do about this (BTW here it is working fine). Differences wrt other BNO055 drivers: Previously at least another driver for the very same chip has been posted to the Linux ML [0], but it has been never merged, and it seems no one cared of it since quite a long time. This driver differs from the above driver on the following aspects: - This driver supports also serial access - The above driver tried to support all IMU HW modes by allowing to choose one in the DT, and adapting IIO attributes accordingly. This driver does not rely on DT for this, instead settings are done via sysfs attributes. All IIO attributes are always exposed; more on this later on. This driver however supports only a subset of the HW-supported modes. - This driver has some support for managing the IMU calibration Supported operation modes: - AMG (accelerometer, magnetometer and gyroscope) mode, which provides raw (uncalibrated) measurements from the said sensors, and allows for setting some parameters about them (e.g. filter cut-off frequency, max sensor ranges, etc). - Fusion mode, which still provides AMG measures, while it also provides other data calculated by the IMU (e.g. rotation angles, linear acceleration, etc). In this mode user has no freedom to set any sensor parameter, since the HW locks them. Autocalibration and correction is performed by the IMU. IIO attributes exposing sensors parameters are always present, but in fusion modes the available values are constrained to just the one used by the HW. This is reflected in the '*_available' IIO attributes. Trying to set a not-supported value always falls back to the closest supported one, which in this case is just the one in use by the HW. IIO attributes for unavailable measurements (e.g. Euler angles in AMG mode) just read zero (which is consistent WRT what you get when reading from a buffer with those attributes enabled). IMU calibration: The IMU supports for two sets of calibration parameters: - SIC matrix. user-provided; this driver doesn't currently support it - Offset and radius parameters. The IMU automatically finds out them when it is running in fusion mode; supported by this driver. The driver provides access to autocalibration flags (i.e. you can known if the IMU has successfully autocalibrated) and to calibration data blob. The user can save this blob in a "firmware" file (i.e. in /lib/firmware) that the driver looks for at probe time. If found, then the IMU is initialized with this calibration data. This saves the user from performing the calibration procedure every time (which consist of moving the IMU in various way). The driver looks for calibration data file using two different names: first a file whose name is suffixed with the IMU unique ID is searched for; this is useful when there is more than one IMU instance. If this file is not found, then a "generic" calibration file is searched for (which can be used when only one IMU is present, without struggling with fancy names, that changes on each device). In AMG mode the IIO 'offset' attributes provide access to the offsets from calibration data (if any), so that the user can apply them to the accel, angvel and magn IIO attributes. In fusion mode they are not needed and read as zero. Access protocols and serdev module: The serial protocol is quite simple, but there are tricks to make it really works. Those tricks and workarounds are documented in the driver source file. The core BNO055 driver tries to group readings in burst when appropriate, in order to optimize triggered buffer operation. The threshold for splitting a burst (i.e. max number of unused bytes in the middle of a burst that will be throw away) is provided to the core driver by the lowlevel access driver (either serdev or I2C) at probe time. [0] https://www.spinics.net/lists/linux-iio/msg25508.html Andrea Merello (10): utils_macro: introduce find_closest_unsorted() iio: document linear acceleration modifiers iio: document euler angles modifiers iio: add modifiers for linear acceleration iio: add modifers for pitch, yaw, roll iio: document bno055 private sysfs attributes iio: imu: add Bosch Sensortec BNO055 core driver dt-bindings: iio: imu: add documentation for Bosch BNO055 bindings iio: imu: add BNO055 serdev driver iio: imu: add BNO055 I2C driver Documentation/ABI/testing/sysfs-bus-iio | 16 + .../ABI/testing/sysfs-bus-iio-bno055 | 84 + .../bindings/iio/imu/bosch,bno055.yaml | 59 + drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/bno055/Kconfig | 15 + drivers/iio/imu/bno055/Makefile | 5 + drivers/iio/imu/bno055/bno055.c | 1485 +++++++++++++++++ drivers/iio/imu/bno055/bno055.h | 12 + drivers/iio/imu/bno055/bno055_i2c.c | 54 + drivers/iio/imu/bno055/bno055_sl.c | 568 +++++++ drivers/iio/industrialio-core.c | 6 + include/linux/util_macros.h | 26 + include/uapi/linux/iio/types.h | 7 +- 14 files changed, 2338 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-bno055 create mode 100644 Documentation/devicetree/bindings/iio/imu/bosch,bno055.yaml create mode 100644 drivers/iio/imu/bno055/Kconfig create mode 100644 drivers/iio/imu/bno055/Makefile create mode 100644 drivers/iio/imu/bno055/bno055.c create mode 100644 drivers/iio/imu/bno055/bno055.h create mode 100644 drivers/iio/imu/bno055/bno055_i2c.c create mode 100644 drivers/iio/imu/bno055/bno055_sl.c -- 2.17.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* [v2 01/10] utils_macro: introduce find_closest_unsorted() 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 10:25 ` Andy Shevchenko 2021-10-28 10:18 ` [v2 02/10] iio: document linear acceleration modifiers Andrea Merello ` (9 subsequent siblings) 10 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello, Andrea Merello This is similar to find_closest() and find_closest_descending(), but, it doesn't make any assumption about the array being ordered. Signed-off-by: Andrea Merello <andrea.merello@iit.it> --- include/linux/util_macros.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/linux/util_macros.h b/include/linux/util_macros.h index 72299f261b25..b48f80ceb380 100644 --- a/include/linux/util_macros.h +++ b/include/linux/util_macros.h @@ -2,6 +2,8 @@ #ifndef _LINUX_HELPER_MACROS_H_ #define _LINUX_HELPER_MACROS_H_ +#include <linux/math.h> + #define __find_closest(x, a, as, op) \ ({ \ typeof(as) __fc_i, __fc_as = (as) - 1; \ @@ -38,4 +40,28 @@ */ #define find_closest_descending(x, a, as) __find_closest(x, a, as, >=) +/** + * find_closest_unsorted - locate the closest element in a unsorted array + * @x: The reference value. + * @a: The array in which to look for the closest element. + * @as: Size of 'a'. + * + * Similar to find_closest() but 'a' has no requirement to being sorted + */ +#define find_closest_unsorted(x, a, as) \ +({ \ + typeof(x) __fc_best_delta, __fc_delta; \ + typeof(as) __fc_i, __fc_best_idx; \ + bool __fc_first = true; \ + for (__fc_i = 0; __fc_i < (as); __fc_i++) { \ + __fc_delta = abs(a[__fc_i] - (x)); \ + if (__fc_first || __fc_delta < __fc_best_delta) { \ + __fc_best_delta = __fc_delta; \ + __fc_best_idx = __fc_i; \ + } \ + __fc_first = false; \ + } \ + (__fc_best_idx); \ +}) + #endif -- 2.17.1 ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 01/10] utils_macro: introduce find_closest_unsorted() 2021-10-28 10:18 ` [v2 01/10] utils_macro: introduce find_closest_unsorted() Andrea Merello @ 2021-10-28 10:25 ` Andy Shevchenko 2021-11-08 11:05 ` Andrea Merello 0 siblings, 1 reply; 55+ messages in thread From: Andy Shevchenko @ 2021-10-28 10:25 UTC (permalink / raw) To: Andrea Merello Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, Linux Kernel Mailing List, devicetree, Lars-Peter Clausen, Rob Herring, Matt Ranostay, Alexandru Ardelean, jmondi, Andrea Merello On Thu, Oct 28, 2021 at 1:18 PM Andrea Merello <andrea.merello@gmail.com> wrote: > > This is similar to find_closest() and find_closest_descending(), but, it > doesn't make any assumption about the array being ordered. Macros in general are not so welcoming. Why do you do it as a macro? ... > +#include <linux/math.h> Wondering if the current header misses other inclusions it's a direct user of. ... > +/** > + * find_closest_unsorted - locate the closest element in a unsorted array an > + * @x: The reference value. > + * @a: The array in which to look for the closest element. > + * @as: Size of 'a'. > + * > + * Similar to find_closest() but 'a' has no requirement to being sorted > + */ -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 01/10] utils_macro: introduce find_closest_unsorted() 2021-10-28 10:25 ` Andy Shevchenko @ 2021-11-08 11:05 ` Andrea Merello 0 siblings, 0 replies; 55+ messages in thread From: Andrea Merello @ 2021-11-08 11:05 UTC (permalink / raw) To: Andy Shevchenko Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, Linux Kernel Mailing List, devicetree, Lars-Peter Clausen, Rob Herring, Matt Ranostay, Alexandru Ardelean, jmondi, Andrea Merello Il giorno gio 28 ott 2021 alle ore 12:26 Andy Shevchenko <andy.shevchenko@gmail.com> ha scritto: > > On Thu, Oct 28, 2021 at 1:18 PM Andrea Merello <andrea.merello@gmail.com> wrote: > > > > This is similar to find_closest() and find_closest_descending(), but, it > > doesn't make any assumption about the array being ordered. > > Macros in general are not so welcoming. > Why do you do it as a macro? Honestly, I did that just because find_closest() and find_closest_descending() are macros (i.e. to be consistent wrt them). I see no drawbacks in making this a regular function indeed; just, do you have any advice about where should it live? > ... > > > +#include <linux/math.h> > > Wondering if the current header misses other inclusions it's a direct user of. Looking at it, it seems that also __find_closest() actually needs math.h because it (apparently incorrectly[*]) uses DIV_ROUND_CLOSEST().. [*]Indeed it seems there is another issue here about find_closest(): for example it picks the 1st element while searching for "2" in an array like this: {1,2,..} ..This needs to be reported/fixed.. > ... > > > +/** > > + * find_closest_unsorted - locate the closest element in a unsorted array > > an > > > + * @x: The reference value. > > + * @a: The array in which to look for the closest element. > > + * @as: Size of 'a'. > > + * > > + * Similar to find_closest() but 'a' has no requirement to being sorted > > + */ > > -- > With Best Regards, > Andy Shevchenko ^ permalink raw reply [flat|nested] 55+ messages in thread
* [v2 02/10] iio: document linear acceleration modifiers 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello 2021-10-28 10:18 ` [v2 01/10] utils_macro: introduce find_closest_unsorted() Andrea Merello @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 10:31 ` Andy Shevchenko 2021-10-28 10:40 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 03/10] iio: document euler angles modifiers Andrea Merello ` (8 subsequent siblings) 10 siblings, 2 replies; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello, Andrea Merello This patch introduces ABI documentation for new iio modifiers used for reporting "linear acceleration" measures. Signed-off-by: Andrea Merello <andrea.merello@iit.it> --- Documentation/ABI/testing/sysfs-bus-iio | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 6ad47a67521c..5147a00bf24a 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1957,3 +1957,11 @@ Description: Specify the percent for light sensor relative to the channel absolute value that a data field should change before an event is generated. Units are a percentage of the prior reading. + +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_x_raw +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_y_raw +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_z_raw +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Raw (unscaled) linear acceleration readings. -- 2.17.1 ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 02/10] iio: document linear acceleration modifiers 2021-10-28 10:18 ` [v2 02/10] iio: document linear acceleration modifiers Andrea Merello @ 2021-10-28 10:31 ` Andy Shevchenko 2021-11-09 7:48 ` Andrea Merello 2021-10-28 10:40 ` Jonathan Cameron 1 sibling, 1 reply; 55+ messages in thread From: Andy Shevchenko @ 2021-10-28 10:31 UTC (permalink / raw) To: Andrea Merello Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, Linux Kernel Mailing List, devicetree, Lars-Peter Clausen, Rob Herring, Matt Ranostay, Alexandru Ardelean, jmondi, Andrea Merello On Thu, Oct 28, 2021 at 1:18 PM Andrea Merello <andrea.merello@gmail.com> wrote: > > This patch introduces ABI documentation for new iio modifiers used for > reporting "linear acceleration" measures. Because of ordering and absence of Fixes tag I haven't clearly got if this is an existing set of attributes or that that will be added by the series. If the former, use a Fixes tag and place it first in the series. If the latter, move it after the actual addition of the attributes in the code. -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 02/10] iio: document linear acceleration modifiers 2021-10-28 10:31 ` Andy Shevchenko @ 2021-11-09 7:48 ` Andrea Merello 0 siblings, 0 replies; 55+ messages in thread From: Andrea Merello @ 2021-11-09 7:48 UTC (permalink / raw) To: Andy Shevchenko Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, Linux Kernel Mailing List, devicetree, Lars-Peter Clausen, Rob Herring, Matt Ranostay, Alexandru Ardelean, jmondi, Andrea Merello Il giorno gio 28 ott 2021 alle ore 12:32 Andy Shevchenko <andy.shevchenko@gmail.com> ha scritto: > > On Thu, Oct 28, 2021 at 1:18 PM Andrea Merello <andrea.merello@gmail.com> wrote: > > > > This patch introduces ABI documentation for new iio modifiers used for > > reporting "linear acceleration" measures. > > Because of ordering and absence of Fixes tag I haven't clearly got if > this is an existing set of attributes or that that will be added by > the series. If the former, use a Fixes tag and place it first in the > series. If the latter, move it after the actual addition of the > attributes in the code. The latter. Will move in V3. Thanks > -- > With Best Regards, > Andy Shevchenko ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 02/10] iio: document linear acceleration modifiers 2021-10-28 10:18 ` [v2 02/10] iio: document linear acceleration modifiers Andrea Merello 2021-10-28 10:31 ` Andy Shevchenko @ 2021-10-28 10:40 ` Jonathan Cameron 2021-11-09 8:00 ` Andrea Merello 1 sibling, 1 reply; 55+ messages in thread From: Jonathan Cameron @ 2021-10-28 10:40 UTC (permalink / raw) To: Andrea Merello Cc: mchehab+huawei, linux-iio, linux-kernel, devicetree, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello On Thu, 28 Oct 2021 12:18:32 +0200 Andrea Merello <andrea.merello@gmail.com> wrote: > This patch introduces ABI documentation for new iio modifiers used for > reporting "linear acceleration" measures. > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > --- > Documentation/ABI/testing/sysfs-bus-iio | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio > index 6ad47a67521c..5147a00bf24a 100644 > --- a/Documentation/ABI/testing/sysfs-bus-iio > +++ b/Documentation/ABI/testing/sysfs-bus-iio > @@ -1957,3 +1957,11 @@ Description: > Specify the percent for light sensor relative to the channel > absolute value that a data field should change before an event > is generated. Units are a percentage of the prior reading. > + > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_x_raw > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_y_raw > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_z_raw > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Raw (unscaled) linear acceleration readings. Probably need more information that this. What element is being 'removed' from a normal acceleration measurement? What are units after application of offset and scale? Can cross refer to the in_accel_x_raw for that info if you like. Also, but them immediately after the block with the in_accel_x_raw etc The organization fo that file needs a rethink but let us try to avoid making it worse in the meeantime! Jonathan ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 02/10] iio: document linear acceleration modifiers 2021-10-28 10:40 ` Jonathan Cameron @ 2021-11-09 8:00 ` Andrea Merello 2021-11-09 17:00 ` Jonathan Cameron 0 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-11-09 8:00 UTC (permalink / raw) To: Jonathan Cameron Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello Il giorno gio 28 ott 2021 alle ore 12:35 Jonathan Cameron <jic23@kernel.org> ha scritto: > > On Thu, 28 Oct 2021 12:18:32 +0200 > Andrea Merello <andrea.merello@gmail.com> wrote: > > > This patch introduces ABI documentation for new iio modifiers used for > > reporting "linear acceleration" measures. > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > --- > > Documentation/ABI/testing/sysfs-bus-iio | 8 ++++++++ > > 1 file changed, 8 insertions(+) > > > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio > > index 6ad47a67521c..5147a00bf24a 100644 > > --- a/Documentation/ABI/testing/sysfs-bus-iio > > +++ b/Documentation/ABI/testing/sysfs-bus-iio > > @@ -1957,3 +1957,11 @@ Description: > > Specify the percent for light sensor relative to the channel > > absolute value that a data field should change before an event > > is generated. Units are a percentage of the prior reading. > > + > > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_x_raw > > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_y_raw > > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_z_raw > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Raw (unscaled) linear acceleration readings. > > Probably need more information that this. What element is being 'removed' from > a normal acceleration measurement? What are units after application of offset and > scale? Can cross refer to the in_accel_x_raw for that info if you like. OK. So, may I just state something like "As per in_accel_X_raw attributes, but minus the gravity acceleration" ? > Also, but them immediately after the block with the in_accel_x_raw etc OK > The organization fo that file needs a rethink but let us try to avoid making > it worse in the meeantime! > > Jonathan > > ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 02/10] iio: document linear acceleration modifiers 2021-11-09 8:00 ` Andrea Merello @ 2021-11-09 17:00 ` Jonathan Cameron 0 siblings, 0 replies; 55+ messages in thread From: Jonathan Cameron @ 2021-11-09 17:00 UTC (permalink / raw) To: Andrea Merello Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On Tue, 9 Nov 2021 09:00:09 +0100 Andrea Merello <andrea.merello@gmail.com> wrote: > Il giorno gio 28 ott 2021 alle ore 12:35 Jonathan Cameron > <jic23@kernel.org> ha scritto: > > > > On Thu, 28 Oct 2021 12:18:32 +0200 > > Andrea Merello <andrea.merello@gmail.com> wrote: > > > > > This patch introduces ABI documentation for new iio modifiers used for > > > reporting "linear acceleration" measures. > > > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > > --- > > > Documentation/ABI/testing/sysfs-bus-iio | 8 ++++++++ > > > 1 file changed, 8 insertions(+) > > > > > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio > > > index 6ad47a67521c..5147a00bf24a 100644 > > > --- a/Documentation/ABI/testing/sysfs-bus-iio > > > +++ b/Documentation/ABI/testing/sysfs-bus-iio > > > @@ -1957,3 +1957,11 @@ Description: > > > Specify the percent for light sensor relative to the channel > > > absolute value that a data field should change before an event > > > is generated. Units are a percentage of the prior reading. > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_x_raw > > > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_y_raw > > > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_linear_z_raw > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Raw (unscaled) linear acceleration readings. > > > > Probably need more information that this. What element is being 'removed' from > > a normal acceleration measurement? What are units after application of offset and > > scale? Can cross refer to the in_accel_x_raw for that info if you like. > > OK. So, may I just state something like "As per in_accel_X_raw > attributes, but minus the gravity acceleration" ? Yup, something along those lines. Wow, I had a lot of typos in my email. :) Jonathan > > > Also, but them immediately after the block with the in_accel_x_raw etc > > OK > > > The organization fo that file needs a rethink but let us try to avoid making > > it worse in the meeantime! > > > > Jonathan > > > > ^ permalink raw reply [flat|nested] 55+ messages in thread
* [v2 03/10] iio: document euler angles modifiers 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello 2021-10-28 10:18 ` [v2 01/10] utils_macro: introduce find_closest_unsorted() Andrea Merello 2021-10-28 10:18 ` [v2 02/10] iio: document linear acceleration modifiers Andrea Merello @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 10:33 ` Andy Shevchenko 2021-10-28 10:41 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 04/10] iio: add modifiers for linear acceleration Andrea Merello ` (7 subsequent siblings) 10 siblings, 2 replies; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello, Andrea Merello This patch introduces ABI documentation for new modifiers used for reporting rotations expressed as euler angles (i.e. yaw, pitch, roll). Signed-off-by: Andrea Merello <andrea.merello@iit.it> --- Documentation/ABI/testing/sysfs-bus-iio | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 5147a00bf24a..f0adc2c817bd 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1965,3 +1965,11 @@ KernelVersion: 5.15 Contact: linux-iio@vger.kernel.org Description: Raw (unscaled) linear acceleration readings. + +What: /sys/bus/iio/devices/iio:deviceX/in_rot_yaw_raw +What: /sys/bus/iio/devices/iio:deviceX/in_rot_pitch_raw +What: /sys/bus/iio/devices/iio:deviceX/in_rot_roll_raw +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Raw (unscaled) euler angles readings. -- 2.17.1 ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 03/10] iio: document euler angles modifiers 2021-10-28 10:18 ` [v2 03/10] iio: document euler angles modifiers Andrea Merello @ 2021-10-28 10:33 ` Andy Shevchenko 2021-10-28 10:41 ` Jonathan Cameron 1 sibling, 0 replies; 55+ messages in thread From: Andy Shevchenko @ 2021-10-28 10:33 UTC (permalink / raw) To: Andrea Merello Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, Linux Kernel Mailing List, devicetree, Lars-Peter Clausen, Rob Herring, Matt Ranostay, Alexandru Ardelean, jmondi, Andrea Merello On Thu, Oct 28, 2021 at 1:18 PM Andrea Merello <andrea.merello@gmail.com> wrote: > > This patch introduces ABI documentation for new modifiers used for > reporting rotations expressed as euler angles (i.e. yaw, pitch, roll). As per previous patch. -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 03/10] iio: document euler angles modifiers 2021-10-28 10:18 ` [v2 03/10] iio: document euler angles modifiers Andrea Merello 2021-10-28 10:33 ` Andy Shevchenko @ 2021-10-28 10:41 ` Jonathan Cameron 2021-11-09 8:15 ` Andrea Merello 1 sibling, 1 reply; 55+ messages in thread From: Jonathan Cameron @ 2021-10-28 10:41 UTC (permalink / raw) To: Andrea Merello Cc: mchehab+huawei, linux-iio, linux-kernel, devicetree, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello On Thu, 28 Oct 2021 12:18:33 +0200 Andrea Merello <andrea.merello@gmail.com> wrote: > This patch introduces ABI documentation for new modifiers used for > reporting rotations expressed as euler angles (i.e. yaw, pitch, roll). > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > --- > Documentation/ABI/testing/sysfs-bus-iio | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio > index 5147a00bf24a..f0adc2c817bd 100644 > --- a/Documentation/ABI/testing/sysfs-bus-iio > +++ b/Documentation/ABI/testing/sysfs-bus-iio > @@ -1965,3 +1965,11 @@ KernelVersion: 5.15 > Contact: linux-iio@vger.kernel.org > Description: > Raw (unscaled) linear acceleration readings. > + > +What: /sys/bus/iio/devices/iio:deviceX/in_rot_yaw_raw > +What: /sys/bus/iio/devices/iio:deviceX/in_rot_pitch_raw > +What: /sys/bus/iio/devices/iio:deviceX/in_rot_roll_raw > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Raw (unscaled) euler angles readings. Any _raw entry should also include what the units are after application of offset and scale. Or you could just add this as more info to the in_rot_raw block as an extra sentence explaining that they are euler angles. That will lose the 'KernelVersion' information but honestly I'm not sure we care that much about that. Jonathan ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 03/10] iio: document euler angles modifiers 2021-10-28 10:41 ` Jonathan Cameron @ 2021-11-09 8:15 ` Andrea Merello 2021-11-09 17:03 ` Jonathan Cameron 0 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-11-09 8:15 UTC (permalink / raw) To: Jonathan Cameron Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello Il giorno gio 28 ott 2021 alle ore 12:37 Jonathan Cameron <jic23@kernel.org> ha scritto: > > On Thu, 28 Oct 2021 12:18:33 +0200 > Andrea Merello <andrea.merello@gmail.com> wrote: > > > This patch introduces ABI documentation for new modifiers used for > > reporting rotations expressed as euler angles (i.e. yaw, pitch, roll). > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > --- > > Documentation/ABI/testing/sysfs-bus-iio | 8 ++++++++ > > 1 file changed, 8 insertions(+) > > > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio > > index 5147a00bf24a..f0adc2c817bd 100644 > > --- a/Documentation/ABI/testing/sysfs-bus-iio > > +++ b/Documentation/ABI/testing/sysfs-bus-iio > > @@ -1965,3 +1965,11 @@ KernelVersion: 5.15 > > Contact: linux-iio@vger.kernel.org > > Description: > > Raw (unscaled) linear acceleration readings. > > + > > +What: /sys/bus/iio/devices/iio:deviceX/in_rot_yaw_raw > > +What: /sys/bus/iio/devices/iio:deviceX/in_rot_pitch_raw > > +What: /sys/bus/iio/devices/iio:deviceX/in_rot_roll_raw > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Raw (unscaled) euler angles readings. > Any _raw entry should also include what the units are after application of > offset and scale. Or you could just add this as more info to the in_rot_raw > block as an extra sentence explaining that they are euler angles. > That will lose the 'KernelVersion' information but honestly I'm not sure we > care that much about that. I'm unsure which block you are talking about: I see there are two blocks that refer to rot things: in_rot_quaternion_raw and in_rot_from_north_xxx_raw. Looking at the 1st one description, it looks very specific to quaternions to me; the 2nd seems very specific to its own thing, whatever it is.. So I would just add the missing information (unit) in the new block just being introduced, if this is ok for you. Or am I missing some other block in which I could coalesce this new euler thing? > Jonathan > > ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 03/10] iio: document euler angles modifiers 2021-11-09 8:15 ` Andrea Merello @ 2021-11-09 17:03 ` Jonathan Cameron 0 siblings, 0 replies; 55+ messages in thread From: Jonathan Cameron @ 2021-11-09 17:03 UTC (permalink / raw) To: Andrea Merello Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On Tue, 9 Nov 2021 09:15:09 +0100 Andrea Merello <andrea.merello@gmail.com> wrote: > Il giorno gio 28 ott 2021 alle ore 12:37 Jonathan Cameron > <jic23@kernel.org> ha scritto: > > > > On Thu, 28 Oct 2021 12:18:33 +0200 > > Andrea Merello <andrea.merello@gmail.com> wrote: > > > > > This patch introduces ABI documentation for new modifiers used for > > > reporting rotations expressed as euler angles (i.e. yaw, pitch, roll). > > > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > > --- > > > Documentation/ABI/testing/sysfs-bus-iio | 8 ++++++++ > > > 1 file changed, 8 insertions(+) > > > > > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio > > > index 5147a00bf24a..f0adc2c817bd 100644 > > > --- a/Documentation/ABI/testing/sysfs-bus-iio > > > +++ b/Documentation/ABI/testing/sysfs-bus-iio > > > @@ -1965,3 +1965,11 @@ KernelVersion: 5.15 > > > Contact: linux-iio@vger.kernel.org > > > Description: > > > Raw (unscaled) linear acceleration readings. > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/in_rot_yaw_raw > > > +What: /sys/bus/iio/devices/iio:deviceX/in_rot_pitch_raw > > > +What: /sys/bus/iio/devices/iio:deviceX/in_rot_roll_raw > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Raw (unscaled) euler angles readings. > > Any _raw entry should also include what the units are after application of > > offset and scale. Or you could just add this as more info to the in_rot_raw > > block as an extra sentence explaining that they are euler angles. > > That will lose the 'KernelVersion' information but honestly I'm not sure we > > care that much about that. > > I'm unsure which block you are talking about: I see there are two > blocks that refer to rot things: in_rot_quaternion_raw and > in_rot_from_north_xxx_raw. > > Looking at the 1st one description, it looks very specific to > quaternions to me; the 2nd seems very specific to its own thing, > whatever it is.. So I would just add the missing information (unit) in > the new block just being introduced, if this is ok for you. Or am I > missing some other block in which I could coalesce this new euler > thing? Good point, not sure what I was thinking. There isn't a sensible block to add this to. So just add the info about units. Jonathan > > > > Jonathan > > > > ^ permalink raw reply [flat|nested] 55+ messages in thread
* [v2 04/10] iio: add modifiers for linear acceleration 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello ` (2 preceding siblings ...) 2021-10-28 10:18 ` [v2 03/10] iio: document euler angles modifiers Andrea Merello @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 10:45 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 05/10] iio: add modifers for pitch, yaw, roll Andrea Merello ` (6 subsequent siblings) 10 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello, Andrea Merello This patch is preparatory for adding the Bosh BNO055 IMU driver. The said IMU can report raw accelerations (among x, y and z axis) as well as the so called "linear accelerations" (again, among x, y and z axis) which is basically the acceleration after subtracting gravity. This patch adds IIO_MOD_ACCEL_LINEAR_X, IIO_MOD_ACCEL_LINEAR_Y and IIO_MOD_ACCEL_LINEAR_Z modifiers to te IIO core. Signed-off-by: Andrea Merello <andrea.merello@iit.it> --- drivers/iio/industrialio-core.c | 3 +++ include/uapi/linux/iio/types.h | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2dbb37e09b8c..a79cb32207e4 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -134,6 +134,9 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_ETHANOL] = "ethanol", [IIO_MOD_H2] = "h2", [IIO_MOD_O2] = "o2", + [IIO_MOD_ACCEL_LINEAR_X] = "linear_x", + [IIO_MOD_ACCEL_LINEAR_Y] = "linear_y", + [IIO_MOD_ACCEL_LINEAR_Z] = "linear_z" }; /* relies on pairs of these shared then separate */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 48c13147c0a8..db00f7c45f48 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -95,6 +95,9 @@ enum iio_modifier { IIO_MOD_ETHANOL, IIO_MOD_H2, IIO_MOD_O2, + IIO_MOD_ACCEL_LINEAR_X, + IIO_MOD_ACCEL_LINEAR_Y, + IIO_MOD_ACCEL_LINEAR_Z, }; enum iio_event_type { @@ -114,4 +117,3 @@ enum iio_event_direction { }; #endif /* _UAPI_IIO_TYPES_H_ */ - -- 2.17.1 ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 04/10] iio: add modifiers for linear acceleration 2021-10-28 10:18 ` [v2 04/10] iio: add modifiers for linear acceleration Andrea Merello @ 2021-10-28 10:45 ` Jonathan Cameron 2021-11-09 9:58 ` Andrea Merello 0 siblings, 1 reply; 55+ messages in thread From: Jonathan Cameron @ 2021-10-28 10:45 UTC (permalink / raw) To: Andrea Merello Cc: mchehab+huawei, linux-iio, linux-kernel, devicetree, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello On Thu, 28 Oct 2021 12:18:34 +0200 Andrea Merello <andrea.merello@gmail.com> wrote: > This patch is preparatory for adding the Bosh BNO055 IMU driver. > The said IMU can report raw accelerations (among x, y and z axis) > as well as the so called "linear accelerations" (again, among x, > y and z axis) which is basically the acceleration after subtracting > gravity. > > This patch adds IIO_MOD_ACCEL_LINEAR_X, IIO_MOD_ACCEL_LINEAR_Y and > IIO_MOD_ACCEL_LINEAR_Z modifiers to te IIO core. > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> They sometimes get forgotten but we should also update tools/iio/iio_event_montitor.c to handle these new modifiers. That can be a separate patch, but also fine to do it in this one. > --- > drivers/iio/industrialio-core.c | 3 +++ > include/uapi/linux/iio/types.h | 4 +++- > 2 files changed, 6 insertions(+), 1 deletion(-) > > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c > index 2dbb37e09b8c..a79cb32207e4 100644 > --- a/drivers/iio/industrialio-core.c > +++ b/drivers/iio/industrialio-core.c > @@ -134,6 +134,9 @@ static const char * const iio_modifier_names[] = { > [IIO_MOD_ETHANOL] = "ethanol", > [IIO_MOD_H2] = "h2", > [IIO_MOD_O2] = "o2", > + [IIO_MOD_ACCEL_LINEAR_X] = "linear_x", > + [IIO_MOD_ACCEL_LINEAR_Y] = "linear_y", > + [IIO_MOD_ACCEL_LINEAR_Z] = "linear_z" > }; > > /* relies on pairs of these shared then separate */ > diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h > index 48c13147c0a8..db00f7c45f48 100644 > --- a/include/uapi/linux/iio/types.h > +++ b/include/uapi/linux/iio/types.h > @@ -95,6 +95,9 @@ enum iio_modifier { > IIO_MOD_ETHANOL, > IIO_MOD_H2, > IIO_MOD_O2, > + IIO_MOD_ACCEL_LINEAR_X, > + IIO_MOD_ACCEL_LINEAR_Y, > + IIO_MOD_ACCEL_LINEAR_Z, It might be useful for other channel types, so probably drop the ACCEL part of the name. I'll admit I can't immediately think of what, but you never know.. :) > }; > > enum iio_event_type { > @@ -114,4 +117,3 @@ enum iio_event_direction { > }; > > #endif /* _UAPI_IIO_TYPES_H_ */ > - ? ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 04/10] iio: add modifiers for linear acceleration 2021-10-28 10:45 ` Jonathan Cameron @ 2021-11-09 9:58 ` Andrea Merello 2021-11-09 17:05 ` Jonathan Cameron 0 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-11-09 9:58 UTC (permalink / raw) To: Jonathan Cameron Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello Il giorno gio 28 ott 2021 alle ore 12:41 Jonathan Cameron <jic23@kernel.org> ha scritto: > > On Thu, 28 Oct 2021 12:18:34 +0200 > Andrea Merello <andrea.merello@gmail.com> wrote: > > > This patch is preparatory for adding the Bosh BNO055 IMU driver. > > The said IMU can report raw accelerations (among x, y and z axis) > > as well as the so called "linear accelerations" (again, among x, > > y and z axis) which is basically the acceleration after subtracting > > gravity. > > > > This patch adds IIO_MOD_ACCEL_LINEAR_X, IIO_MOD_ACCEL_LINEAR_Y and > > IIO_MOD_ACCEL_LINEAR_Z modifiers to te IIO core. > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > They sometimes get forgotten but we should also update > tools/iio/iio_event_montitor.c to handle these new modifiers. I'm not so familiar with this tool, but it seems like it has to do with IIO events, which the bno055 driver doesn't use. On the other hand the modifiers I would add are not used by any other driver right now. So I would say that it would end up in adding things that I couldn't test.. Or is there any test infrastructure for this? It seems trivial, just a matter of a few defines, so it shouldn't be an issue indeed.. > That can be a separate patch, but also fine to do it in this one. > > > --- > > drivers/iio/industrialio-core.c | 3 +++ > > include/uapi/linux/iio/types.h | 4 +++- > > 2 files changed, 6 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c > > index 2dbb37e09b8c..a79cb32207e4 100644 > > --- a/drivers/iio/industrialio-core.c > > +++ b/drivers/iio/industrialio-core.c > > @@ -134,6 +134,9 @@ static const char * const iio_modifier_names[] = { > > [IIO_MOD_ETHANOL] = "ethanol", > > [IIO_MOD_H2] = "h2", > > [IIO_MOD_O2] = "o2", > > + [IIO_MOD_ACCEL_LINEAR_X] = "linear_x", > > + [IIO_MOD_ACCEL_LINEAR_Y] = "linear_y", > > + [IIO_MOD_ACCEL_LINEAR_Z] = "linear_z" > > }; > > > > /* relies on pairs of these shared then separate */ > > diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h > > index 48c13147c0a8..db00f7c45f48 100644 > > --- a/include/uapi/linux/iio/types.h > > +++ b/include/uapi/linux/iio/types.h > > @@ -95,6 +95,9 @@ enum iio_modifier { > > IIO_MOD_ETHANOL, > > IIO_MOD_H2, > > IIO_MOD_O2, > > + IIO_MOD_ACCEL_LINEAR_X, > > + IIO_MOD_ACCEL_LINEAR_Y, > > + IIO_MOD_ACCEL_LINEAR_Z, > > It might be useful for other channel types, so probably drop the ACCEL > part of the name. > > I'll admit I can't immediately think of what, but you never know.. :) But in this case what should I write in the ABI documentation? If I state that this is something that makes the gravity not being included then isn't it intrinsically tied to be an acceleration? Or, I do that, and if someone eventually finds another use, then she/he will change the ABI doc? > > }; > > > > enum iio_event_type { > > @@ -114,4 +117,3 @@ enum iio_event_direction { > > }; > > > > #endif /* _UAPI_IIO_TYPES_H_ */ > > - > ? > > ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 04/10] iio: add modifiers for linear acceleration 2021-11-09 9:58 ` Andrea Merello @ 2021-11-09 17:05 ` Jonathan Cameron 0 siblings, 0 replies; 55+ messages in thread From: Jonathan Cameron @ 2021-11-09 17:05 UTC (permalink / raw) To: Andrea Merello, linux-kernel, devicetree Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On Tue, 9 Nov 2021 10:58:19 +0100 Andrea Merello <andrea.merello@gmail.com> wrote: > Il giorno gio 28 ott 2021 alle ore 12:41 Jonathan Cameron > <jic23@kernel.org> ha scritto: > > > > On Thu, 28 Oct 2021 12:18:34 +0200 > > Andrea Merello <andrea.merello@gmail.com> wrote: > > > > > This patch is preparatory for adding the Bosh BNO055 IMU driver. > > > The said IMU can report raw accelerations (among x, y and z axis) > > > as well as the so called "linear accelerations" (again, among x, > > > y and z axis) which is basically the acceleration after subtracting > > > gravity. > > > > > > This patch adds IIO_MOD_ACCEL_LINEAR_X, IIO_MOD_ACCEL_LINEAR_Y and > > > IIO_MOD_ACCEL_LINEAR_Z modifiers to te IIO core. > > > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > > > They sometimes get forgotten but we should also update > > tools/iio/iio_event_montitor.c to handle these new modifiers. > > I'm not so familiar with this tool, but it seems like it has to do > with IIO events, which the bno055 driver doesn't use. On the other > hand the modifiers I would add are not used by any other driver right > now. > > So I would say that it would end up in adding things that I couldn't > test.. Or is there any test infrastructure for this? It seems trivial, > just a matter of a few defines, so it shouldn't be an issue indeed.. > > > That can be a separate patch, but also fine to do it in this one. > > > > > --- > > > drivers/iio/industrialio-core.c | 3 +++ > > > include/uapi/linux/iio/types.h | 4 +++- > > > 2 files changed, 6 insertions(+), 1 deletion(-) > > > > > > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c > > > index 2dbb37e09b8c..a79cb32207e4 100644 > > > --- a/drivers/iio/industrialio-core.c > > > +++ b/drivers/iio/industrialio-core.c > > > @@ -134,6 +134,9 @@ static const char * const iio_modifier_names[] = { > > > [IIO_MOD_ETHANOL] = "ethanol", > > > [IIO_MOD_H2] = "h2", > > > [IIO_MOD_O2] = "o2", > > > + [IIO_MOD_ACCEL_LINEAR_X] = "linear_x", > > > + [IIO_MOD_ACCEL_LINEAR_Y] = "linear_y", > > > + [IIO_MOD_ACCEL_LINEAR_Z] = "linear_z" > > > }; > > > > > > /* relies on pairs of these shared then separate */ > > > diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h > > > index 48c13147c0a8..db00f7c45f48 100644 > > > --- a/include/uapi/linux/iio/types.h > > > +++ b/include/uapi/linux/iio/types.h > > > @@ -95,6 +95,9 @@ enum iio_modifier { > > > IIO_MOD_ETHANOL, > > > IIO_MOD_H2, > > > IIO_MOD_O2, > > > + IIO_MOD_ACCEL_LINEAR_X, > > > + IIO_MOD_ACCEL_LINEAR_Y, > > > + IIO_MOD_ACCEL_LINEAR_Z, > > > > It might be useful for other channel types, so probably drop the ACCEL > > part of the name. > > > > I'll admit I can't immediately think of what, but you never know.. :) > > But in this case what should I write in the ABI documentation? If I > state that this is something that makes the gravity not being included > then isn't it intrinsically tied to be an acceleration? Or, I do > that, and if someone eventually finds another use, then she/he will > change the ABI doc? The ABI docs are only documenting the complete ABI, not separately the modifier so you will be documenting the same thing whatever we call the modifier inside the code. I'm just suggesting you call the enum entries the more generic IIO_MOD_LINEAR_X, etc, not a change to the resulting string. Jonathan > > > > }; > > > > > > enum iio_event_type { > > > @@ -114,4 +117,3 @@ enum iio_event_direction { > > > }; > > > > > > #endif /* _UAPI_IIO_TYPES_H_ */ > > > - > > ? > > > > ^ permalink raw reply [flat|nested] 55+ messages in thread
* [v2 05/10] iio: add modifers for pitch, yaw, roll 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello ` (3 preceding siblings ...) 2021-10-28 10:18 ` [v2 04/10] iio: add modifiers for linear acceleration Andrea Merello @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 10:47 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 06/10] iio: document bno055 private sysfs attributes Andrea Merello ` (5 subsequent siblings) 10 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello, Andrea Merello This patch adds modifiers for reporting rotations as euler angles (i.e. yaw, pitch and roll). Signed-off-by: Andrea Merello <andrea.merello@iit.it> --- drivers/iio/industrialio-core.c | 5 ++++- include/uapi/linux/iio/types.h | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index a79cb32207e4..d2ebbfa8b9fc 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -136,7 +136,10 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_O2] = "o2", [IIO_MOD_ACCEL_LINEAR_X] = "linear_x", [IIO_MOD_ACCEL_LINEAR_Y] = "linear_y", - [IIO_MOD_ACCEL_LINEAR_Z] = "linear_z" + [IIO_MOD_ACCEL_LINEAR_Z] = "linear_z", + [IIO_MOD_PITCH] = "pitch", + [IIO_MOD_YAW] = "yaw", + [IIO_MOD_ROLL] = "roll" }; /* relies on pairs of these shared then separate */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index db00f7c45f48..fc9909ca4f95 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -98,6 +98,9 @@ enum iio_modifier { IIO_MOD_ACCEL_LINEAR_X, IIO_MOD_ACCEL_LINEAR_Y, IIO_MOD_ACCEL_LINEAR_Z, + IIO_MOD_PITCH, + IIO_MOD_YAW, + IIO_MOD_ROLL }; enum iio_event_type { -- 2.17.1 ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 05/10] iio: add modifers for pitch, yaw, roll 2021-10-28 10:18 ` [v2 05/10] iio: add modifers for pitch, yaw, roll Andrea Merello @ 2021-10-28 10:47 ` Jonathan Cameron 0 siblings, 0 replies; 55+ messages in thread From: Jonathan Cameron @ 2021-10-28 10:47 UTC (permalink / raw) To: Andrea Merello Cc: mchehab+huawei, linux-iio, linux-kernel, devicetree, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello On Thu, 28 Oct 2021 12:18:35 +0200 Andrea Merello <andrea.merello@gmail.com> wrote: > This patch adds modifiers for reporting rotations as euler angles (i.e. > yaw, pitch and roll). > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> Same comment on tools update, and a few editorial things inline. Jonathan > --- > drivers/iio/industrialio-core.c | 5 ++++- > include/uapi/linux/iio/types.h | 3 +++ > 2 files changed, 7 insertions(+), 1 deletion(-) > > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c > index a79cb32207e4..d2ebbfa8b9fc 100644 > --- a/drivers/iio/industrialio-core.c > +++ b/drivers/iio/industrialio-core.c > @@ -136,7 +136,10 @@ static const char * const iio_modifier_names[] = { > [IIO_MOD_O2] = "o2", > [IIO_MOD_ACCEL_LINEAR_X] = "linear_x", > [IIO_MOD_ACCEL_LINEAR_Y] = "linear_y", > - [IIO_MOD_ACCEL_LINEAR_Z] = "linear_z" > + [IIO_MOD_ACCEL_LINEAR_Z] = "linear_z", Move the comman to the previous patch. > + [IIO_MOD_PITCH] = "pitch", > + [IIO_MOD_YAW] = "yaw", > + [IIO_MOD_ROLL] = "roll" > }; > > /* relies on pairs of these shared then separate */ > diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h > index db00f7c45f48..fc9909ca4f95 100644 > --- a/include/uapi/linux/iio/types.h > +++ b/include/uapi/linux/iio/types.h > @@ -98,6 +98,9 @@ enum iio_modifier { > IIO_MOD_ACCEL_LINEAR_X, > IIO_MOD_ACCEL_LINEAR_Y, > IIO_MOD_ACCEL_LINEAR_Z, > + IIO_MOD_PITCH, > + IIO_MOD_YAW, > + IIO_MOD_ROLL And add a comma here to make extending this in future easy. > }; > > enum iio_event_type { ^ permalink raw reply [flat|nested] 55+ messages in thread
* [v2 06/10] iio: document bno055 private sysfs attributes 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello ` (4 preceding siblings ...) 2021-10-28 10:18 ` [v2 05/10] iio: add modifers for pitch, yaw, roll Andrea Merello @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 11:04 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 07/10] iio: imu: add Bosch Sensortec BNO055 core driver Andrea Merello ` (4 subsequent siblings) 10 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello, Andrea Merello This patch adds ABI documentation for bno055 driver private sysfs attributes. Signed-off-by: Andrea Merello <andrea.merello@iit.it> --- .../ABI/testing/sysfs-bus-iio-bno055 | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-bno055 diff --git a/Documentation/ABI/testing/sysfs-bus-iio-bno055 b/Documentation/ABI/testing/sysfs-bus-iio-bno055 new file mode 100644 index 000000000000..930a70c5a858 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-bno055 @@ -0,0 +1,84 @@ +What: /sys/bus/iio/devices/iio:deviceX/in_accel_range +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Range for acceleration readings in G. Note that this does not + affects the scale (which should be used when changing the + maximum and minimum readable value affects also the reading + scaling factor). + +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_range +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Range for angular velocity readings in dps. Note that this does + not affects the scale (which should be used when changing the + maximum and minimum readable value affects also the reading + scaling factor). + +What: /sys/bus/iio/devices/iio:deviceX/in_accel_range_available +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + List of allowed values for in_accel_range attribute + +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_range_available +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + List of allowed values for in_anglvel_range attribute + +What: /sys/bus/iio/devices/iio:deviceX/fast_magnetometer_calibration_enable +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Can be 1 or 0. Enables/disables the "Fast Magnetometer + Calibration" HW function. + +What: /sys/bus/iio/devices/iio:deviceX/fusion_enable +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Can be 1 or 0. Enables/disables the "sensor fusion" (a.k.a. + NDOF) HW function. + +What: /sys/bus/iio/devices/iio:deviceX/in_calibration_data +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Reports the binary calibration data blob for the IMU sensors. + +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_accel +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". + Report the autocalibration status for the accelerometer sensor. + +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_gyro +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". + Reports the autocalibration status for the gyroscope sensor. + +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_magn +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". + Reports the autocalibration status for the magnetometer sensor. + +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_sys +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". + Reports the status for the IMU overall autocalibration. + +What: /sys/bus/iio/devices/iio:deviceX/unique_id +KernelVersion: 5.15 +Contact: linux-iio@vger.kernel.org +Description: + 16-bytes, 2-digits-per-byte, HEX-string representing the sensor + unique ID number. -- 2.17.1 ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 06/10] iio: document bno055 private sysfs attributes 2021-10-28 10:18 ` [v2 06/10] iio: document bno055 private sysfs attributes Andrea Merello @ 2021-10-28 11:04 ` Jonathan Cameron 2021-11-09 10:22 ` Andrea Merello 0 siblings, 1 reply; 55+ messages in thread From: Jonathan Cameron @ 2021-10-28 11:04 UTC (permalink / raw) To: Andrea Merello Cc: mchehab+huawei, linux-iio, linux-kernel, devicetree, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello On Thu, 28 Oct 2021 12:18:36 +0200 Andrea Merello <andrea.merello@gmail.com> wrote: > This patch adds ABI documentation for bno055 driver private sysfs > attributes. Hohum. As normal I dislike custom attributes but reality is these don't map to anything 'standard' and I don't want them getting adopted in places where the 'standard' approach works. So thinking a bit more on this, I wonder if we can fit it into standard ABI. We can't use the normal range specification method of _scale because it's internal to the device and the output reading is unaffected. The range specification via _raw_available would let us know the range, but it is not writeable so.. A control that changes the internal scaling of the sensor in a fashion that is not visible to the outside world maps to calibscale. Whilst that was intended for little tweaks to the input signal (often front end amplifier gain tweak) it works here. It doesn't map through to anything userspace is expected to apply. That combined with _raw_available to let us know what the result is should work? What do you think of that approach? It's obviously a little more complex to handle in the driver, but it does map to existing ABI and avoids custom attributes etc. > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > --- > .../ABI/testing/sysfs-bus-iio-bno055 | 84 +++++++++++++++++++ > 1 file changed, 84 insertions(+) > create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-bno055 > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio-bno055 b/Documentation/ABI/testing/sysfs-bus-iio-bno055 > new file mode 100644 > index 000000000000..930a70c5a858 > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-bus-iio-bno055 > @@ -0,0 +1,84 @@ > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_range > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Range for acceleration readings in G. Note that this does not > + affects the scale (which should be used when changing the > + maximum and minimum readable value affects also the reading > + scaling factor). Having this in G but the sensor output in m/s^2 seems inconsistent. > + > +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_range > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Range for angular velocity readings in dps. Note that this does > + not affects the scale (which should be used when changing the > + maximum and minimum readable value affects also the reading > + scaling factor). Again, units need to match or this is going to be really confusing. > + > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_range_available > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + List of allowed values for in_accel_range attribute > + > +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_range_available > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + List of allowed values for in_anglvel_range attribute > + > +What: /sys/bus/iio/devices/iio:deviceX/fast_magnetometer_calibration_enable > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Can be 1 or 0. Enables/disables the "Fast Magnetometer > + Calibration" HW function. Naming needs to be consistent with the ABI. This is a channel type specific function and to match existing calibration related ABI naming it would be. in_magn_calibration_fast_enable Some of the others need renaming in a similar way. > + > +What: /sys/bus/iio/devices/iio:deviceX/fusion_enable > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Can be 1 or 0. Enables/disables the "sensor fusion" (a.k.a. > + NDOF) HW function. > + > +What: /sys/bus/iio/devices/iio:deviceX/in_calibration_data > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Reports the binary calibration data blob for the IMU sensors. Why in_ ? What channels does this apply to? > + > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_accel > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > + Report the autocalibration status for the accelerometer sensor. For interfaces that really don't have any chance of generalising this one is terrible. Any hope at all of mapping this to something numeric? in_accel_calibration_auto_status > + > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_gyro > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > + Reports the autocalibration status for the gyroscope sensor. in_angvel_calibration_auto_status etc. > + > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_magn > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > + Reports the autocalibration status for the magnetometer sensor. > + > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_sys > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > + Reports the status for the IMU overall autocalibration. > + > +What: /sys/bus/iio/devices/iio:deviceX/unique_id Hmm. So normally we just dump these in the kernel log. I guess you need it here to associate a calibration blob with a particular sensor? We could put it in label, but that would stop us using that for things like positioning of the sensor. So perhaps this is something that we should add to the main ABI doc. Probably as serial_number rather than unique ID though. > +KernelVersion: 5.15 > +Contact: linux-iio@vger.kernel.org > +Description: > + 16-bytes, 2-digits-per-byte, HEX-string representing the sensor > + unique ID number. ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 06/10] iio: document bno055 private sysfs attributes 2021-10-28 11:04 ` Jonathan Cameron @ 2021-11-09 10:22 ` Andrea Merello 2021-11-14 16:20 ` Jonathan Cameron 0 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-11-09 10:22 UTC (permalink / raw) To: Jonathan Cameron Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello Few inline comments; ok for the rest. Il giorno gio 28 ott 2021 alle ore 12:59 Jonathan Cameron <jic23@kernel.org> ha scritto: > > On Thu, 28 Oct 2021 12:18:36 +0200 > Andrea Merello <andrea.merello@gmail.com> wrote: > > > This patch adds ABI documentation for bno055 driver private sysfs > > attributes. > > Hohum. As normal I dislike custom attributes but reality is these > don't map to anything 'standard' and I don't want them getting adopted > in places where the 'standard' approach works. > > So thinking a bit more on this, I wonder if we can fit it into standard > ABI. > > We can't use the normal range specification method of > _scale because it's internal to the device and the output reading is > unaffected. The range specification via _raw_available would let us know > the range, but it is not writeable so.. > > A control that changes the internal scaling of the sensor in a fashion > that is not visible to the outside world maps to calibscale. Whilst > that was intended for little tweaks to the input signal (often front > end amplifier gain tweak) it works here. It doesn't map through to > anything userspace is expected to apply. That combined with > _raw_available to let us know what the result is should work? > > What do you think of that approach? It's obviously a little more complex > to handle in the driver, but it does map to existing ABI and avoids > custom attributes etc. If I read the ABI documentation, then I would say that calibscale has nothing to do with this, but I think you have obviously a better feeling than me about what calibscale is really for. To be honest I've probably not a clear idea about what calibscale is indeed... In general, I would say that is better to stick to standard attributes when possible, and of course to avoid having the same thing mapped on random custom attributes in each driver, but IMO only up to the extent which doesn't force something that is really something different to map on a standard thing just because of the sake of having as much standard things as possible... But all this is probably quite obvious, and it all depends on the above (i.e. is it calibscale fitting well in your opinion?) .. Up to you on this one.. BTW I'm missing why this should complicate the driver.. I guess I'll find out if I'll implement it :) > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > --- > > .../ABI/testing/sysfs-bus-iio-bno055 | 84 +++++++++++++++++++ > > 1 file changed, 84 insertions(+) > > create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-bno055 > > > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio-bno055 b/Documentation/ABI/testing/sysfs-bus-iio-bno055 > > new file mode 100644 > > index 000000000000..930a70c5a858 > > --- /dev/null > > +++ b/Documentation/ABI/testing/sysfs-bus-iio-bno055 > > @@ -0,0 +1,84 @@ > > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_range > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Range for acceleration readings in G. Note that this does not > > + affects the scale (which should be used when changing the > > + maximum and minimum readable value affects also the reading > > + scaling factor). > > Having this in G but the sensor output in m/s^2 seems inconsistent. > > > + > > +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_range > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Range for angular velocity readings in dps. Note that this does > > + not affects the scale (which should be used when changing the > > + maximum and minimum readable value affects also the reading > > + scaling factor). > > Again, units need to match or this is going to be really confusing. > > > + > > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_range_available > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + List of allowed values for in_accel_range attribute > > + > > +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_range_available > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + List of allowed values for in_anglvel_range attribute > > + > > +What: /sys/bus/iio/devices/iio:deviceX/fast_magnetometer_calibration_enable > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Can be 1 or 0. Enables/disables the "Fast Magnetometer > > + Calibration" HW function. > > Naming needs to be consistent with the ABI. This is a channel type specific function > and to match existing calibration related ABI naming it would be. > > in_magn_calibration_fast_enable > > Some of the others need renaming in a similar way. > > > + > > +What: /sys/bus/iio/devices/iio:deviceX/fusion_enable > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Can be 1 or 0. Enables/disables the "sensor fusion" (a.k.a. > > + NDOF) HW function. > > + > > +What: /sys/bus/iio/devices/iio:deviceX/in_calibration_data > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Reports the binary calibration data blob for the IMU sensors. > > Why in_ ? What channels does this apply to? > > > + > > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_accel > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > > + Report the autocalibration status for the accelerometer sensor. > > For interfaces that really don't have any chance of generalising this one is terrible. > Any hope at all of mapping this to something numeric? > > in_accel_calibration_auto_status > > > > + > > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_gyro > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > > + Reports the autocalibration status for the gyroscope sensor. > > in_angvel_calibration_auto_status > etc. > > > + > > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_magn > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > > + Reports the autocalibration status for the magnetometer sensor. > > + > > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_sys > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > > + Reports the status for the IMU overall autocalibration. > > + > > +What: /sys/bus/iio/devices/iio:deviceX/unique_id > > Hmm. So normally we just dump these in the kernel log. I guess you need it > here to associate a calibration blob with a particular sensor? Well, it was originally in kernel log, but putting in an attribute was one of the changes that has been requested for V2. It is needed by the user who copies the calibration data to the calibration file, in order for her/him to be able to properly name it (in case of more than 1 sensor on the same setup). > We could put it in label, but that would stop us using that for things like > positioning of the sensor. So perhaps this is something that we should add > to the main ABI doc. Probably as serial_number rather than unique ID though. OK, for renaming to "serial_number". I'm not sure they are conceptually the same thing, but I think it works anyway. Of course I can move its doc to the main file. Do you want a separate patch for this? > > +KernelVersion: 5.15 > > +Contact: linux-iio@vger.kernel.org > > +Description: > > + 16-bytes, 2-digits-per-byte, HEX-string representing the sensor > > + unique ID number. > ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 06/10] iio: document bno055 private sysfs attributes 2021-11-09 10:22 ` Andrea Merello @ 2021-11-14 16:20 ` Jonathan Cameron 2022-01-04 11:42 ` Andrea Merello 0 siblings, 1 reply; 55+ messages in thread From: Jonathan Cameron @ 2021-11-14 16:20 UTC (permalink / raw) To: Andrea Merello Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On Tue, 9 Nov 2021 11:22:27 +0100 Andrea Merello <andrea.merello@gmail.com> wrote: > Few inline comments; ok for the rest. > > Il giorno gio 28 ott 2021 alle ore 12:59 Jonathan Cameron > <jic23@kernel.org> ha scritto: > > > > On Thu, 28 Oct 2021 12:18:36 +0200 > > Andrea Merello <andrea.merello@gmail.com> wrote: > > > > > This patch adds ABI documentation for bno055 driver private sysfs > > > attributes. > > > > Hohum. As normal I dislike custom attributes but reality is these > > don't map to anything 'standard' and I don't want them getting adopted > > in places where the 'standard' approach works. > > > > So thinking a bit more on this, I wonder if we can fit it into standard > > ABI. > > > > We can't use the normal range specification method of > > _scale because it's internal to the device and the output reading is > > unaffected. The range specification via _raw_available would let us know > > the range, but it is not writeable so.. > > > > A control that changes the internal scaling of the sensor in a fashion > > that is not visible to the outside world maps to calibscale. Whilst > > that was intended for little tweaks to the input signal (often front > > end amplifier gain tweak) it works here. It doesn't map through to > > anything userspace is expected to apply. That combined with > > _raw_available to let us know what the result is should work? > > > > What do you think of that approach? It's obviously a little more complex > > to handle in the driver, but it does map to existing ABI and avoids > > custom attributes etc. > > If I read the ABI documentation, then I would say that calibscale has > nothing to do with this, but I think you have obviously a better > feeling than me about what calibscale is really for. To be honest I've > probably not a clear idea about what calibscale is indeed... Original intent was that it was a tweak for input amplifiers on some sensor types that you'd set as part of a calibration process. These days, for many sensors that have this it's handled at factory anyway and these tweak values are rarely exposed to software. > > In general, I would say that is better to stick to standard attributes > when possible, and of course to avoid having the same thing mapped on > random custom attributes in each driver, but IMO only up to the extent > which doesn't force something that is really something different to > map on a standard thing just because of the sake of having as much > standard things as possible... But all this is probably quite obvious, > and it all depends on the above (i.e. is it calibscale fitting well in > your opinion?) .. Up to you on this one.. > > BTW I'm missing why this should complicate the driver.. I guess I'll > find out if I'll implement it :) Inverse of the range values which is always a mess without floating point. Ok, I'm persuaded that we have to go with range here even if it is a bit painful and might cause confusion if we start getting it in lots of drivers. *fingers crossed we don't* There is still a units question though. Should we express the ranges in _processed or _raw units? Or do we make it explicit and call it rangeprocessed for example? For some devices the range will naturally be expressed as the range of ADC raw values, so there is definite room for confusion if we don't make it clear in the name. I'm open to other suggestions of how we name this to avoid falling into any heffalump traps. > > > > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > > --- > > > .../ABI/testing/sysfs-bus-iio-bno055 | 84 +++++++++++++++++++ > > > 1 file changed, 84 insertions(+) > > > create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-bno055 > > > > > > diff --git a/Documentation/ABI/testing/sysfs-bus-iio-bno055 b/Documentation/ABI/testing/sysfs-bus-iio-bno055 > > > new file mode 100644 > > > index 000000000000..930a70c5a858 > > > --- /dev/null > > > +++ b/Documentation/ABI/testing/sysfs-bus-iio-bno055 > > > @@ -0,0 +1,84 @@ > > > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_range > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Range for acceleration readings in G. Note that this does not > > > + affects the scale (which should be used when changing the > > > + maximum and minimum readable value affects also the reading > > > + scaling factor). > > > > Having this in G but the sensor output in m/s^2 seems inconsistent. > > > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_range > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Range for angular velocity readings in dps. Note that this does > > > + not affects the scale (which should be used when changing the > > > + maximum and minimum readable value affects also the reading > > > + scaling factor). > > > > Again, units need to match or this is going to be really confusing. > > > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/in_accel_range_available > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + List of allowed values for in_accel_range attribute > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_range_available > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + List of allowed values for in_anglvel_range attribute > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/fast_magnetometer_calibration_enable > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Can be 1 or 0. Enables/disables the "Fast Magnetometer > > > + Calibration" HW function. > > > > Naming needs to be consistent with the ABI. This is a channel type specific function > > and to match existing calibration related ABI naming it would be. > > > > in_magn_calibration_fast_enable > > > > Some of the others need renaming in a similar way. > > > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/fusion_enable > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Can be 1 or 0. Enables/disables the "sensor fusion" (a.k.a. > > > + NDOF) HW function. > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/in_calibration_data > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Reports the binary calibration data blob for the IMU sensors. > > > > Why in_ ? What channels does this apply to? > > > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_accel > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > > > + Report the autocalibration status for the accelerometer sensor. > > > > For interfaces that really don't have any chance of generalising this one is terrible. > > Any hope at all of mapping this to something numeric? > > > > in_accel_calibration_auto_status > > > > > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_gyro > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > > > + Reports the autocalibration status for the gyroscope sensor. > > > > in_angvel_calibration_auto_status > > etc. > > > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_magn > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > > > + Reports the autocalibration status for the magnetometer sensor. > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/in_autocalibration_status_sys > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + Can be "Idle", "Bad", "Barely enough", "Fair", or "Good". > > > + Reports the status for the IMU overall autocalibration. > > > + > > > +What: /sys/bus/iio/devices/iio:deviceX/unique_id > > > > Hmm. So normally we just dump these in the kernel log. I guess you need it > > here to associate a calibration blob with a particular sensor? > > Well, it was originally in kernel log, but putting in an attribute was > one of the changes that has been requested for V2. Oops. :) Inconsistency is my middle name... > It is needed by the user who copies the calibration data to the > calibration file, in order for her/him to be able to properly name it > (in case of more than 1 sensor on the same setup). Fair enough that makes complete sense. > > > We could put it in label, but that would stop us using that for things like > > positioning of the sensor. So perhaps this is something that we should add > > to the main ABI doc. Probably as serial_number rather than unique ID though. > > OK, for renaming to "serial_number". I'm not sure they are > conceptually the same thing, but I think it works anyway. > Of course I can move its doc to the main file. Do you want a separate > patch for this? Separate patch would be great. Thanks, Jonathan > > > > +KernelVersion: 5.15 > > > +Contact: linux-iio@vger.kernel.org > > > +Description: > > > + 16-bytes, 2-digits-per-byte, HEX-string representing the sensor > > > + unique ID number. > > ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 06/10] iio: document bno055 private sysfs attributes 2021-11-14 16:20 ` Jonathan Cameron @ 2022-01-04 11:42 ` Andrea Merello 2022-01-15 15:27 ` Jonathan Cameron 0 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2022-01-04 11:42 UTC (permalink / raw) To: Jonathan Cameron Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello Sorry for the huge delay... > There is still a units question though. Should we express the ranges > in _processed or _raw units? Or do we make it explicit and call it > rangeprocessed for example? For some devices the range will naturally > be expressed as the range of ADC raw values, so there is definite room > for confusion if we don't make it clear in the name. > > I'm open to other suggestions of how we name this to avoid falling into > any heffalump traps. You are right: this might lead to confusion.. Making it explicit in the name seems a good idea. I've looked at other iio sysfs attributes in the DOC. It seems that "thesh" and "roc" attributes allows for both preprocessed and raw data: I found e.g. "<type>[Y][_name]_<raw|input>_thresh_value", but the related "what" entries written above all seem to omit both "_raw" and "_input"; I don't understand why. In any case, maybe we can stick to that already-existent naming schema? Assuming the pattern is correct, then wouldn't it be "in_accel_raw_range" (or "in_accel_x_raw_range", in case it could have different values for each axis) or "in_accel_input_range" in case range applies to preprocessed vals, etc ? Andrea ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 06/10] iio: document bno055 private sysfs attributes 2022-01-04 11:42 ` Andrea Merello @ 2022-01-15 15:27 ` Jonathan Cameron 2022-01-17 9:37 ` Andrea Merello 0 siblings, 1 reply; 55+ messages in thread From: Jonathan Cameron @ 2022-01-15 15:27 UTC (permalink / raw) To: Andrea Merello Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On Tue, 4 Jan 2022 12:42:40 +0100 Andrea Merello <andrea.merello@gmail.com> wrote: > Sorry for the huge delay... No problem though I may have forgotten some of the discussion! > > > There is still a units question though. Should we express the ranges > > in _processed or _raw units? Or do we make it explicit and call it > > rangeprocessed for example? For some devices the range will naturally > > be expressed as the range of ADC raw values, so there is definite room > > for confusion if we don't make it clear in the name. > > > > I'm open to other suggestions of how we name this to avoid falling into > > any heffalump traps. > > You are right: this might lead to confusion.. Making it explicit in > the name seems a good idea. > > I've looked at other iio sysfs attributes in the DOC. It seems that > "thesh" and "roc" attributes allows for both preprocessed and raw > data: I found e.g. "<type>[Y][_name]_<raw|input>_thresh_value", but > the related "what" entries written above all seem to omit both "_raw" > and "_input"; I don't understand why. Excellent point. That documentation is garbage. Events are meant to pick it up implicitly from the related channel _raw or _input. I don't remember them ever having raw or input in their naming but it's possible they did right at the beginning before the ABI was anywhere near stable. Gah. I dread to think how long that that has been wrong. > > In any case, maybe we can stick to that already-existent naming schema? It doesn't exist really the docs are wrong. > > Assuming the pattern is correct, then wouldn't it be > "in_accel_raw_range" (or "in_accel_x_raw_range", in case it could > have different values for each axis) or "in_accel_input_range" in case > range applies to preprocessed vals, etc ? Tricky corner but I'd go with no, because the pattern is direction_type_infotype and in this case the infotype is rangeraw. We've not been totally consistent on whether we allow spaces in infotype or not. Intially we always did but then some of the userspace folks asked us to stop doing so because it requires all userspace software to have an explicit list rather than just adding controls to some GUI based on generic parsing. Hohum. Historical decisions that lead to messy interfaces... *sigh* Nearest to what you have here though are peak_raw and mean_raw though those are odd in of themselves in that they are basically special forms of _raw rather than something else that is in _raw units... So I think range_raw postfix is the best bet. Jonathan > > > Andrea ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 06/10] iio: document bno055 private sysfs attributes 2022-01-15 15:27 ` Jonathan Cameron @ 2022-01-17 9:37 ` Andrea Merello 2022-01-22 18:08 ` Jonathan Cameron 0 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2022-01-17 9:37 UTC (permalink / raw) To: Jonathan Cameron Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello Trivial inline comments below. Beside that, I've found another pleasing issue with this "range" thing on this device.. One one hand, things seem to always work as we discussed for the accelerometer (i.e. range doesn't affect the scale; the HW always provides readings in the same scale, but with different range and precision) on the other hand, the gyroscope behavior depends by the internal IMU firmware version.. great.. Stock firmware has a bug[0], so that the "range" gyroscope registers do change the scale indeed. AFAICT stock firmware is the one you find in most (all?) breakout boards, which are usually available (and which I'm using right now for this driver mainlining attempt). Upgrading firmware looks like a rather obscure process that AFAICT can be done only in some specific USB-stick demo-board ("shuttle board") or with maybe with FAE assistance on custom developed boards [1] (i.e. maybe can be done by some professional user; I would say not for most people). So, I'm now wondering how to handle this... I really want to support the stock FW, which seems the most widespread, and the one I have right now; I'd say this means: the accelerometer thing will still work as we discussed (i.e. the range attribute thing), while the gyro will have writeable scale, and a (ro) scale_available attrib. But what about the gyro range thing? Should I drop it, or keep it as informative read-only? Then I could also support the new firmware (which I cannot test right now with my actual breakout board, but I might see whether I could get a board with an updated IMU), keeping also the current driver behavior (i.e. range stuff). But the question is: in either cases (new vs old fw) should the non-necessary attributes disappear or they may just be RO or locked (i.e. scale_available for new FW and range stuff for the old one)? Any thoughts and advice on this whole thing would be very welcome :) my current inclination anyway now tends to be: go on supporting only the stock FW (i.e. the board I have here now) and eventually add support for the new fw later on, after merge. [0] https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/BNO055-Wrong-sensitivity-resolution-in-datasheet/td-p/10266 [1] https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/BNO055-Software-Version/td-p/14001 > > I've looked at other iio sysfs attributes in the DOC. It seems that > > "thesh" and "roc" attributes allows for both preprocessed and raw > > data: I found e.g. "<type>[Y][_name]_<raw|input>_thresh_value", but > > the related "what" entries written above all seem to omit both "_raw" > > and "_input"; I don't understand why. > > Excellent point. That documentation is garbage. Events are meant > to pick it up implicitly from the related channel _raw or _input. > I don't remember them ever having raw or input in their naming but > it's possible they did right at the beginning before the ABI was anywhere > near stable. Gah. I dread to think how long that that has been wrong. Ok, great :) > So I think range_raw postfix is the best bet. Will go with this, thanks. > Jonathan > > > > > > > > > > > > Andrea > ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 06/10] iio: document bno055 private sysfs attributes 2022-01-17 9:37 ` Andrea Merello @ 2022-01-22 18:08 ` Jonathan Cameron 0 siblings, 0 replies; 55+ messages in thread From: Jonathan Cameron @ 2022-01-22 18:08 UTC (permalink / raw) To: Andrea Merello Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On Mon, 17 Jan 2022 10:37:33 +0100 Andrea Merello <andrea.merello@gmail.com> wrote: > Trivial inline comments below. Beside that, I've found another > pleasing issue with this "range" thing on this device.. > > One one hand, things seem to always work as we discussed for the > accelerometer (i.e. range doesn't affect the scale; the HW always > provides readings in the same scale, but with different range and > precision) on the other hand, the gyroscope behavior depends by the > internal IMU firmware version.. great.. *sigh* :) > > Stock firmware has a bug[0], so that the "range" gyroscope registers > do change the scale indeed. AFAICT stock firmware is the one you find > in most (all?) breakout boards, which are usually available (and which > I'm using right now for this driver mainlining attempt). Upgrading > firmware looks like a rather obscure process that AFAICT can be done > only in some specific USB-stick demo-board ("shuttle board") or with > maybe with FAE assistance on custom developed boards [1] (i.e. maybe > can be done by some professional user; I would say not for most > people). > > So, I'm now wondering how to handle this... I really want to support > the stock FW, which seems the most widespread, and the one I have > right now; I'd say this means: the accelerometer thing will still work > as we discussed (i.e. the range attribute thing), while the gyro will > have writeable scale, and a (ro) scale_available attrib. But what > about the gyro range thing? Should I drop it, or keep it as > informative read-only? I'd be cynical and for initial version at least, just hide it as 'too complex' with a comment in the driver code on why. > > Then I could also support the new firmware (which I cannot test right > now with my actual breakout board, but I might see whether I could get > a board with an updated IMU), keeping also the current driver behavior > (i.e. range stuff). > > But the question is: in either cases (new vs old fw) should the > non-necessary attributes disappear or they may just be RO or locked > (i.e. scale_available for new FW and range stuff for the old one)? If they don't have meaning then they should disappear, but it would also be valid to have the 'broken' one be read only if there is an appropriate value. > > Any thoughts and advice on this whole thing would be very welcome :) > my current inclination anyway now tends to be: go on supporting only > the stock FW (i.e. the board I have here now) and eventually add > support for the new fw later on, after merge. Sounds sensible - but.... Make sure you check the firmware version number (I hope it has one) and print a warning at least if you get one that you have strong reason to believe will handle this differently from whatever the driver is supporting. This is definitely going to be a case for detailed comments in the driver code so that we can 'recall' what on earth was going on here in N years time! > > [0] https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/BNO055-Wrong-sensitivity-resolution-in-datasheet/td-p/10266 > [1] https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/BNO055-Software-Version/td-p/14001 > > > > I've looked at other iio sysfs attributes in the DOC. It seems that > > > "thesh" and "roc" attributes allows for both preprocessed and raw > > > data: I found e.g. "<type>[Y][_name]_<raw|input>_thresh_value", but > > > the related "what" entries written above all seem to omit both "_raw" > > > and "_input"; I don't understand why. > > > > Excellent point. That documentation is garbage. Events are meant > > to pick it up implicitly from the related channel _raw or _input. > > I don't remember them ever having raw or input in their naming but > > it's possible they did right at the beginning before the ABI was anywhere > > near stable. Gah. I dread to think how long that that has been wrong. > > Ok, great :) > > > So I think range_raw postfix is the best bet. > > Will go with this, thanks. > > > Jonathan > > > > > > > > > > > > > > > > > > > > > Andrea > > ^ permalink raw reply [flat|nested] 55+ messages in thread
* [v2 07/10] iio: imu: add Bosch Sensortec BNO055 core driver 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello ` (5 preceding siblings ...) 2021-10-28 10:18 ` [v2 06/10] iio: document bno055 private sysfs attributes Andrea Merello @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 13:31 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 08/10] dt-bindings: iio: imu: add documentation for Bosch BNO055 bindings Andrea Merello ` (3 subsequent siblings) 10 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello, Andrea Merello This patch adds a core driver for the BNO055 IMU from Bosch. This IMU can be connected via both serial and I2C busses; separate patches will add support for them. The driver supports "AMG" (Accelerometer, Magnetometer, Gyroscope) mode, that provides raw data from the said internal sensors, and a couple of "fusion" modes (i.e. the IMU also do calculations in order to provide euler angles, quaternions, linear acceleration and gravity measurements). In fusion modes the AMG data is still available (with some calibration refinements done by the IMU), but certain settings such as low pass filters cut-off frequency and sensors ranges are fixed, while in AMG mode they can be customized; this is why AMG mode can still be interesting. Signed-off-by: Andrea Merello <andrea.merello@iit.it> --- drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/bno055/Kconfig | 4 + drivers/iio/imu/bno055/Makefile | 3 + drivers/iio/imu/bno055/bno055.c | 1480 +++++++++++++++++++++++++++++++ drivers/iio/imu/bno055/bno055.h | 12 + 6 files changed, 1501 insertions(+) create mode 100644 drivers/iio/imu/bno055/Kconfig create mode 100644 drivers/iio/imu/bno055/Makefile create mode 100644 drivers/iio/imu/bno055/bno055.c create mode 100644 drivers/iio/imu/bno055/bno055.h diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 001ca2c3ff95..f1d7d4b5e222 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -52,6 +52,7 @@ config ADIS16480 ADIS16485, ADIS16488 inertial sensors. source "drivers/iio/imu/bmi160/Kconfig" +source "drivers/iio/imu/bno055/Kconfig" config FXOS8700 tristate diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index c82748096c77..6eb612034722 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -15,6 +15,7 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o obj-y += bmi160/ +obj-y += bno055/ obj-$(CONFIG_FXOS8700) += fxos8700_core.o obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig new file mode 100644 index 000000000000..d197310661af --- /dev/null +++ b/drivers/iio/imu/bno055/Kconfig @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +config BOSH_BNO055_IIO + tristate diff --git a/drivers/iio/imu/bno055/Makefile b/drivers/iio/imu/bno055/Makefile new file mode 100644 index 000000000000..c55741d0e96f --- /dev/null +++ b/drivers/iio/imu/bno055/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_BOSH_BNO055_IIO) += bno055.o diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c new file mode 100644 index 000000000000..c85cb985f0f1 --- /dev/null +++ b/drivers/iio/imu/bno055/bno055.c @@ -0,0 +1,1480 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IIO driver for Bosh BNO055 IMU + * + * Copyright (C) 2021 Istituto Italiano di Tecnologia + * Electronic Design Laboratory + * Written by Andrea Merello <andrea.merello@iit.it> + * + * Portions of this driver are taken from the BNO055 driver patch + * from Vlad Dogaru which is Copyright (c) 2016, Intel Corporation. + * + * This driver is also based on BMI160 driver, which is: + * Copyright (c) 2016, Intel Corporation. + * Copyright (c) 2019, Martin Kelly. + */ + +#include <linux/bitmap.h> +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/device.h> +#include <linux/firmware.h> +#include <linux/gpio/consumer.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/util_macros.h> + +#include <linux/iio/iio.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/buffer.h> +#include <linux/iio/sysfs.h> + +#include "bno055.h" + +#define BNO055_FW_NAME "bno055-caldata" +#define BNO055_FW_EXT ".dat" +#define BNO055_FW_UID_NAME BNO055_FW_NAME "-%*phN" BNO055_FW_EXT +#define BNO055_FW_GENERIC_NAME (BNO055_FW_NAME BNO055_FW_EXT) + +/* common registers */ +#define BNO055_PAGESEL_REG 0x7 + +/* page 0 registers */ +#define BNO055_CHIP_ID_REG 0x0 +#define BNO055_CHIP_ID_MAGIC 0xA0 +#define BNO055_SW_REV_LSB_REG 0x4 +#define BNO055_SW_REV_MSB_REG 0x5 +#define BNO055_ACC_DATA_X_LSB_REG 0x8 +#define BNO055_ACC_DATA_Y_LSB_REG 0xA +#define BNO055_ACC_DATA_Z_LSB_REG 0xC +#define BNO055_MAG_DATA_X_LSB_REG 0xE +#define BNO055_MAG_DATA_Y_LSB_REG 0x10 +#define BNO055_MAG_DATA_Z_LSB_REG 0x12 +#define BNO055_GYR_DATA_X_LSB_REG 0x14 +#define BNO055_GYR_DATA_Y_LSB_REG 0x16 +#define BNO055_GYR_DATA_Z_LSB_REG 0x18 +#define BNO055_EUL_DATA_X_LSB_REG 0x1A +#define BNO055_EUL_DATA_Y_LSB_REG 0x1C +#define BNO055_EUL_DATA_Z_LSB_REG 0x1E +#define BNO055_QUAT_DATA_W_LSB_REG 0x20 +#define BNO055_LIA_DATA_X_LSB_REG 0x28 +#define BNO055_LIA_DATA_Y_LSB_REG 0x2A +#define BNO055_LIA_DATA_Z_LSB_REG 0x2C +#define BNO055_GRAVITY_DATA_X_LSB_REG 0x2E +#define BNO055_GRAVITY_DATA_Y_LSB_REG 0x30 +#define BNO055_GRAVITY_DATA_Z_LSB_REG 0x32 +#define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2) +#define BNO055_TEMP_REG 0x34 +#define BNO055_CALIB_STAT_REG 0x35 +#define BNO055_CALIB_STAT_MASK GENMASK(1, 0) +#define BNO055_CALIB_STAT_MAGN_SHIFT 0 +#define BNO055_CALIB_STAT_ACCEL_SHIFT 2 +#define BNO055_CALIB_STAT_GYRO_SHIFT 4 +#define BNO055_CALIB_STAT_SYS_SHIFT 6 +#define BNO055_SYS_ERR_REG 0x3A +#define BNO055_SYS_TRIGGER_REG 0x3F +#define BNO055_SYS_TRIGGER_RST_INT BIT(6) +#define BNO055_SYS_TRIGGER_CLK_SEL BIT(7) +#define BNO055_OPR_MODE_REG 0x3D +#define BNO055_OPR_MODE_CONFIG 0x0 +#define BNO055_OPR_MODE_AMG 0x7 +#define BNO055_OPR_MODE_FUSION_FMC_OFF 0xB +#define BNO055_OPR_MODE_FUSION 0xC +#define BNO055_UNIT_SEL_REG 0x3B +/* Android orientation mode means: pitch value decreases turning clockwise */ +#define BNO055_UNIT_SEL_ANDROID BIT(7) +#define BNO055_CALDATA_START 0x55 +#define BNO055_CALDATA_END 0x6A +#define BNO055_CALDATA_LEN 22 + +/* + * The difference in address between the register that contains the + * value and the register that contains the offset. This applies for + * accel, gyro and magn channels. + */ +#define BNO055_REG_OFFSET_ADDR 0x4D + +/* page 1 registers */ +#define PG1(x) ((x) | 0x80) +#define BNO055_ACC_CONFIG_REG PG1(0x8) +#define BNO055_ACC_CONFIG_LPF_MASK GENMASK(4, 2) +#define BNO055_ACC_CONFIG_RANGE_MASK GENMASK(1, 0) +#define BNO055_MAG_CONFIG_REG PG1(0x9) +#define BNO055_MAG_CONFIG_HIGHACCURACY 0x18 +#define BNO055_MAG_CONFIG_ODR_MASK GENMASK(2, 0) +#define BNO055_GYR_CONFIG_REG PG1(0xA) +#define BNO055_GYR_CONFIG_RANGE_MASK GENMASK(2, 0) +#define BNO055_GYR_CONFIG_LPF_MASK GENMASK(5, 3) +#define BNO055_GYR_AM_SET_REG PG1(0x1F) +#define BNO055_UID_LOWER_REG PG1(0x50) +#define BNO055_UID_HIGHER_REG PG1(0x5F) +#define BNO055_UID_LEN 16 + +static const int bno055_mag_odr_vals[] = {2, 6, 8, 10, 15, 20, 25, 30}; +/* the following one is INT_PLUS_MICRO */ +static const int bno055_acc_lpf_vals[] = {7, 810000, 15, 630000, + 31, 250000, 62, 500000, 125, 0, + 250, 0, 500, 0, 1000, 0}; +static const int bno055_acc_ranges[] = {2, 4, 8, 16}; +static const int bno055_gyr_lpf_vals[] = {523, 230, 116, 47, 23, 12, 64, 32}; +static const int bno055_gyr_ranges[] = {2000, 1000, 500, 250, 125}; + +struct bno055_priv { + struct regmap *regmap; + struct device *dev; + struct clk *clk; + int operation_mode; + int xfer_burst_break_thr; + struct mutex lock; + u8 uid[BNO055_UID_LEN]; + struct { + __le16 chans[BNO055_SCAN_CH_COUNT]; + s64 timestamp __aligned(8); + } buf; +}; + +static bool bno055_regmap_volatile(struct device *dev, unsigned int reg) +{ + /* data and status registers */ + if (reg >= BNO055_ACC_DATA_X_LSB_REG && reg <= BNO055_SYS_ERR_REG) + return true; + + /* when in fusion mode, config is updated by chip */ + if (reg == BNO055_MAG_CONFIG_REG || + reg == BNO055_ACC_CONFIG_REG || + reg == BNO055_GYR_CONFIG_REG) + return true; + + /* calibration data may be updated by the IMU */ + if (reg >= BNO055_CALDATA_START && reg <= BNO055_CALDATA_END) + return true; + return false; +} + +static bool bno055_regmap_readable(struct device *dev, unsigned int reg) +{ + /* unnamed PG0 reserved areas */ + if ((reg < PG1(0) && reg > BNO055_CALDATA_END) || + reg == 0x3C) + return false; + + /* unnamed PG1 reserved areas */ + if (reg > PG1(BNO055_UID_HIGHER_REG) || + (reg < PG1(BNO055_UID_LOWER_REG) && reg > PG1(BNO055_GYR_AM_SET_REG)) || + reg == PG1(0xE) || + (reg < PG1(BNO055_PAGESEL_REG) && reg >= PG1(0x0))) + return false; + return true; +} + +static bool bno055_regmap_writeable(struct device *dev, unsigned int reg) +{ + /* + * Unreadable registers are indeed reserved; there are no WO regs + * (except for a single bit in SYS_TRIGGER register) + */ + if (!bno055_regmap_readable(dev, reg)) + return false; + + /* data and status registers */ + if (reg >= BNO055_ACC_DATA_X_LSB_REG && reg <= BNO055_SYS_ERR_REG) + return false; + + /* IDs areas */ + if (reg < BNO055_PAGESEL_REG || + (reg <= BNO055_UID_HIGHER_REG && reg >= BNO055_UID_LOWER_REG)) + return false; + + return true; +} + +static const struct regmap_range_cfg bno055_regmap_ranges[] = { + { + .range_min = 0, + .range_max = 0x7f * 2, + .selector_reg = BNO055_PAGESEL_REG, + .selector_mask = GENMASK(7, 0), + .selector_shift = 0, + .window_start = 0, + .window_len = 0x80 + }, +}; + +const struct regmap_config bno055_regmap_config = { + .name = "bno055", + .reg_bits = 8, + .val_bits = 8, + .ranges = bno055_regmap_ranges, + .num_ranges = 1, + .volatile_reg = bno055_regmap_volatile, + .max_register = 0x80 * 2, + .writeable_reg = bno055_regmap_writeable, + .readable_reg = bno055_regmap_readable, + .cache_type = REGCACHE_RBTREE, +}; +EXPORT_SYMBOL_GPL(bno055_regmap_config); + +static int bno055_reg_update_bits(struct bno055_priv *priv, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int ret; + + ret = regmap_update_bits(priv->regmap, reg, mask, val); + if (ret && ret != -ERESTARTSYS) { + dev_err(priv->dev, "Regmap update_bits error. adr: 0x%x, ret: %d", + reg, ret); + } + + return ret; +} + +/* must be called in configuration mode */ +int bno055_calibration_load(struct bno055_priv *priv, const struct firmware *fw) +{ + if (fw->size != BNO055_CALDATA_LEN) { + dev_dbg(priv->dev, "Invalid calibration file size %d (expected %d)", + fw->size, BNO055_CALDATA_LEN); + return -EINVAL; + } + + dev_dbg(priv->dev, "loading cal data: %*ph", BNO055_CALDATA_LEN, fw->data); + return regmap_bulk_write(priv->regmap, BNO055_CALDATA_START, + fw->data, BNO055_CALDATA_LEN); +} + +static int bno055_init(struct bno055_priv *priv, const struct firmware *caldata) +{ + int ret; + + ret = regmap_write(priv->regmap, BNO055_SYS_TRIGGER_REG, + (priv->clk ? BNO055_SYS_TRIGGER_CLK_SEL : 0) | + BNO055_SYS_TRIGGER_RST_INT); + if (ret) + return ret; + + msleep(100); + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, + BNO055_OPR_MODE_CONFIG); + if (ret) + return ret; + + /* use standard SI units */ + ret = regmap_write(priv->regmap, BNO055_UNIT_SEL_REG, + BNO055_UNIT_SEL_ANDROID); + if (ret) + return ret; + + if (caldata) { + ret = bno055_calibration_load(priv, caldata); + if (ret) + dev_warn(priv->dev, "failed to load calibration data with error %d", + ret); + } + + priv->operation_mode = BNO055_OPR_MODE_FUSION; + return regmap_write(priv->regmap, BNO055_OPR_MODE_REG, + priv->operation_mode); +} + +static void bno055_uninit(void *arg) +{ + struct bno055_priv *priv = arg; + + /* stop the IMU */ + regmap_write(priv->regmap, BNO055_OPR_MODE_REG, BNO055_OPR_MODE_CONFIG); +} + +static void bno055_clk_disable(void *arg) +{ + struct bno055_priv *priv = arg; + + clk_disable_unprepare(priv->clk); +} + +#define BNO055_CHANNEL(_type, _axis, _index, _address, _sep, _sh, _avail) { \ + .address = _address, \ + .type = _type, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | (_sep), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | (_sh), \ + .info_mask_shared_by_type_available = _avail, \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + .repeat = IIO_MOD_##_axis == IIO_MOD_QUATERNION ? 4 : 0 \ + }, \ +} + +/* scan indexes follow DATA register order */ +enum bmi160_scan_axis { + BNO055_SCAN_ACCEL_X, + BNO055_SCAN_ACCEL_Y, + BNO055_SCAN_ACCEL_Z, + BNO055_SCAN_MAGN_X, + BNO055_SCAN_MAGN_Y, + BNO055_SCAN_MAGN_Z, + BNO055_SCAN_GYRO_X, + BNO055_SCAN_GYRO_Y, + BNO055_SCAN_GYRO_Z, + BNO055_SCAN_YAW, + BNO055_SCAN_ROLL, + BNO055_SCAN_PITCH, + BNO055_SCAN_QUATERNION, + BNO055_SCAN_LIA_X, + BNO055_SCAN_LIA_Y, + BNO055_SCAN_LIA_Z, + BNO055_SCAN_GRAVITY_X, + BNO055_SCAN_GRAVITY_Y, + BNO055_SCAN_GRAVITY_Z, + BNO055_SCAN_TIMESTAMP, +}; + +static const struct iio_chan_spec bno055_channels[] = { + /* accelerometer */ + BNO055_CHANNEL(IIO_ACCEL, X, BNO055_SCAN_ACCEL_X, + BNO055_ACC_DATA_X_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)), + BNO055_CHANNEL(IIO_ACCEL, Y, BNO055_SCAN_ACCEL_Y, + BNO055_ACC_DATA_Y_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)), + BNO055_CHANNEL(IIO_ACCEL, Z, BNO055_SCAN_ACCEL_Z, + BNO055_ACC_DATA_Z_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)), + /* gyroscope */ + BNO055_CHANNEL(IIO_ANGL_VEL, X, BNO055_SCAN_GYRO_X, + BNO055_GYR_DATA_X_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)), + BNO055_CHANNEL(IIO_ANGL_VEL, Y, BNO055_SCAN_GYRO_Y, + BNO055_GYR_DATA_Y_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)), + BNO055_CHANNEL(IIO_ANGL_VEL, Z, BNO055_SCAN_GYRO_Z, + BNO055_GYR_DATA_Z_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)), + /* magnetometer */ + BNO055_CHANNEL(IIO_MAGN, X, BNO055_SCAN_MAGN_X, + BNO055_MAG_DATA_X_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), + BIT(IIO_CHAN_INFO_SAMP_FREQ), BIT(IIO_CHAN_INFO_SAMP_FREQ)), + BNO055_CHANNEL(IIO_MAGN, Y, BNO055_SCAN_MAGN_Y, + BNO055_MAG_DATA_Y_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), + BIT(IIO_CHAN_INFO_SAMP_FREQ), BIT(IIO_CHAN_INFO_SAMP_FREQ)), + BNO055_CHANNEL(IIO_MAGN, Z, BNO055_SCAN_MAGN_Z, + BNO055_MAG_DATA_Z_LSB_REG, BIT(IIO_CHAN_INFO_OFFSET), + BIT(IIO_CHAN_INFO_SAMP_FREQ), BIT(IIO_CHAN_INFO_SAMP_FREQ)), + /* euler angle */ + BNO055_CHANNEL(IIO_ROT, YAW, BNO055_SCAN_YAW, + BNO055_EUL_DATA_X_LSB_REG, 0, 0, 0), + BNO055_CHANNEL(IIO_ROT, ROLL, BNO055_SCAN_ROLL, + BNO055_EUL_DATA_Y_LSB_REG, 0, 0, 0), + BNO055_CHANNEL(IIO_ROT, PITCH, BNO055_SCAN_PITCH, + BNO055_EUL_DATA_Z_LSB_REG, 0, 0, 0), + /* quaternion */ + BNO055_CHANNEL(IIO_ROT, QUATERNION, BNO055_SCAN_QUATERNION, + BNO055_QUAT_DATA_W_LSB_REG, 0, 0, 0), + + /* linear acceleration */ + BNO055_CHANNEL(IIO_ACCEL, ACCEL_LINEAR_X, BNO055_SCAN_LIA_X, + BNO055_LIA_DATA_X_LSB_REG, 0, 0, 0), + BNO055_CHANNEL(IIO_ACCEL, ACCEL_LINEAR_Y, BNO055_SCAN_LIA_Y, + BNO055_LIA_DATA_Y_LSB_REG, 0, 0, 0), + BNO055_CHANNEL(IIO_ACCEL, ACCEL_LINEAR_Z, BNO055_SCAN_LIA_Z, + BNO055_LIA_DATA_Z_LSB_REG, 0, 0, 0), + + /* gravity vector */ + BNO055_CHANNEL(IIO_GRAVITY, X, BNO055_SCAN_GRAVITY_X, + BNO055_GRAVITY_DATA_X_LSB_REG, 0, 0, 0), + BNO055_CHANNEL(IIO_GRAVITY, Y, BNO055_SCAN_GRAVITY_Y, + BNO055_GRAVITY_DATA_Y_LSB_REG, 0, 0, 0), + BNO055_CHANNEL(IIO_GRAVITY, Z, BNO055_SCAN_GRAVITY_Z, + BNO055_GRAVITY_DATA_Z_LSB_REG, 0, 0, 0), + + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .scan_index = -1 + }, + IIO_CHAN_SOFT_TIMESTAMP(BNO055_SCAN_TIMESTAMP), +}; + +static int bno055_get_acc_lpf(struct bno055_priv *priv, int *val, int *val2) +{ + const int shift = __ffs(BNO055_ACC_CONFIG_LPF_MASK); + int hwval, idx; + int ret; + + ret = regmap_read(priv->regmap, BNO055_ACC_CONFIG_REG, &hwval); + if (ret) + return ret; + + idx = (hwval & BNO055_ACC_CONFIG_LPF_MASK) >> shift; + *val = bno055_acc_lpf_vals[idx * 2]; + *val2 = bno055_acc_lpf_vals[idx * 2 + 1]; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int bno055_set_acc_lpf(struct bno055_priv *priv, int val, int val2) +{ + const int shift = __ffs(BNO055_ACC_CONFIG_LPF_MASK); + int req_val = val * 1000 + val2 / 1000; + bool first = true; + int best_delta; + int best_idx; + int tbl_val; + int delta; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(bno055_acc_lpf_vals) / 2; i++) { + tbl_val = bno055_acc_lpf_vals[i * 2] * 1000 + + bno055_acc_lpf_vals[i * 2 + 1] / 1000; + delta = abs(tbl_val - req_val); + if (first || delta < best_delta) { + best_delta = delta; + best_idx = i; + first = false; + } + } + + /* + * The closest value the HW supports is only one in fusion mode, + * and it is autoselected, so don't do anything, just return OK, + * as the closest possible value has been (virtually) selected + */ + if (priv->operation_mode != BNO055_OPR_MODE_AMG) + return 0; + + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, + BNO055_OPR_MODE_CONFIG); + if (ret) + return ret; + + ret = bno055_reg_update_bits(priv, BNO055_ACC_CONFIG_REG, + BNO055_ACC_CONFIG_LPF_MASK, + best_idx << shift); + + if (ret) + return ret; + + return regmap_write(priv->regmap, BNO055_OPR_MODE_REG, + BNO055_OPR_MODE_AMG); +} + +static int bno055_get_regmask(struct bno055_priv *priv, int *val, int reg, + int mask, const int tbl[]) +{ + const int shift = __ffs(mask); + int hwval, idx; + int ret; + + ret = regmap_read(priv->regmap, reg, &hwval); + if (ret) + return ret; + + idx = (hwval & mask) >> shift; + *val = tbl[idx]; + + return IIO_VAL_INT; +} + +static int bno055_set_regmask(struct bno055_priv *priv, int val, int reg, + int mask, const int table[], int table_len) + +{ + int hwval = find_closest_unsorted(val, table, table_len); + const int shift = __ffs(mask); + int ret; + /* + * The closest value the HW supports is only one in fusion mode, + * and it is autoselected, so don't do anything, just return OK, + * as the closest possible value has been (virtually) selected + */ + if (priv->operation_mode != BNO055_OPR_MODE_AMG) + return 0; + + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, + BNO055_OPR_MODE_CONFIG); + if (ret) + return ret; + + ret = bno055_reg_update_bits(priv, reg, mask, hwval << shift); + + if (ret) + return ret; + + return regmap_write(priv->regmap, BNO055_OPR_MODE_REG, + BNO055_OPR_MODE_AMG); +} + +#define bno055_get_mag_odr(p, v) \ + bno055_get_regmask(p, v, \ + BNO055_MAG_CONFIG_REG, BNO055_MAG_CONFIG_ODR_MASK, \ + bno055_mag_odr_vals) + +#define bno055_set_mag_odr(p, v) \ + bno055_set_regmask(p, v, \ + BNO055_MAG_CONFIG_REG, BNO055_MAG_CONFIG_ODR_MASK, \ + bno055_mag_odr_vals, \ + ARRAY_SIZE(bno055_mag_odr_vals)) + +#define bno055_get_acc_range(p, v) \ + bno055_get_regmask(priv, v, \ + BNO055_ACC_CONFIG_REG, BNO055_ACC_CONFIG_RANGE_MASK, \ + bno055_acc_ranges) + +#define bno055_set_acc_range(p, v) \ + bno055_set_regmask(p, v, \ + BNO055_ACC_CONFIG_REG, \ + BNO055_ACC_CONFIG_RANGE_MASK, \ + bno055_acc_ranges, ARRAY_SIZE(bno055_acc_ranges)) + +#define bno055_get_gyr_lpf(p, v) \ + bno055_get_regmask(p, v, \ + BNO055_GYR_CONFIG_REG, BNO055_GYR_CONFIG_LPF_MASK, \ + bno055_gyr_lpf_vals) + +#define bno055_set_gyr_lpf(p, v) \ + bno055_set_regmask(p, v, \ + BNO055_GYR_CONFIG_REG, BNO055_GYR_CONFIG_LPF_MASK, \ + bno055_gyr_lpf_vals, \ + ARRAY_SIZE(bno055_gyr_lpf_vals)) + +#define bno055_get_gyr_range(p, v) \ + bno055_get_regmask(p, v, \ + BNO055_GYR_CONFIG_REG, BNO055_GYR_CONFIG_RANGE_MASK, \ + bno055_gyr_ranges) + +#define bno055_set_gyr_range(p, v) \ + bno055_set_regmask(p, v, \ + BNO055_GYR_CONFIG_REG, \ + BNO055_GYR_CONFIG_RANGE_MASK, \ + bno055_gyr_ranges, ARRAY_SIZE(bno055_gyr_ranges)) + +static int bno055_read_simple_chan(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bno055_priv *priv = iio_priv(indio_dev); + __le16 raw_val; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = regmap_bulk_read(priv->regmap, chan->address, + &raw_val, sizeof(raw_val)); + if (ret < 0) + return ret; + *val = (s16)le16_to_cpu(raw_val); + return IIO_VAL_INT; + case IIO_CHAN_INFO_OFFSET: + if (priv->operation_mode != BNO055_OPR_MODE_AMG) { + *val = 0; + } else { + ret = regmap_bulk_read(priv->regmap, + chan->address + + BNO055_REG_OFFSET_ADDR, + &raw_val, sizeof(raw_val)); + if (ret < 0) + return ret; + /* + * IMU reports sensor offests; IIO wants correction + * offset, thus we need the 'minus' here. + */ + *val = -(s16)le16_to_cpu(raw_val); + } + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 1; + switch (chan->type) { + case IIO_GRAVITY: + /* Table 3-35: 1 m/s^2 = 100 LSB */ + case IIO_ACCEL: + /* Table 3-17: 1 m/s^2 = 100 LSB */ + *val2 = 100; + break; + case IIO_MAGN: + /* + * Table 3-19: 1 uT = 16 LSB. But we need + * Gauss: 1G = 0.1 uT. + */ + *val2 = 160; + break; + case IIO_ANGL_VEL: + /* Table 3-22: 1 Rps = 900 LSB */ + *val2 = 900; + break; + case IIO_ROT: + /* Table 3-28: 1 degree = 16 LSB */ + *val2 = 16; + break; + default: + return -EINVAL; + } + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + + case IIO_CHAN_INFO_SAMP_FREQ: + if (chan->type != IIO_MAGN) + return -EINVAL; + else + return bno055_get_mag_odr(priv, val); + + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + switch (chan->type) { + case IIO_ANGL_VEL: + return bno055_get_gyr_lpf(priv, val); + case IIO_ACCEL: + return bno055_get_acc_lpf(priv, val, val2); + default: + return -EINVAL; + } + } +} + +static int bno055_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + struct bno055_priv *priv = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + switch (chan->type) { + case IIO_ANGL_VEL: + if (priv->operation_mode != BNO055_OPR_MODE_AMG) { + /* locked on 32 */ + *vals = bno055_gyr_lpf_vals + 7; + *length = 1; + } else { + *vals = bno055_gyr_lpf_vals; + *length = ARRAY_SIZE(bno055_gyr_lpf_vals); + } + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + case IIO_ACCEL: + if (priv->operation_mode != BNO055_OPR_MODE_AMG) { + /* locked on 62.5Hz */ + *vals = bno055_acc_lpf_vals + 6; + *length = 2; + } else { + *vals = bno055_acc_lpf_vals; + *length = ARRAY_SIZE(bno055_acc_lpf_vals); + } + *type = IIO_VAL_INT_PLUS_MICRO; + return IIO_AVAIL_LIST; + } + break; + case IIO_CHAN_INFO_SAMP_FREQ: + switch (chan->type) { + case IIO_MAGN: + if (priv->operation_mode != BNO055_OPR_MODE_AMG) { + /* locked on 20Hz */ + *vals = bno055_mag_odr_vals + 5; + *length = 1; + } else { + *vals = bno055_mag_odr_vals; + *length = ARRAY_SIZE(bno055_mag_odr_vals); + } + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int bno055_read_temp_chan(struct iio_dev *indio_dev, int *val) +{ + struct bno055_priv *priv = iio_priv(indio_dev); + unsigned int raw_val; + int ret; + + ret = regmap_read(priv->regmap, BNO055_TEMP_REG, &raw_val); + if (ret < 0) + return ret; + + /* + * Tables 3-36 and 3-37: one byte of priv, signed, 1 LSB = 1C. + * ABI wants milliC. + */ + *val = raw_val * 1000; + + return IIO_VAL_INT; +} + +static int bno055_read_quaternion(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int size, int *vals, int *val_len, + long mask) +{ + struct bno055_priv *priv = iio_priv(indio_dev); + __le16 raw_vals[4]; + int i, ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (size < 4) + return -EINVAL; + ret = regmap_bulk_read(priv->regmap, + BNO055_QUAT_DATA_W_LSB_REG, + raw_vals, sizeof(raw_vals)); + if (ret < 0) + return ret; + for (i = 0; i < 4; i++) + vals[i] = (s16)le16_to_cpu(raw_vals[i]); + *val_len = 4; + return IIO_VAL_INT_MULTIPLE; + case IIO_CHAN_INFO_SCALE: + /* Table 3-31: 1 quaternion = 2^14 LSB */ + if (size < 2) + return -EINVAL; + vals[0] = 1; + vals[1] = 1 << 14; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } +} + +static int _bno055_read_raw_multi(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int size, int *vals, int *val_len, + long mask) +{ + switch (chan->type) { + case IIO_MAGN: + case IIO_ACCEL: + case IIO_ANGL_VEL: + case IIO_GRAVITY: + if (size < 2) + return -EINVAL; + *val_len = 2; + return bno055_read_simple_chan(indio_dev, chan, + &vals[0], &vals[1], + mask); + case IIO_TEMP: + *val_len = 1; + return bno055_read_temp_chan(indio_dev, &vals[0]); + case IIO_ROT: + /* + * Rotation is exposed as either a quaternion or three + * Euler angles. + */ + if (chan->channel2 == IIO_MOD_QUATERNION) + return bno055_read_quaternion(indio_dev, chan, + size, vals, + val_len, mask); + if (size < 2) + return -EINVAL; + *val_len = 2; + return bno055_read_simple_chan(indio_dev, chan, + &vals[0], &vals[1], + mask); + default: + return -EINVAL; + } +} + +static int bno055_read_raw_multi(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int size, int *vals, int *val_len, + long mask) +{ + struct bno055_priv *priv = iio_priv(indio_dev); + int ret; + + mutex_lock(&priv->lock); + ret = _bno055_read_raw_multi(indio_dev, chan, size, + vals, val_len, mask); + mutex_unlock(&priv->lock); + return ret; +} + +static int _bno055_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bno055_priv *priv = iio_priv(iio_dev); + + switch (chan->type) { + case IIO_MAGN: + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return bno055_set_mag_odr(priv, val); + + default: + return -EINVAL; + } + case IIO_ACCEL: + switch (mask) { + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + return bno055_set_acc_lpf(priv, val, val2); + + default: + return -EINVAL; + } + case IIO_ANGL_VEL: + switch (mask) { + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + return bno055_set_gyr_lpf(priv, val); + + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +static int bno055_write_raw(struct iio_dev *iio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bno055_priv *priv = iio_priv(iio_dev); + int ret; + + mutex_lock(&priv->lock); + ret = _bno055_write_raw(iio_dev, chan, val, val2, mask); + mutex_unlock(&priv->lock); + + return ret; +} + +static ssize_t in_accel_range_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + + return sysfs_emit(buf, "%s\n", + priv->operation_mode != BNO055_OPR_MODE_AMG ? "4" : + "2 4 8 16"); +} + +static ssize_t in_anglvel_range_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + + return sysfs_emit(buf, "%s\n", + (priv->operation_mode != BNO055_OPR_MODE_AMG) ? "2000" : + "125 250 500 1000 2000"); +} + +static ssize_t bno055_operation_mode_set(struct bno055_priv *priv, + int operation_mode) +{ + int ret; + + mutex_lock(&priv->lock); + priv->operation_mode = operation_mode; + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, + BNO055_OPR_MODE_CONFIG); + if (ret) { + mutex_unlock(&priv->lock); + return ret; + } + + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, priv->operation_mode); + mutex_unlock(&priv->lock); + + return ret; +} + +static ssize_t bno055_fusion_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + + return sysfs_emit(buf, "%d\n", + priv->operation_mode != BNO055_OPR_MODE_AMG); +} + +static ssize_t bno055_fusion_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + int ret = 0; + + if (sysfs_streq(buf, "0")) { + ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_AMG); + } else { + /* + * Coming from AMG means the FMC was off, just switch to fusion + * but don't change anything that doesn't belong to us (i.e let. + * FMC stay off. + * Coming from any other fusion mode means we don't need to do + * anything. + */ + if (priv->operation_mode == BNO055_OPR_MODE_AMG) + ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION_FMC_OFF); + } + + return len ?: len; +} + +static ssize_t bno055_fmc_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + + return sysfs_emit(buf, "%d\n", + priv->operation_mode == BNO055_OPR_MODE_FUSION); +} + +static ssize_t bno055_fmc_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + int ret = 0; + + if (sysfs_streq(buf, "0")) { + if (priv->operation_mode == BNO055_OPR_MODE_FUSION) + ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION_FMC_OFF); + } else { + if (priv->operation_mode == BNO055_OPR_MODE_AMG) + return -EINVAL; + } + + return len ?: ret; +} + +static ssize_t bno055_in_accel_range_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + int val; + int ret; + + ret = bno055_get_acc_range(priv, &val); + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%d\n", val); +} + +static ssize_t bno055_in_accel_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&priv->lock); + ret = bno055_set_acc_range(priv, val); + mutex_unlock(&priv->lock); + + return ret ?: len; +} + +static ssize_t bno055_in_gyr_range_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int val; + int ret; + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + + ret = bno055_get_gyr_range(priv, &val); + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%d\n", val); +} + +static ssize_t bno055_in_gyr_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + unsigned long val; + int ret; + + ret = kstrtoul(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&priv->lock); + ret = bno055_set_gyr_range(priv, val); + mutex_unlock(&priv->lock); + + return ret ?: len; +} + +static ssize_t bno055_get_calib_status(struct device *dev, char *buf, int which) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + static const char * const calib_status[] = { + "bad", "barely enough", "fair", "good" }; + const char *calib_str; + int ret; + int val; + + if (priv->operation_mode == BNO055_OPR_MODE_AMG || + (priv->operation_mode == BNO055_OPR_MODE_FUSION_FMC_OFF && + which == BNO055_CALIB_STAT_MAGN_SHIFT)) { + calib_str = "idle"; + } else { + mutex_lock(&priv->lock); + ret = regmap_read(priv->regmap, BNO055_CALIB_STAT_REG, &val); + mutex_unlock(&priv->lock); + + if (ret) + return -EIO; + + val = (val >> which) & BNO055_CALIB_STAT_MASK; + calib_str = calib_status[val]; + } + + return sysfs_emit(buf, "%s\n", calib_str); +} + +static ssize_t unique_id_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + + return sysfs_emit(buf, "%*ph\n", BNO055_UID_LEN, priv->uid); +} + +static ssize_t in_calibration_data_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); + u8 data[BNO055_CALDATA_LEN]; + int ret; + + mutex_lock(&priv->lock); + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, + BNO055_OPR_MODE_CONFIG); + if (ret) + goto unlock; + + ret = regmap_bulk_read(priv->regmap, BNO055_CALDATA_START, data, + BNO055_CALDATA_LEN); + if (ret) + goto unlock; + + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, priv->operation_mode); + mutex_unlock(&priv->lock); + if (ret) + return ret; + + memcpy(buf, data, BNO055_CALDATA_LEN); + + return BNO055_CALDATA_LEN; +unlock: + mutex_unlock(&priv->lock); + return ret; +} + +static ssize_t in_autocalibration_status_sys_show(struct device *dev, + struct device_attribute *a, + char *buf) +{ + return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_SYS_SHIFT); +} + +static ssize_t in_autocalibration_status_accel_show(struct device *dev, + struct device_attribute *a, + char *buf) +{ + return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_ACCEL_SHIFT); +} + +static ssize_t in_autocalibration_status_gyro_show(struct device *dev, + struct device_attribute *a, + char *buf) +{ + return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_GYRO_SHIFT); +} + +static ssize_t in_autocalibration_status_magn_show(struct device *dev, + struct device_attribute *a, + char *buf) +{ + return bno055_get_calib_status(dev, buf, BNO055_CALIB_STAT_MAGN_SHIFT); +} + +#ifdef CONFIG_DEBUG_FS +int bno055_debugfs_reg_access(struct iio_dev *iio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct bno055_priv *priv = iio_priv(iio_dev); + + if (readval) + return regmap_read(priv->regmap, reg, readval); + else + return regmap_write(priv->regmap, reg, writeval); +} + +static ssize_t bno055_show_fw_version(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct bno055_priv *priv = file->private_data; + int rev, ver; + char *buf; + int ret; + + ret = regmap_read(priv->regmap, BNO055_SW_REV_LSB_REG, &rev); + if (ret) + return ret; + + ret = regmap_read(priv->regmap, BNO055_SW_REV_MSB_REG, &ver); + if (ret) + return ret; + + buf = devm_kasprintf(priv->dev, GFP_KERNEL, "ver: 0x%x, rev: 0x%x\n", + ver, rev); + if (!buf) + return -ENOMEM; + + ret = simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); + devm_kfree(priv->dev, buf); + + return ret; +} + +static const struct file_operations bno055_fw_version_ops = { + .open = simple_open, + .read = bno055_show_fw_version, + .llseek = default_llseek, + .owner = THIS_MODULE, +}; + +static void bno055_debugfs_init(struct iio_dev *iio_dev) +{ + struct bno055_priv *priv = iio_priv(iio_dev); + + debugfs_create_file("firmware_version", 0400, + iio_get_debugfs_dentry(iio_dev), priv, + &bno055_fw_version_ops); +} +#else +static void bno055_debugfs_init(struct iio_dev *iio_dev) +{ +} + +int bno055_debugfs_reg_access(struct iio_dev *iio_dev, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + return 0; +} +#endif + +static IIO_DEVICE_ATTR(fusion_enable, 0644, + bno055_fusion_enable_show, + bno055_fusion_enable_store, 0); + +static IIO_DEVICE_ATTR(fast_magnetometer_calibration_enable, 0644, + bno055_fmc_enable_show, + bno055_fmc_enable_store, 0); + +static IIO_DEVICE_ATTR(in_accel_range, 0644, + bno055_in_accel_range_show, + bno055_in_accel_range_store, 0); + +static IIO_DEVICE_ATTR_RO(in_accel_range_available, 0); + +static IIO_DEVICE_ATTR(in_anglvel_range, 0644, + bno055_in_gyr_range_show, + bno055_in_gyr_range_store, 0); + +static IIO_DEVICE_ATTR_RO(in_anglvel_range_available, 0); + +static IIO_DEVICE_ATTR_RO(in_autocalibration_status_sys, 0); +static IIO_DEVICE_ATTR_RO(in_autocalibration_status_accel, 0); +static IIO_DEVICE_ATTR_RO(in_autocalibration_status_gyro, 0); +static IIO_DEVICE_ATTR_RO(in_autocalibration_status_magn, 0); +static IIO_DEVICE_ATTR_RO(in_calibration_data, 0); + +static IIO_DEVICE_ATTR_RO(unique_id, 0); + +static struct attribute *bno055_attrs[] = { + &iio_dev_attr_in_accel_range_available.dev_attr.attr, + &iio_dev_attr_in_accel_range.dev_attr.attr, + &iio_dev_attr_in_anglvel_range_available.dev_attr.attr, + &iio_dev_attr_in_anglvel_range.dev_attr.attr, + &iio_dev_attr_fusion_enable.dev_attr.attr, + &iio_dev_attr_fast_magnetometer_calibration_enable.dev_attr.attr, + &iio_dev_attr_in_autocalibration_status_sys.dev_attr.attr, + &iio_dev_attr_in_autocalibration_status_accel.dev_attr.attr, + &iio_dev_attr_in_autocalibration_status_gyro.dev_attr.attr, + &iio_dev_attr_in_autocalibration_status_magn.dev_attr.attr, + &iio_dev_attr_in_calibration_data.dev_attr.attr, + &iio_dev_attr_unique_id.dev_attr.attr, + NULL +}; + +static const struct attribute_group bno055_attrs_group = { + .attrs = bno055_attrs, +}; + +static const struct iio_info bno055_info = { + .read_raw_multi = bno055_read_raw_multi, + .read_avail = bno055_read_avail, + .write_raw = bno055_write_raw, + .attrs = &bno055_attrs_group, + .debugfs_reg_access = bno055_debugfs_reg_access, +}; + +/* + * Reads len samples from the HW, stores them in buf starting from buf_idx, + * and applies mask to cull (skip) unneeded samples. + * Updates buf_idx incrementing with the number of stored samples. + * Samples from HW are transferred into buf, then in-place copy on buf is + * performed in order to cull samples that need to be skipped. + * This avoids copies of the first samples until we hit the 1st sample to skip, + * and also avoids having an extra bounce buffer. + * buf must be able to contain len elements in spite of how many samples we are + * going to cull. + */ +static int bno055_scan_xfer(struct bno055_priv *priv, + int start_ch, int len, unsigned long mask, + __le16 *buf, int *buf_idx) +{ + const int base = BNO055_ACC_DATA_X_LSB_REG; + bool quat_in_read = false; + int buf_base = *buf_idx; + __le16 *dst, *src; + int offs_fixup = 0; + int xfer_len = len; + int ret; + int i, n; + + /* + * All chans are made up 1 16-bit sample, except for quaternion that is + * made up 4 16-bit values. + * For us the quaternion CH is just like 4 regular CHs. + * If our read starts past the quaternion make sure to adjust the + * starting offset; if the quaternion is contained in our scan then make + * sure to adjust the read len. + */ + if (start_ch > BNO055_SCAN_QUATERNION) { + start_ch += 3; + } else if ((start_ch <= BNO055_SCAN_QUATERNION) && + ((start_ch + len) > BNO055_SCAN_QUATERNION)) { + quat_in_read = true; + xfer_len += 3; + } + + ret = regmap_bulk_read(priv->regmap, + base + start_ch * sizeof(__le16), + buf + buf_base, + xfer_len * sizeof(__le16)); + if (ret) + return ret; + + for_each_set_bit(i, &mask, len) { + if (quat_in_read && ((start_ch + i) > BNO055_SCAN_QUATERNION)) + offs_fixup = 3; + + dst = buf + *buf_idx; + src = buf + buf_base + offs_fixup + i; + + n = (start_ch + i == BNO055_SCAN_QUATERNION) ? 4 : 1; + + if (dst != src) + memcpy(dst, src, n * sizeof(__le16)); + + *buf_idx += n; + } + return 0; +} + +static irqreturn_t bno055_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *iio_dev = pf->indio_dev; + struct bno055_priv *priv = iio_priv(iio_dev); + int xfer_start, start, end, prev_end; + bool xfer_pending = false; + bool first = true; + unsigned long mask; + int buf_idx = 0; + bool thr_hit; + int quat; + int ret; + + mutex_lock(&priv->lock); + for_each_set_bitrange(start, end, iio_dev->active_scan_mask, + iio_dev->masklength) { + if (!xfer_pending) + xfer_start = start; + xfer_pending = true; + + if (!first) { + quat = ((start > BNO055_SCAN_QUATERNION) && + (prev_end <= BNO055_SCAN_QUATERNION)) ? 3 : 0; + thr_hit = (start - prev_end + quat) > + priv->xfer_burst_break_thr; + + if (thr_hit) { + mask = *iio_dev->active_scan_mask >> xfer_start; + ret = bno055_scan_xfer(priv, xfer_start, + prev_end - xfer_start + 1, + mask, priv->buf.chans, &buf_idx); + if (ret) + goto done; + xfer_pending = false; + } + first = false; + } + prev_end = end; + } + + if (xfer_pending) { + mask = *iio_dev->active_scan_mask >> xfer_start; + ret = bno055_scan_xfer(priv, xfer_start, + end - xfer_start + 1, + mask, priv->buf.chans, &buf_idx); + } + + iio_push_to_buffers_with_timestamp(iio_dev, &priv->buf, pf->timestamp); +done: + mutex_unlock(&priv->lock); + iio_trigger_notify_done(iio_dev->trig); + return IRQ_HANDLED; +} + +int bno055_probe(struct device *dev, struct regmap *regmap, + int xfer_burst_break_thr) +{ + const struct firmware *caldata; + struct bno055_priv *priv; + struct iio_dev *iio_dev; + struct gpio_desc *rst; + char *fw_name_buf; + unsigned int val; + int ret; + + iio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); + if (!iio_dev) + return -ENOMEM; + + iio_dev->name = "bno055"; + priv = iio_priv(iio_dev); + mutex_init(&priv->lock); + priv->regmap = regmap; + priv->dev = dev; + priv->xfer_burst_break_thr = xfer_burst_break_thr; + rst = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(rst)) + return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset GPIO"); + + priv->clk = devm_clk_get_optional(dev, "clk"); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get CLK"); + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, bno055_clk_disable, priv); + if (ret) + return ret; + + if (rst) { + usleep_range(5000, 10000); + gpiod_set_value_cansleep(rst, 0); + usleep_range(650000, 750000); + } + + ret = regmap_read(priv->regmap, BNO055_CHIP_ID_REG, &val); + if (ret) + return ret; + + if (val != BNO055_CHIP_ID_MAGIC) { + dev_err(dev, "Unrecognized chip ID 0x%x", val); + return -ENODEV; + } + + ret = regmap_bulk_read(priv->regmap, BNO055_UID_LOWER_REG, + priv->uid, BNO055_UID_LEN); + if (ret) + return ret; + + /* + * This has nothing to do with the IMU firmware, this is for sensor + * calibration data. + */ + fw_name_buf = devm_kasprintf(dev, GFP_KERNEL, + BNO055_FW_UID_NAME, + BNO055_UID_LEN, priv->uid); + if (!fw_name_buf) + return -ENOMEM; + + ret = request_firmware(&caldata, fw_name_buf, dev); + devm_kfree(dev, fw_name_buf); + if (ret) + ret = request_firmware(&caldata, BNO055_FW_GENERIC_NAME, dev); + + if (ret) { + dev_notice(dev, "Failed to load calibration data firmware file; this has nothing to do with IMU main firmware.\nYou can calibrate your IMU (look for 'in_autocalibration_status*' files in sysfs) and then copy 'in_calibration_data' to your firmware file"); + caldata = NULL; + } + + ret = bno055_init(priv, caldata); + if (caldata) + release_firmware(caldata); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, bno055_uninit, priv); + if (ret) + return ret; + + iio_dev->channels = bno055_channels; + iio_dev->num_channels = ARRAY_SIZE(bno055_channels); + iio_dev->info = &bno055_info; + iio_dev->modes = INDIO_DIRECT_MODE; + + ret = devm_iio_triggered_buffer_setup(dev, iio_dev, + iio_pollfunc_store_time, + bno055_trigger_handler, NULL); + if (ret) + return ret; + + ret = devm_iio_device_register(dev, iio_dev); + if (ret) + return ret; + + bno055_debugfs_init(iio_dev); + + return 0; +} +EXPORT_SYMBOL_GPL(bno055_probe); + +MODULE_AUTHOR("Andrea Merello <andrea.merello@iit.it>"); +MODULE_DESCRIPTION("Bosch BNO055 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/bno055/bno055.h b/drivers/iio/imu/bno055/bno055.h new file mode 100644 index 000000000000..7ad8da1ffbf0 --- /dev/null +++ b/drivers/iio/imu/bno055/bno055.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __BNO055_H__ +#define __BNO055_H__ + +#include <linux/regmap.h> + +struct device; +int bno055_probe(struct device *dev, struct regmap *regmap, + int xfer_burst_break_thr); +extern const struct regmap_config bno055_regmap_config; + +#endif -- 2.17.1 ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 07/10] iio: imu: add Bosch Sensortec BNO055 core driver 2021-10-28 10:18 ` [v2 07/10] iio: imu: add Bosch Sensortec BNO055 core driver Andrea Merello @ 2021-10-28 13:31 ` Jonathan Cameron 2021-11-09 11:52 ` Andrea Merello 0 siblings, 1 reply; 55+ messages in thread From: Jonathan Cameron @ 2021-10-28 13:31 UTC (permalink / raw) To: Andrea Merello Cc: mchehab+huawei, linux-iio, linux-kernel, devicetree, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello On Thu, 28 Oct 2021 12:18:37 +0200 Andrea Merello <andrea.merello@gmail.com> wrote: > This patch adds a core driver for the BNO055 IMU from Bosch. This IMU > can be connected via both serial and I2C busses; separate patches will > add support for them. > > The driver supports "AMG" (Accelerometer, Magnetometer, Gyroscope) mode, > that provides raw data from the said internal sensors, and a couple of > "fusion" modes (i.e. the IMU also do calculations in order to provide > euler angles, quaternions, linear acceleration and gravity measurements). > > In fusion modes the AMG data is still available (with some calibration > refinements done by the IMU), but certain settings such as low pass > filters cut-off frequency and sensors ranges are fixed, while in AMG mode > they can be customized; this is why AMG mode can still be interesting. > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > --- > drivers/iio/imu/Kconfig | 1 + > drivers/iio/imu/Makefile | 1 + > drivers/iio/imu/bno055/Kconfig | 4 + > drivers/iio/imu/bno055/Makefile | 3 + > drivers/iio/imu/bno055/bno055.c | 1480 +++++++++++++++++++++++++++++++ > drivers/iio/imu/bno055/bno055.h | 12 + > 6 files changed, 1501 insertions(+) > create mode 100644 drivers/iio/imu/bno055/Kconfig > create mode 100644 drivers/iio/imu/bno055/Makefile > create mode 100644 drivers/iio/imu/bno055/bno055.c > create mode 100644 drivers/iio/imu/bno055/bno055.h > ... > diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c > new file mode 100644 > index 000000000000..c85cb985f0f1 > --- /dev/null > +++ b/drivers/iio/imu/bno055/bno055.c > @@ -0,0 +1,1480 @@ ... > + > +static int bno055_reg_update_bits(struct bno055_priv *priv, unsigned int reg, > + unsigned int mask, unsigned int val) > +{ > + int ret; > + > + ret = regmap_update_bits(priv->regmap, reg, mask, val); > + if (ret && ret != -ERESTARTSYS) { > + dev_err(priv->dev, "Regmap update_bits error. adr: 0x%x, ret: %d", > + reg, ret); This feels like a wrapper that made sense when developing but probably doesn't want to still be here now things are 'working'. > + } > + > + return ret; > +} > + ... > + > +static void bno055_clk_disable(void *arg) Easy to make arg == priv->clk and turn this into a one line function. I'd expect these cleanup functions to be just above where probe() is defined rather than all the way up here. > +{ > + struct bno055_priv *priv = arg; > + > + clk_disable_unprepare(priv->clk); > +} > + ... > + > +static int bno055_get_acc_lpf(struct bno055_priv *priv, int *val, int *val2) > +{ > + const int shift = __ffs(BNO055_ACC_CONFIG_LPF_MASK); > + int hwval, idx; > + int ret; > + > + ret = regmap_read(priv->regmap, BNO055_ACC_CONFIG_REG, &hwval); > + if (ret) > + return ret; > + > + idx = (hwval & BNO055_ACC_CONFIG_LPF_MASK) >> shift; Use FIELD_GET() and FIELD_PREP where possible rather than reinventing them. > + *val = bno055_acc_lpf_vals[idx * 2]; > + *val2 = bno055_acc_lpf_vals[idx * 2 + 1]; > + > + return IIO_VAL_INT_PLUS_MICRO; > +} > + > +static int bno055_set_acc_lpf(struct bno055_priv *priv, int val, int val2) > +{ > + const int shift = __ffs(BNO055_ACC_CONFIG_LPF_MASK); > + int req_val = val * 1000 + val2 / 1000; > + bool first = true; > + int best_delta; > + int best_idx; > + int tbl_val; > + int delta; > + int ret; > + int i; > + > + for (i = 0; i < ARRAY_SIZE(bno055_acc_lpf_vals) / 2; i++) { > + tbl_val = bno055_acc_lpf_vals[i * 2] * 1000 + > + bno055_acc_lpf_vals[i * 2 + 1] / 1000; > + delta = abs(tbl_val - req_val); > + if (first || delta < best_delta) { > + best_delta = delta; > + best_idx = i; > + first = false; > + } > + } > + > + /* > + * The closest value the HW supports is only one in fusion mode, > + * and it is autoselected, so don't do anything, just return OK, > + * as the closest possible value has been (virtually) selected > + */ > + if (priv->operation_mode != BNO055_OPR_MODE_AMG) > + return 0; Can we do this before the big loop above? > + > + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, > + BNO055_OPR_MODE_CONFIG); > + if (ret) > + return ret; > + > + ret = bno055_reg_update_bits(priv, BNO055_ACC_CONFIG_REG, > + BNO055_ACC_CONFIG_LPF_MASK, > + best_idx << shift); > + > + if (ret) > + return ret; > + > + return regmap_write(priv->regmap, BNO055_OPR_MODE_REG, > + BNO055_OPR_MODE_AMG); > +} > + ... > + > +#define bno055_get_mag_odr(p, v) \ > + bno055_get_regmask(p, v, \ > + BNO055_MAG_CONFIG_REG, BNO055_MAG_CONFIG_ODR_MASK, \ > + bno055_mag_odr_vals) I'm not really convinced this is a worthwhile abstraction as these are typically only used once. > + ... > +static int bno055_read_simple_chan(struct iio_dev *indio_dev, > + struct iio_chan_spec const *chan, > + int *val, int *val2, long mask) > +{ > + struct bno055_priv *priv = iio_priv(indio_dev); > + __le16 raw_val; > + int ret; > + > + switch (mask) { > + case IIO_CHAN_INFO_RAW: > + ret = regmap_bulk_read(priv->regmap, chan->address, > + &raw_val, sizeof(raw_val)); > + if (ret < 0) > + return ret; > + *val = (s16)le16_to_cpu(raw_val); > + return IIO_VAL_INT; > + case IIO_CHAN_INFO_OFFSET: > + if (priv->operation_mode != BNO055_OPR_MODE_AMG) { > + *val = 0; > + } else { > + ret = regmap_bulk_read(priv->regmap, > + chan->address + > + BNO055_REG_OFFSET_ADDR, > + &raw_val, sizeof(raw_val)); > + if (ret < 0) > + return ret; > + /* > + * IMU reports sensor offests; IIO wants correction > + * offset, thus we need the 'minus' here. > + */ > + *val = -(s16)le16_to_cpu(raw_val); > + } > + return IIO_VAL_INT; > + case IIO_CHAN_INFO_SCALE: > + *val = 1; > + switch (chan->type) { > + case IIO_GRAVITY: > + /* Table 3-35: 1 m/s^2 = 100 LSB */ > + case IIO_ACCEL: > + /* Table 3-17: 1 m/s^2 = 100 LSB */ > + *val2 = 100; > + break; > + case IIO_MAGN: > + /* > + * Table 3-19: 1 uT = 16 LSB. But we need > + * Gauss: 1G = 0.1 uT. > + */ > + *val2 = 160; > + break; > + case IIO_ANGL_VEL: > + /* Table 3-22: 1 Rps = 900 LSB */ > + *val2 = 900; > + break; > + case IIO_ROT: > + /* Table 3-28: 1 degree = 16 LSB */ > + *val2 = 16; > + break; > + default: > + return -EINVAL; > + } > + return IIO_VAL_FRACTIONAL; > + default: > + return -EINVAL; default in the middle is a bit unusual. move it to the end. > + > + case IIO_CHAN_INFO_SAMP_FREQ: > + if (chan->type != IIO_MAGN) > + return -EINVAL; > + else > + return bno055_get_mag_odr(priv, val); > + > + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: > + switch (chan->type) { > + case IIO_ANGL_VEL: > + return bno055_get_gyr_lpf(priv, val); > + case IIO_ACCEL: > + return bno055_get_acc_lpf(priv, val, val2); > + default: > + return -EINVAL; > + } > + } > +} > + > + > +static int bno055_read_quaternion(struct iio_dev *indio_dev, > + struct iio_chan_spec const *chan, > + int size, int *vals, int *val_len, > + long mask) > +{ > + struct bno055_priv *priv = iio_priv(indio_dev); > + __le16 raw_vals[4]; > + int i, ret; > + > + switch (mask) { > + case IIO_CHAN_INFO_RAW: > + if (size < 4) > + return -EINVAL; > + ret = regmap_bulk_read(priv->regmap, > + BNO055_QUAT_DATA_W_LSB_REG, > + raw_vals, sizeof(raw_vals)); > + if (ret < 0) > + return ret; > + for (i = 0; i < 4; i++) > + vals[i] = (s16)le16_to_cpu(raw_vals[i]); > + *val_len = 4; > + return IIO_VAL_INT_MULTIPLE; > + case IIO_CHAN_INFO_SCALE: > + /* Table 3-31: 1 quaternion = 2^14 LSB */ > + if (size < 2) > + return -EINVAL; > + vals[0] = 1; > + vals[1] = 1 << 14; IIO_VAL_FRACTIONAL_LOG2? > + return IIO_VAL_FRACTIONAL; > + default: > + return -EINVAL; > + } > +} > + ... > + > +static ssize_t bno055_fusion_enable_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + int ret = 0; > + > + if (sysfs_streq(buf, "0")) { > + ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_AMG); > + } else { > + /* > + * Coming from AMG means the FMC was off, just switch to fusion > + * but don't change anything that doesn't belong to us (i.e let. > + * FMC stay off. > + * Coming from any other fusion mode means we don't need to do > + * anything. > + */ > + if (priv->operation_mode == BNO055_OPR_MODE_AMG) > + ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION_FMC_OFF); > + } > + > + return len ?: len; return ret?: len; might make sense, though my inclination would be to use an explicit if (ret) at the various possible error locations. > +} ... > +static ssize_t bno055_fmc_enable_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t len) > +{ > + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + int ret = 0; > + > + if (sysfs_streq(buf, "0")) { > + if (priv->operation_mode == BNO055_OPR_MODE_FUSION) > + ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION_FMC_OFF); > + } else { > + if (priv->operation_mode == BNO055_OPR_MODE_AMG) > + return -EINVAL; > + } > + > + return len ?: ret; Don't think that will return ret which is what we want if it's set. > +} > + ... > +static ssize_t in_calibration_data_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); > + u8 data[BNO055_CALDATA_LEN]; > + int ret; > + > + mutex_lock(&priv->lock); > + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, > + BNO055_OPR_MODE_CONFIG); > + if (ret) > + goto unlock; > + > + ret = regmap_bulk_read(priv->regmap, BNO055_CALDATA_START, data, > + BNO055_CALDATA_LEN); > + if (ret) > + goto unlock; > + > + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, priv->operation_mode); > + mutex_unlock(&priv->lock); > + if (ret) > + return ret; This is a case where I'd move the mutex_unlock after the check so that we have a nice shared error path via the unlock lable. > + > + memcpy(buf, data, BNO055_CALDATA_LEN); > + > + return BNO055_CALDATA_LEN; > +unlock: > + mutex_unlock(&priv->lock); > + return ret; > +} > + ... > +static ssize_t bno055_show_fw_version(struct file *file, char __user *userbuf, > + size_t count, loff_t *ppos) > +{ > + struct bno055_priv *priv = file->private_data; > + int rev, ver; > + char *buf; > + int ret; > + > + ret = regmap_read(priv->regmap, BNO055_SW_REV_LSB_REG, &rev); > + if (ret) > + return ret; > + > + ret = regmap_read(priv->regmap, BNO055_SW_REV_MSB_REG, &ver); > + if (ret) > + return ret; > + > + buf = devm_kasprintf(priv->dev, GFP_KERNEL, "ver: 0x%x, rev: 0x%x\n", > + ver, rev); > + if (!buf) > + return -ENOMEM; > + > + ret = simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); > + devm_kfree(priv->dev, buf); Why use devm managed allocations if you are just going to free it immediately? > + > + return ret; > +} > + ... > +/* > + * Reads len samples from the HW, stores them in buf starting from buf_idx, > + * and applies mask to cull (skip) unneeded samples. > + * Updates buf_idx incrementing with the number of stored samples. > + * Samples from HW are transferred into buf, then in-place copy on buf is > + * performed in order to cull samples that need to be skipped. > + * This avoids copies of the first samples until we hit the 1st sample to skip, > + * and also avoids having an extra bounce buffer. > + * buf must be able to contain len elements in spite of how many samples we are > + * going to cull. This is rather complex - I take we can't just fall back to letting the IIO core demux do all the hard work for us? > + */ > +static int bno055_scan_xfer(struct bno055_priv *priv, > + int start_ch, int len, unsigned long mask, > + __le16 *buf, int *buf_idx) > +{ > + const int base = BNO055_ACC_DATA_X_LSB_REG; > + bool quat_in_read = false; > + int buf_base = *buf_idx; > + __le16 *dst, *src; > + int offs_fixup = 0; > + int xfer_len = len; > + int ret; > + int i, n; > + > + /* > + * All chans are made up 1 16-bit sample, except for quaternion that is > + * made up 4 16-bit values. > + * For us the quaternion CH is just like 4 regular CHs. > + * If our read starts past the quaternion make sure to adjust the > + * starting offset; if the quaternion is contained in our scan then make > + * sure to adjust the read len. > + */ > + if (start_ch > BNO055_SCAN_QUATERNION) { > + start_ch += 3; > + } else if ((start_ch <= BNO055_SCAN_QUATERNION) && > + ((start_ch + len) > BNO055_SCAN_QUATERNION)) { > + quat_in_read = true; > + xfer_len += 3; > + } > + > + ret = regmap_bulk_read(priv->regmap, > + base + start_ch * sizeof(__le16), > + buf + buf_base, > + xfer_len * sizeof(__le16)); > + if (ret) > + return ret; > + > + for_each_set_bit(i, &mask, len) { > + if (quat_in_read && ((start_ch + i) > BNO055_SCAN_QUATERNION)) > + offs_fixup = 3; > + > + dst = buf + *buf_idx; > + src = buf + buf_base + offs_fixup + i; > + > + n = (start_ch + i == BNO055_SCAN_QUATERNION) ? 4 : 1; > + > + if (dst != src) > + memcpy(dst, src, n * sizeof(__le16)); > + > + *buf_idx += n; > + } > + return 0; > +} > + > +static irqreturn_t bno055_trigger_handler(int irq, void *p) > +{ > + struct iio_poll_func *pf = p; > + struct iio_dev *iio_dev = pf->indio_dev; > + struct bno055_priv *priv = iio_priv(iio_dev); > + int xfer_start, start, end, prev_end; > + bool xfer_pending = false; > + bool first = true; > + unsigned long mask; > + int buf_idx = 0; > + bool thr_hit; > + int quat; > + int ret; > + > + mutex_lock(&priv->lock); > + for_each_set_bitrange(start, end, iio_dev->active_scan_mask, > + iio_dev->masklength) { I'm not seeing this function in mainline... I guess this series has a dependency I missed? > + if (!xfer_pending) > + xfer_start = start; > + xfer_pending = true; > + > + if (!first) { first == true and we never get in here to set it to false. Perhaps we would benefit from a state machine diagram for this function? In general this function is complex enough to need documentation of what each major part is doing. > + quat = ((start > BNO055_SCAN_QUATERNION) && > + (prev_end <= BNO055_SCAN_QUATERNION)) ? 3 : 0; Having quat == 3 for a variable named quat doesn't seem intuitive. > + thr_hit = (start - prev_end + quat) > > + priv->xfer_burst_break_thr; > + > + if (thr_hit) { > + mask = *iio_dev->active_scan_mask >> xfer_start; > + ret = bno055_scan_xfer(priv, xfer_start, > + prev_end - xfer_start + 1, > + mask, priv->buf.chans, &buf_idx); > + if (ret) > + goto done; > + xfer_pending = false; > + } > + first = false; > + } > + prev_end = end; > + } > + > + if (xfer_pending) { > + mask = *iio_dev->active_scan_mask >> xfer_start; > + ret = bno055_scan_xfer(priv, xfer_start, > + end - xfer_start + 1, > + mask, priv->buf.chans, &buf_idx); > + } > + > + iio_push_to_buffers_with_timestamp(iio_dev, &priv->buf, pf->timestamp); > +done: > + mutex_unlock(&priv->lock); > + iio_trigger_notify_done(iio_dev->trig); > + return IRQ_HANDLED; > +} > + > +int bno055_probe(struct device *dev, struct regmap *regmap, > + int xfer_burst_break_thr) > +{ > + const struct firmware *caldata; > + struct bno055_priv *priv; > + struct iio_dev *iio_dev; > + struct gpio_desc *rst; > + char *fw_name_buf; > + unsigned int val; > + int ret; > + > + iio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); > + if (!iio_dev) > + return -ENOMEM; > + > + iio_dev->name = "bno055"; > + priv = iio_priv(iio_dev); > + mutex_init(&priv->lock); > + priv->regmap = regmap; > + priv->dev = dev; > + priv->xfer_burst_break_thr = xfer_burst_break_thr; blank line here would hep readability a little I think. > + rst = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); > + if (IS_ERR(rst)) > + return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset GPIO"); > + > + priv->clk = devm_clk_get_optional(dev, "clk"); > + if (IS_ERR(priv->clk)) > + return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get CLK"); > + > + ret = clk_prepare_enable(priv->clk); > + if (ret) > + return ret; > + > + ret = devm_add_action_or_reset(dev, bno055_clk_disable, priv); As mentioned above, pass priv->clk into this as we don't need to see anything else in the callback. > + if (ret) > + return ret; > + > + if (rst) { > + usleep_range(5000, 10000); > + gpiod_set_value_cansleep(rst, 0); > + usleep_range(650000, 750000); > + } > + > + ret = regmap_read(priv->regmap, BNO055_CHIP_ID_REG, &val); > + if (ret) > + return ret; > + > + if (val != BNO055_CHIP_ID_MAGIC) { > + dev_err(dev, "Unrecognized chip ID 0x%x", val); > + return -ENODEV; > + } > + > + ret = regmap_bulk_read(priv->regmap, BNO055_UID_LOWER_REG, > + priv->uid, BNO055_UID_LEN); > + if (ret) > + return ret; > + > + /* > + * This has nothing to do with the IMU firmware, this is for sensor > + * calibration data. > + */ > + fw_name_buf = devm_kasprintf(dev, GFP_KERNEL, > + BNO055_FW_UID_NAME, > + BNO055_UID_LEN, priv->uid); > + if (!fw_name_buf) > + return -ENOMEM; > + > + ret = request_firmware(&caldata, fw_name_buf, dev); > + devm_kfree(dev, fw_name_buf); > + if (ret) > + ret = request_firmware(&caldata, BNO055_FW_GENERIC_NAME, dev); > + > + if (ret) { > + dev_notice(dev, "Failed to load calibration data firmware file; this has nothing to do with IMU main firmware.\nYou can calibrate your IMU (look for 'in_autocalibration_status*' files in sysfs) and then copy 'in_calibration_data' to your firmware file"); As the notice has multiple lines, you can break at the \n points without any loss of greppability. It would be good to make this shorter though if we can - I wouldn't way what it isn't for example. Calibration file load failed. Follow instructions in Documentation/ * + write some docs on the calibration procedure. I don't think it is a good plan to give a guide in a kernel log. > + caldata = NULL; I'd hope that is already the case and it definitely looks like it is from a quick look at request_firmware(). I'd consider request_firmware buggy if it did anything else as that would imply it had side effects that weren't cleaned up on error. > + } > + > + ret = bno055_init(priv, caldata); > + if (caldata) > + release_firmware(caldata); > + if (ret) > + return ret; > + > + ret = devm_add_action_or_reset(dev, bno055_uninit, priv); > + if (ret) > + return ret; > + > + iio_dev->channels = bno055_channels; > + iio_dev->num_channels = ARRAY_SIZE(bno055_channels); > + iio_dev->info = &bno055_info; > + iio_dev->modes = INDIO_DIRECT_MODE; > + > + ret = devm_iio_triggered_buffer_setup(dev, iio_dev, > + iio_pollfunc_store_time, > + bno055_trigger_handler, NULL); > + if (ret) > + return ret; > + > + ret = devm_iio_device_register(dev, iio_dev); > + if (ret) > + return ret; > + > + bno055_debugfs_init(iio_dev); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(bno055_probe); > + ... Thanks, Jonathan ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 07/10] iio: imu: add Bosch Sensortec BNO055 core driver 2021-10-28 13:31 ` Jonathan Cameron @ 2021-11-09 11:52 ` Andrea Merello 2021-11-14 16:33 ` Jonathan Cameron 0 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-11-09 11:52 UTC (permalink / raw) To: Jonathan Cameron Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello Some inline notes. OK for all the rest. Il giorno gio 28 ott 2021 alle ore 15:27 Jonathan Cameron <jic23@kernel.org> ha scritto: > > On Thu, 28 Oct 2021 12:18:37 +0200 > Andrea Merello <andrea.merello@gmail.com> wrote: > > > This patch adds a core driver for the BNO055 IMU from Bosch. This IMU > > can be connected via both serial and I2C busses; separate patches will > > add support for them. > > > > The driver supports "AMG" (Accelerometer, Magnetometer, Gyroscope) mode, > > that provides raw data from the said internal sensors, and a couple of > > "fusion" modes (i.e. the IMU also do calculations in order to provide > > euler angles, quaternions, linear acceleration and gravity measurements). > > > > In fusion modes the AMG data is still available (with some calibration > > refinements done by the IMU), but certain settings such as low pass > > filters cut-off frequency and sensors ranges are fixed, while in AMG mode > > they can be customized; this is why AMG mode can still be interesting. > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > --- > > drivers/iio/imu/Kconfig | 1 + > > drivers/iio/imu/Makefile | 1 + > > drivers/iio/imu/bno055/Kconfig | 4 + > > drivers/iio/imu/bno055/Makefile | 3 + > > drivers/iio/imu/bno055/bno055.c | 1480 +++++++++++++++++++++++++++++++ > > drivers/iio/imu/bno055/bno055.h | 12 + > > 6 files changed, 1501 insertions(+) > > create mode 100644 drivers/iio/imu/bno055/Kconfig > > create mode 100644 drivers/iio/imu/bno055/Makefile > > create mode 100644 drivers/iio/imu/bno055/bno055.c > > create mode 100644 drivers/iio/imu/bno055/bno055.h > > > ... > > > diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c > > new file mode 100644 > > index 000000000000..c85cb985f0f1 > > --- /dev/null > > +++ b/drivers/iio/imu/bno055/bno055.c > > @@ -0,0 +1,1480 @@ > > ... > > > + > > +static int bno055_reg_update_bits(struct bno055_priv *priv, unsigned int reg, > > + unsigned int mask, unsigned int val) > > +{ > > + int ret; > > + > > + ret = regmap_update_bits(priv->regmap, reg, mask, val); > > + if (ret && ret != -ERESTARTSYS) { > > + dev_err(priv->dev, "Regmap update_bits error. adr: 0x%x, ret: %d", > > + reg, ret); > > This feels like a wrapper that made sense when developing but probably doesn't > want to still be here now things are 'working'. > > > + } > > + > > + return ret; > > +} > > + > > ... > > > + > > +static void bno055_clk_disable(void *arg) > > Easy to make arg == priv->clk and turn this into a one line function. > I'd expect these cleanup functions to be just above where probe() is defined rather > than all the way up here. > > > +{ > > + struct bno055_priv *priv = arg; > > + > > + clk_disable_unprepare(priv->clk); > > +} > > + > > ... > > > + > > +static int bno055_get_acc_lpf(struct bno055_priv *priv, int *val, int *val2) > > +{ > > + const int shift = __ffs(BNO055_ACC_CONFIG_LPF_MASK); > > + int hwval, idx; > > + int ret; > > + > > + ret = regmap_read(priv->regmap, BNO055_ACC_CONFIG_REG, &hwval); > > + if (ret) > > + return ret; > > + > > + idx = (hwval & BNO055_ACC_CONFIG_LPF_MASK) >> shift; > > Use FIELD_GET() and FIELD_PREP where possible rather than reinventing them. > > > + *val = bno055_acc_lpf_vals[idx * 2]; > > + *val2 = bno055_acc_lpf_vals[idx * 2 + 1]; > > + > > + return IIO_VAL_INT_PLUS_MICRO; > > +} > > + > > +static int bno055_set_acc_lpf(struct bno055_priv *priv, int val, int val2) > > +{ > > + const int shift = __ffs(BNO055_ACC_CONFIG_LPF_MASK); > > + int req_val = val * 1000 + val2 / 1000; > > + bool first = true; > > + int best_delta; > > + int best_idx; > > + int tbl_val; > > + int delta; > > + int ret; > > + int i; > > + > > + for (i = 0; i < ARRAY_SIZE(bno055_acc_lpf_vals) / 2; i++) { > > + tbl_val = bno055_acc_lpf_vals[i * 2] * 1000 + > > + bno055_acc_lpf_vals[i * 2 + 1] / 1000; > > + delta = abs(tbl_val - req_val); > > + if (first || delta < best_delta) { > > + best_delta = delta; > > + best_idx = i; > > + first = false; > > + } > > + } > > + > > + /* > > + * The closest value the HW supports is only one in fusion mode, > > + * and it is autoselected, so don't do anything, just return OK, > > + * as the closest possible value has been (virtually) selected > > + */ > > + if (priv->operation_mode != BNO055_OPR_MODE_AMG) > > + return 0; > > Can we do this before the big loop above? > > > > + > > + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, > > + BNO055_OPR_MODE_CONFIG); > > + if (ret) > > + return ret; > > + > > + ret = bno055_reg_update_bits(priv, BNO055_ACC_CONFIG_REG, > > + BNO055_ACC_CONFIG_LPF_MASK, > > + best_idx << shift); > > + > > + if (ret) > > + return ret; > > + > > + return regmap_write(priv->regmap, BNO055_OPR_MODE_REG, > > + BNO055_OPR_MODE_AMG); > > +} > > + > > ... > > > + > > +#define bno055_get_mag_odr(p, v) \ > > + bno055_get_regmask(p, v, \ > > + BNO055_MAG_CONFIG_REG, BNO055_MAG_CONFIG_ODR_MASK, \ > > + bno055_mag_odr_vals) > > I'm not really convinced this is a worthwhile abstraction as these are typically > only used once. > > > + > ... > > > +static int bno055_read_simple_chan(struct iio_dev *indio_dev, > > + struct iio_chan_spec const *chan, > > + int *val, int *val2, long mask) > > +{ > > + struct bno055_priv *priv = iio_priv(indio_dev); > > + __le16 raw_val; > > + int ret; > > + > > + switch (mask) { > > + case IIO_CHAN_INFO_RAW: > > + ret = regmap_bulk_read(priv->regmap, chan->address, > > + &raw_val, sizeof(raw_val)); > > + if (ret < 0) > > + return ret; > > + *val = (s16)le16_to_cpu(raw_val); > > + return IIO_VAL_INT; > > + case IIO_CHAN_INFO_OFFSET: > > + if (priv->operation_mode != BNO055_OPR_MODE_AMG) { > > + *val = 0; > > + } else { > > + ret = regmap_bulk_read(priv->regmap, > > + chan->address + > > + BNO055_REG_OFFSET_ADDR, > > + &raw_val, sizeof(raw_val)); > > + if (ret < 0) > > + return ret; > > + /* > > + * IMU reports sensor offests; IIO wants correction > > + * offset, thus we need the 'minus' here. > > + */ > > + *val = -(s16)le16_to_cpu(raw_val); > > + } > > + return IIO_VAL_INT; > > + case IIO_CHAN_INFO_SCALE: > > + *val = 1; > > + switch (chan->type) { > > + case IIO_GRAVITY: > > + /* Table 3-35: 1 m/s^2 = 100 LSB */ > > + case IIO_ACCEL: > > + /* Table 3-17: 1 m/s^2 = 100 LSB */ > > + *val2 = 100; > > + break; > > + case IIO_MAGN: > > + /* > > + * Table 3-19: 1 uT = 16 LSB. But we need > > + * Gauss: 1G = 0.1 uT. > > + */ > > + *val2 = 160; > > + break; > > + case IIO_ANGL_VEL: > > + /* Table 3-22: 1 Rps = 900 LSB */ > > + *val2 = 900; > > + break; > > + case IIO_ROT: > > + /* Table 3-28: 1 degree = 16 LSB */ > > + *val2 = 16; > > + break; > > + default: > > + return -EINVAL; > > + } > > + return IIO_VAL_FRACTIONAL; > > + default: > > + return -EINVAL; > > default in the middle is a bit unusual. move it to the end. > > > + > > + case IIO_CHAN_INFO_SAMP_FREQ: > > + if (chan->type != IIO_MAGN) > > + return -EINVAL; > > + else > > + return bno055_get_mag_odr(priv, val); > > + > > + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: > > + switch (chan->type) { > > + case IIO_ANGL_VEL: > > + return bno055_get_gyr_lpf(priv, val); > > + case IIO_ACCEL: > > + return bno055_get_acc_lpf(priv, val, val2); > > + default: > > + return -EINVAL; > > + } > > + } > > +} > > + > > > > + > > +static int bno055_read_quaternion(struct iio_dev *indio_dev, > > + struct iio_chan_spec const *chan, > > + int size, int *vals, int *val_len, > > + long mask) > > +{ > > + struct bno055_priv *priv = iio_priv(indio_dev); > > + __le16 raw_vals[4]; > > + int i, ret; > > + > > + switch (mask) { > > + case IIO_CHAN_INFO_RAW: > > + if (size < 4) > > + return -EINVAL; > > + ret = regmap_bulk_read(priv->regmap, > > + BNO055_QUAT_DATA_W_LSB_REG, > > + raw_vals, sizeof(raw_vals)); > > + if (ret < 0) > > + return ret; > > + for (i = 0; i < 4; i++) > > + vals[i] = (s16)le16_to_cpu(raw_vals[i]); > > + *val_len = 4; > > + return IIO_VAL_INT_MULTIPLE; > > + case IIO_CHAN_INFO_SCALE: > > + /* Table 3-31: 1 quaternion = 2^14 LSB */ > > + if (size < 2) > > + return -EINVAL; > > + vals[0] = 1; > > + vals[1] = 1 << 14; > > IIO_VAL_FRACTIONAL_LOG2? > > > + return IIO_VAL_FRACTIONAL; > > + default: > > + return -EINVAL; > > + } > > +} > > + > > ... > > > + > > +static ssize_t bno055_fusion_enable_store(struct device *dev, > > + struct device_attribute *attr, > > + const char *buf, size_t len) > > +{ > > + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); > > + int ret = 0; > > + > > + if (sysfs_streq(buf, "0")) { > > + ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_AMG); > > + } else { > > + /* > > + * Coming from AMG means the FMC was off, just switch to fusion > > + * but don't change anything that doesn't belong to us (i.e let. > > + * FMC stay off. > > + * Coming from any other fusion mode means we don't need to do > > + * anything. > > + */ > > + if (priv->operation_mode == BNO055_OPR_MODE_AMG) > > + ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION_FMC_OFF); > > + } > > + > > + return len ?: len; > > return ret?: len; might make sense, though my inclination would be to use an explicit > if (ret) at the various possible error locations. > > > +} > > ... > > > +static ssize_t bno055_fmc_enable_store(struct device *dev, > > + struct device_attribute *attr, > > + const char *buf, size_t len) > > +{ > > + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); > > + int ret = 0; > > + > > + if (sysfs_streq(buf, "0")) { > > + if (priv->operation_mode == BNO055_OPR_MODE_FUSION) > > + ret = bno055_operation_mode_set(priv, BNO055_OPR_MODE_FUSION_FMC_OFF); > > + } else { > > + if (priv->operation_mode == BNO055_OPR_MODE_AMG) > > + return -EINVAL; > > + } > > + > > + return len ?: ret; > > Don't think that will return ret which is what we want if it's set. > > > +} > > + > > ... > > > +static ssize_t in_calibration_data_show(struct device *dev, > > + struct device_attribute *attr, > > + char *buf) > > +{ > > + struct bno055_priv *priv = iio_priv(dev_to_iio_dev(dev)); > > + u8 data[BNO055_CALDATA_LEN]; > > + int ret; > > + > > + mutex_lock(&priv->lock); > > + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, > > + BNO055_OPR_MODE_CONFIG); > > + if (ret) > > + goto unlock; > > + > > + ret = regmap_bulk_read(priv->regmap, BNO055_CALDATA_START, data, > > + BNO055_CALDATA_LEN); > > + if (ret) > > + goto unlock; > > + > > + ret = regmap_write(priv->regmap, BNO055_OPR_MODE_REG, priv->operation_mode); > > + mutex_unlock(&priv->lock); > > + if (ret) > > + return ret; > > This is a case where I'd move the mutex_unlock after the check so that we have > a nice shared error path via the unlock lable. > > > + > > + memcpy(buf, data, BNO055_CALDATA_LEN); > > + > > + return BNO055_CALDATA_LEN; > > +unlock: > > + mutex_unlock(&priv->lock); > > + return ret; > > +} > > + > ... > > > +static ssize_t bno055_show_fw_version(struct file *file, char __user *userbuf, > > + size_t count, loff_t *ppos) > > +{ > > + struct bno055_priv *priv = file->private_data; > > + int rev, ver; > > + char *buf; > > + int ret; > > + > > + ret = regmap_read(priv->regmap, BNO055_SW_REV_LSB_REG, &rev); > > + if (ret) > > + return ret; > > + > > + ret = regmap_read(priv->regmap, BNO055_SW_REV_MSB_REG, &ver); > > + if (ret) > > + return ret; > > + > > + buf = devm_kasprintf(priv->dev, GFP_KERNEL, "ver: 0x%x, rev: 0x%x\n", > > + ver, rev); > > + if (!buf) > > + return -ENOMEM; > > + > > + ret = simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); > > + devm_kfree(priv->dev, buf); > > Why use devm managed allocations if you are just going to free it immediately? > > > + > > + return ret; > > +} > > + > > ... > > > +/* > > + * Reads len samples from the HW, stores them in buf starting from buf_idx, > > + * and applies mask to cull (skip) unneeded samples. > > + * Updates buf_idx incrementing with the number of stored samples. > > + * Samples from HW are transferred into buf, then in-place copy on buf is > > + * performed in order to cull samples that need to be skipped. > > + * This avoids copies of the first samples until we hit the 1st sample to skip, > > + * and also avoids having an extra bounce buffer. > > + * buf must be able to contain len elements in spite of how many samples we are > > + * going to cull. > > This is rather complex - I take we can't just fall back to letting the IIO core > demux do all the hard work for us? Hum. I'm not sure.. I admit that I'm not familiar with the demux thing, but as far as I can see it needs to be initialized once with a list containing all allowed scan masks; IIO core will pick one of them and eventually cull extra samples it contains. Is this right? I would say we may precalculate this list at probe time (depending on the burst break threshold) and populate it with all the possible scan masks in which there are no gaps < than the bust break threshold. But this could be a quite high number of combinations.. This way the IIO layer will only request xfers in which gaps are always > than burst break threshold, which the driver in turn will always split in several xfers. Does this make sense to you? > > + */ > > +static int bno055_scan_xfer(struct bno055_priv *priv, > > + int start_ch, int len, unsigned long mask, > > + __le16 *buf, int *buf_idx) > > +{ > > + const int base = BNO055_ACC_DATA_X_LSB_REG; > > + bool quat_in_read = false; > > + int buf_base = *buf_idx; > > + __le16 *dst, *src; > > + int offs_fixup = 0; > > + int xfer_len = len; > > + int ret; > > + int i, n; > > + > > + /* > > + * All chans are made up 1 16-bit sample, except for quaternion that is > > + * made up 4 16-bit values. > > + * For us the quaternion CH is just like 4 regular CHs. > > + * If our read starts past the quaternion make sure to adjust the > > + * starting offset; if the quaternion is contained in our scan then make > > + * sure to adjust the read len. > > + */ > > + if (start_ch > BNO055_SCAN_QUATERNION) { > > + start_ch += 3; > > + } else if ((start_ch <= BNO055_SCAN_QUATERNION) && > > + ((start_ch + len) > BNO055_SCAN_QUATERNION)) { > > + quat_in_read = true; > > + xfer_len += 3; > > + } > > + > > + ret = regmap_bulk_read(priv->regmap, > > + base + start_ch * sizeof(__le16), > > + buf + buf_base, > > + xfer_len * sizeof(__le16)); > > + if (ret) > > + return ret; > > + > > + for_each_set_bit(i, &mask, len) { > > + if (quat_in_read && ((start_ch + i) > BNO055_SCAN_QUATERNION)) > > + offs_fixup = 3; > > + > > + dst = buf + *buf_idx; > > + src = buf + buf_base + offs_fixup + i; > > + > > + n = (start_ch + i == BNO055_SCAN_QUATERNION) ? 4 : 1; > > + > > + if (dst != src) > > + memcpy(dst, src, n * sizeof(__le16)); > > + > > + *buf_idx += n; > > + } > > + return 0; > > +} > > + > > +static irqreturn_t bno055_trigger_handler(int irq, void *p) > > +{ > > + struct iio_poll_func *pf = p; > > + struct iio_dev *iio_dev = pf->indio_dev; > > + struct bno055_priv *priv = iio_priv(iio_dev); > > + int xfer_start, start, end, prev_end; > > + bool xfer_pending = false; > > + bool first = true; > > + unsigned long mask; > > + int buf_idx = 0; > > + bool thr_hit; > > + int quat; > > + int ret; > > + > > + mutex_lock(&priv->lock); > > + for_each_set_bitrange(start, end, iio_dev->active_scan_mask, > > + iio_dev->masklength) { > > I'm not seeing this function in mainline... I guess this series has a dependency > I missed? I've been pointed to Yuri Norov bitmap series (I mentioned this in the cover letter). Assuming it is close to be merged, I've updated my drv for its API changes, but if you prefer I can revert to the current mainline API. It's a trivial change. > > + if (!xfer_pending) > > + xfer_start = start; > > + xfer_pending = true; > > + > > + if (!first) { > > first == true and we never get in here to set it to false. That's awful. Possibly I've broken this while making changes for V2, and my test program didn't catch it. Maybe it just impacts performances, which, now I realize, I probably didn't rechek :( > Perhaps we would benefit from a state machine diagram for this function? > In general this function is complex enough to need documentation of what > each major part is doing. > > > + quat = ((start > BNO055_SCAN_QUATERNION) && > > + (prev_end <= BNO055_SCAN_QUATERNION)) ? 3 : 0; > > Having quat == 3 for a variable named quat doesn't seem intuitive. > > > + thr_hit = (start - prev_end + quat) > > > + priv->xfer_burst_break_thr; > > + > > + if (thr_hit) { > > + mask = *iio_dev->active_scan_mask >> xfer_start; > > + ret = bno055_scan_xfer(priv, xfer_start, > > + prev_end - xfer_start + 1, > > + mask, priv->buf.chans, &buf_idx); > > + if (ret) > > + goto done; > > + xfer_pending = false; > > + } > > + first = false; > > + } > > + prev_end = end; > > + } > > + > > + if (xfer_pending) { > > + mask = *iio_dev->active_scan_mask >> xfer_start; > > + ret = bno055_scan_xfer(priv, xfer_start, > > + end - xfer_start + 1, > > + mask, priv->buf.chans, &buf_idx); > > + } > > + > > + iio_push_to_buffers_with_timestamp(iio_dev, &priv->buf, pf->timestamp); > > +done: > > + mutex_unlock(&priv->lock); > > + iio_trigger_notify_done(iio_dev->trig); > > + return IRQ_HANDLED; > > +} > > + > > +int bno055_probe(struct device *dev, struct regmap *regmap, > > + int xfer_burst_break_thr) > > +{ > > + const struct firmware *caldata; > > + struct bno055_priv *priv; > > + struct iio_dev *iio_dev; > > + struct gpio_desc *rst; > > + char *fw_name_buf; > > + unsigned int val; > > + int ret; > > + > > + iio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); > > + if (!iio_dev) > > + return -ENOMEM; > > + > > + iio_dev->name = "bno055"; > > + priv = iio_priv(iio_dev); > > + mutex_init(&priv->lock); > > + priv->regmap = regmap; > > + priv->dev = dev; > > + priv->xfer_burst_break_thr = xfer_burst_break_thr; > > blank line here would hep readability a little I think. > > > + rst = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); > > + if (IS_ERR(rst)) > > + return dev_err_probe(dev, PTR_ERR(rst), "Failed to get reset GPIO"); > > + > > + priv->clk = devm_clk_get_optional(dev, "clk"); > > + if (IS_ERR(priv->clk)) > > + return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get CLK"); > > + > > + ret = clk_prepare_enable(priv->clk); > > + if (ret) > > + return ret; > > + > > + ret = devm_add_action_or_reset(dev, bno055_clk_disable, priv); > > As mentioned above, pass priv->clk into this as we don't need to see anything > else in the callback. > > > + if (ret) > > + return ret; > > + > > + if (rst) { > > + usleep_range(5000, 10000); > > + gpiod_set_value_cansleep(rst, 0); > > + usleep_range(650000, 750000); > > + } > > + > > + ret = regmap_read(priv->regmap, BNO055_CHIP_ID_REG, &val); > > + if (ret) > > + return ret; > > + > > + if (val != BNO055_CHIP_ID_MAGIC) { > > + dev_err(dev, "Unrecognized chip ID 0x%x", val); > > + return -ENODEV; > > + } > > + > > + ret = regmap_bulk_read(priv->regmap, BNO055_UID_LOWER_REG, > > + priv->uid, BNO055_UID_LEN); > > + if (ret) > > + return ret; > > + > > + /* > > + * This has nothing to do with the IMU firmware, this is for sensor > > + * calibration data. > > + */ > > + fw_name_buf = devm_kasprintf(dev, GFP_KERNEL, > > + BNO055_FW_UID_NAME, > > + BNO055_UID_LEN, priv->uid); > > + if (!fw_name_buf) > > + return -ENOMEM; > > + > > + ret = request_firmware(&caldata, fw_name_buf, dev); > > + devm_kfree(dev, fw_name_buf); > > + if (ret) > > + ret = request_firmware(&caldata, BNO055_FW_GENERIC_NAME, dev); > > + > > + if (ret) { > > + dev_notice(dev, "Failed to load calibration data firmware file; this has nothing to do with IMU main firmware.\nYou can calibrate your IMU (look for 'in_autocalibration_status*' files in sysfs) and then copy 'in_calibration_data' to your firmware file"); > > As the notice has multiple lines, you can break at the \n points without any loss of greppability. > It would be good to make this shorter though if we can - I wouldn't way what it isn't for example. > > Calibration file load failed. > Follow instructions in Documentation/ * > > + write some docs on the calibration procedure. I don't think it is a > good plan to give a guide in a kernel log. > > > + caldata = NULL; > > I'd hope that is already the case and it definitely looks like it is from a quick look > at request_firmware(). I'd consider request_firmware buggy if it did anything else > as that would imply it had side effects that weren't cleaned up on error. > > > + } > > + > > + ret = bno055_init(priv, caldata); > > + if (caldata) > > + release_firmware(caldata); > > + if (ret) > > + return ret; > > + > > + ret = devm_add_action_or_reset(dev, bno055_uninit, priv); > > + if (ret) > > + return ret; > > + > > + iio_dev->channels = bno055_channels; > > + iio_dev->num_channels = ARRAY_SIZE(bno055_channels); > > + iio_dev->info = &bno055_info; > > + iio_dev->modes = INDIO_DIRECT_MODE; > > + > > + ret = devm_iio_triggered_buffer_setup(dev, iio_dev, > > + iio_pollfunc_store_time, > > + bno055_trigger_handler, NULL); > > + if (ret) > > + return ret; > > + > > + ret = devm_iio_device_register(dev, iio_dev); > > + if (ret) > > + return ret; > > + > > + bno055_debugfs_init(iio_dev); > > + > > + return 0; > > +} > > +EXPORT_SYMBOL_GPL(bno055_probe); > > + > ... > > Thanks, > > Jonathan ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 07/10] iio: imu: add Bosch Sensortec BNO055 core driver 2021-11-09 11:52 ` Andrea Merello @ 2021-11-14 16:33 ` Jonathan Cameron 0 siblings, 0 replies; 55+ messages in thread From: Jonathan Cameron @ 2021-11-14 16:33 UTC (permalink / raw) To: Andrea Merello Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On Tue, 9 Nov 2021 12:52:14 +0100 Andrea Merello <andrea.merello@gmail.com> wrote: > Some inline notes. OK for all the rest. > > Il giorno gio 28 ott 2021 alle ore 15:27 Jonathan Cameron > <jic23@kernel.org> ha scritto: > > > > On Thu, 28 Oct 2021 12:18:37 +0200 > > Andrea Merello <andrea.merello@gmail.com> wrote: > > > > > This patch adds a core driver for the BNO055 IMU from Bosch. This IMU > > > can be connected via both serial and I2C busses; separate patches will > > > add support for them. > > > > > > The driver supports "AMG" (Accelerometer, Magnetometer, Gyroscope) mode, > > > that provides raw data from the said internal sensors, and a couple of > > > "fusion" modes (i.e. the IMU also do calculations in order to provide > > > euler angles, quaternions, linear acceleration and gravity measurements). > > > > > > In fusion modes the AMG data is still available (with some calibration > > > refinements done by the IMU), but certain settings such as low pass > > > filters cut-off frequency and sensors ranges are fixed, while in AMG mode > > > they can be customized; this is why AMG mode can still be interesting. > > > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> Side not. Please crop out bits of the discussion we aren't continuing. Makes it easier to find the relevant parts of the email! Note this is a do as I say rather than do as I do as I don't always remember to do this either. ... > > > > > +/* > > > + * Reads len samples from the HW, stores them in buf starting from buf_idx, > > > + * and applies mask to cull (skip) unneeded samples. > > > + * Updates buf_idx incrementing with the number of stored samples. > > > + * Samples from HW are transferred into buf, then in-place copy on buf is > > > + * performed in order to cull samples that need to be skipped. > > > + * This avoids copies of the first samples until we hit the 1st sample to skip, > > > + * and also avoids having an extra bounce buffer. > > > + * buf must be able to contain len elements in spite of how many samples we are > > > + * going to cull. > > > > This is rather complex - I take we can't just fall back to letting the IIO core > > demux do all the hard work for us? > > Hum. I'm not sure.. I admit that I'm not familiar with the demux > thing, but as far as I can see it needs to be initialized once with a > list containing all allowed scan masks; IIO core will pick one of them > and eventually cull extra samples it contains. Is this right? yup - that's pretty much it. > > I would say we may precalculate this list at probe time (depending on > the burst break threshold) and populate it with all the possible scan > masks in which there are no gaps < than the bust break threshold. But > this could be a quite high number of combinations.. > > This way the IIO layer will only request xfers in which gaps are > always > than burst break threshold, which the driver in turn will > always split in several xfers. > > Does this make sense to you? If it works and ends up simpler than this I'm all for it, but I'll confess you've lost me in the explanation. Whether the approach you are using here ends up more efficient than the one in the demux (which IIRC works by doing an expensive copy map building just once and can then use that to do things like merging copies of neighbouring elements) will be dependent on exact combinations of enabled channels. There is also a usecase question for how much effort it is worth putting in to optimise these paths. In a lot of cases people have put an IMU in because their application needs one so will be grabbing almost all channels all the time. It is unlikely they want a random set of scattered channels. > > > > + */ > > > +static int bno055_scan_xfer(struct bno055_priv *priv, > > > + int start_ch, int len, unsigned long mask, > > > + __le16 *buf, int *buf_idx) > > > +{ > > > + const int base = BNO055_ACC_DATA_X_LSB_REG; > > > + bool quat_in_read = false; > > > + int buf_base = *buf_idx; > > > + __le16 *dst, *src; > > > + int offs_fixup = 0; > > > + int xfer_len = len; > > > + int ret; > > > + int i, n; > > > + > > > + /* > > > + * All chans are made up 1 16-bit sample, except for quaternion that is > > > + * made up 4 16-bit values. > > > + * For us the quaternion CH is just like 4 regular CHs. > > > + * If our read starts past the quaternion make sure to adjust the > > > + * starting offset; if the quaternion is contained in our scan then make > > > + * sure to adjust the read len. > > > + */ > > > + if (start_ch > BNO055_SCAN_QUATERNION) { > > > + start_ch += 3; > > > + } else if ((start_ch <= BNO055_SCAN_QUATERNION) && > > > + ((start_ch + len) > BNO055_SCAN_QUATERNION)) { > > > + quat_in_read = true; > > > + xfer_len += 3; > > > + } > > > + > > > + ret = regmap_bulk_read(priv->regmap, > > > + base + start_ch * sizeof(__le16), > > > + buf + buf_base, > > > + xfer_len * sizeof(__le16)); > > > + if (ret) > > > + return ret; > > > + > > > + for_each_set_bit(i, &mask, len) { > > > + if (quat_in_read && ((start_ch + i) > BNO055_SCAN_QUATERNION)) > > > + offs_fixup = 3; > > > + > > > + dst = buf + *buf_idx; > > > + src = buf + buf_base + offs_fixup + i; > > > + > > > + n = (start_ch + i == BNO055_SCAN_QUATERNION) ? 4 : 1; > > > + > > > + if (dst != src) > > > + memcpy(dst, src, n * sizeof(__le16)); > > > + > > > + *buf_idx += n; > > > + } > > > + return 0; > > > +} > > > + > > > +static irqreturn_t bno055_trigger_handler(int irq, void *p) > > > +{ > > > + struct iio_poll_func *pf = p; > > > + struct iio_dev *iio_dev = pf->indio_dev; > > > + struct bno055_priv *priv = iio_priv(iio_dev); > > > + int xfer_start, start, end, prev_end; > > > + bool xfer_pending = false; > > > + bool first = true; > > > + unsigned long mask; > > > + int buf_idx = 0; > > > + bool thr_hit; > > > + int quat; > > > + int ret; > > > + > > > + mutex_lock(&priv->lock); > > > + for_each_set_bitrange(start, end, iio_dev->active_scan_mask, > > > + iio_dev->masklength) { > > > > I'm not seeing this function in mainline... I guess this series has a dependency > > I missed? > > I've been pointed to Yuri Norov bitmap series (I mentioned this in the > cover letter). Assuming it is close to be merged, I've updated my drv > for its API changes, but if you prefer I can revert to the current > mainline API. It's a trivial change. Ah. Thanks for pointing that out. I missed the note in the cover letter. Jonathan ^ permalink raw reply [flat|nested] 55+ messages in thread
* [v2 08/10] dt-bindings: iio: imu: add documentation for Bosch BNO055 bindings 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello ` (6 preceding siblings ...) 2021-10-28 10:18 ` [v2 07/10] iio: imu: add Bosch Sensortec BNO055 core driver Andrea Merello @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 12:25 ` Rob Herring 2021-10-28 10:18 ` [v2 09/10] iio: imu: add BNO055 serdev driver Andrea Merello ` (2 subsequent siblings) 10 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello, Andrea Merello Introduce new documentation file for the Bosch BNO055 IMU Signed-off-by: Andrea Merello <andrea.merello@iit.it> --- .../bindings/iio/imu/bosch,bno055.yaml | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/bosch,bno055.yaml diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,bno055.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,bno055.yaml new file mode 100644 index 000000000000..0c0141162d63 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/bosch,bno055.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/imu/bosch,bno055-serial.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bosch BNO055 + +maintainers: + - Andrea Merello <andrea.merello@iit.it> + +description: | + Inertial Measurement Unit with Accelerometer, Gyroscope, Magnetometer and + internal MCU for sensor fusion + https://www.bosch-sensortec.com/products/smart-sensors/bno055/ + +properties: + compatible: + enum: + - bosch,bno055 + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + serial { + imu { + compatible = "bosch,bno055"; + reset-gpios = <&gpio0 54 GPIO_ACTIVE_LOW>; + clocks = <&imu_clk>; + }; + }; + + - | + #include <dt-bindings/gpio/gpio.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + + imu@28 { + compatible = "bosch,bno055"; + reg = <0x28> + reset-gpios = <&gpio0 54 GPIO_ACTIVE_LOW>; + clocks = <&imu_clk>; + }; + }; -- 2.17.1 ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 08/10] dt-bindings: iio: imu: add documentation for Bosch BNO055 bindings 2021-10-28 10:18 ` [v2 08/10] dt-bindings: iio: imu: add documentation for Bosch BNO055 bindings Andrea Merello @ 2021-10-28 12:25 ` Rob Herring 0 siblings, 0 replies; 55+ messages in thread From: Rob Herring @ 2021-10-28 12:25 UTC (permalink / raw) To: Andrea Merello Cc: andy.shevchenko, robh+dt, lars, matt.ranostay, Andrea Merello, devicetree, jacopo, mchehab+huawei, linux-kernel, linux-iio, jic23, ardeleanalex On Thu, 28 Oct 2021 12:18:38 +0200, Andrea Merello wrote: > Introduce new documentation file for the Bosch BNO055 IMU > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > --- > .../bindings/iio/imu/bosch,bno055.yaml | 59 +++++++++++++++++++ > 1 file changed, 59 insertions(+) > create mode 100644 Documentation/devicetree/bindings/iio/imu/bosch,bno055.yaml > My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check' on your patch (DT_CHECKER_FLAGS is new in v5.13): yamllint warnings/errors: ./Documentation/devicetree/bindings/iio/imu/bosch,bno055.yaml:20:6: [warning] wrong indentation: expected 6 but found 5 (indentation) ./Documentation/devicetree/bindings/iio/imu/bosch,bno055.yaml:37:2: [warning] wrong indentation: expected 2 but found 1 (indentation) dtschema/dtc warnings/errors: ./Documentation/devicetree/bindings/iio/imu/bosch,bno055.yaml: $id: relative path/filename doesn't match actual path or filename expected: http://devicetree.org/schemas/iio/imu/bosch,bno055.yaml# Error: Documentation/devicetree/bindings/iio/imu/bosch,bno055.example.dts:53.13-14 syntax error FATAL ERROR: Unable to parse input tree make[1]: *** [scripts/Makefile.lib:385: Documentation/devicetree/bindings/iio/imu/bosch,bno055.example.dt.yaml] Error 1 make[1]: *** Waiting for unfinished jobs.... make: *** [Makefile:1441: dt_binding_check] Error 2 doc reference errors (make refcheckdocs): See https://patchwork.ozlabs.org/patch/1547408 This check can fail if there are any dependencies. The base for a patch series is generally the most recent rc1. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit. ^ permalink raw reply [flat|nested] 55+ messages in thread
* [v2 09/10] iio: imu: add BNO055 serdev driver 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello ` (7 preceding siblings ...) 2021-10-28 10:18 ` [v2 08/10] dt-bindings: iio: imu: add documentation for Bosch BNO055 bindings Andrea Merello @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 12:31 ` Jonathan Cameron ` (2 more replies) 2021-10-28 10:18 ` [v2 10/10] iio: imu: add BNO055 I2C driver Andrea Merello 2021-10-28 10:35 ` [v2 00/10] Add support for Bosch BNO055 IMU Jonathan Cameron 10 siblings, 3 replies; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello, Andrea Merello This path adds a serdev driver for communicating to a BNO055 IMU via serial bus, and it enables the BNO055 core driver to work in this scenario. Signed-off-by: Andrea Merello <andrea.merello@iit.it> --- drivers/iio/imu/bno055/Kconfig | 5 + drivers/iio/imu/bno055/Makefile | 1 + drivers/iio/imu/bno055/bno055_sl.c | 568 +++++++++++++++++++++++++++++ 3 files changed, 574 insertions(+) create mode 100644 drivers/iio/imu/bno055/bno055_sl.c diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig index d197310661af..941e43f0368d 100644 --- a/drivers/iio/imu/bno055/Kconfig +++ b/drivers/iio/imu/bno055/Kconfig @@ -2,3 +2,8 @@ config BOSH_BNO055_IIO tristate + +config BOSH_BNO055_SERIAL + tristate "Bosh BNO055 attached via serial bus" + depends on SERIAL_DEV_BUS + select BOSH_BNO055_IIO diff --git a/drivers/iio/imu/bno055/Makefile b/drivers/iio/imu/bno055/Makefile index c55741d0e96f..7285ade2f4b9 100644 --- a/drivers/iio/imu/bno055/Makefile +++ b/drivers/iio/imu/bno055/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_BOSH_BNO055_IIO) += bno055.o +obj-$(CONFIG_BOSH_BNO055_SERIAL) += bno055_sl.o diff --git a/drivers/iio/imu/bno055/bno055_sl.c b/drivers/iio/imu/bno055/bno055_sl.c new file mode 100644 index 000000000000..1d1410fdaa7c --- /dev/null +++ b/drivers/iio/imu/bno055/bno055_sl.c @@ -0,0 +1,568 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Serial line interface for Bosh BNO055 IMU (via serdev). + * This file implements serial communication up to the register read/write + * level. + * + * Copyright (C) 2021 Istituto Italiano di Tecnologia + * Electronic Design Laboratory + * Written by Andrea Merello <andrea.merello@iit.it> + * + * This driver is besed on + * Plantower PMS7003 particulate matter sensor driver + * Which is + * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com> + */ + +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/serdev.h> + +#include "bno055.h" + +/* + * Register writes cmd have the following format + * +------+------+-----+-----+----- ... ----+ + * | 0xAA | 0xOO | REG | LEN | payload[LEN] | + * +------+------+-----+-----+----- ... ----+ + * + * Register write responses have the following format + * +------+----------+ + * | 0xEE | ERROCODE | + * +------+----------+ + * + * Register read have the following format + * +------+------+-----+-----+ + * | 0xAA | 0xO1 | REG | LEN | + * +------+------+-----+-----+ + * + * Successful register read response have the following format + * +------+-----+----- ... ----+ + * | 0xBB | LEN | payload[LEN] | + * +------+-----+----- ... ----+ + * + * Failed register read response have the following format + * +------+--------+ + * | 0xEE | ERRCODE| (ERRCODE always > 1) + * +------+--------+ + * + * Error codes are + * 01: OK + * 02: read/write FAIL + * 04: invalid address + * 05: write on RO + * 06: wrong start byte + * 07: bus overrun + * 08: len too high + * 09: len too low + * 10: bus RX byte timeout (timeout is 30mS) + * + * + * **WORKAROUND ALERT** + * + * Serial communication seems very fragile: the BNO055 buffer seems to overflow + * very easy; BNO055 seems able to sink few bytes, then it needs a brief pause. + * On the other hand, it is also picky on timeout: if there is a pause > 30mS in + * between two bytes then the transaction fails (IMU internal RX FSM resets). + * + * BMU055 has been seen also failing to process commands in case we send them + * too close each other (or if it is somehow busy?) + * + * One idea would be to split data in chunks, and then wait 1-2mS between + * chunks (we hope not to exceed 30mS delay for any reason - which should + * be pretty a lot of time for us), and eventually retry in case the BNO055 + * gets upset for any reason. This seems to work in avoiding the overflow + * errors, but indeed it seems slower than just perform a retry when an overflow + * error occur. + * In particular I saw these scenarios: + * 1) If we send 2 bytes per time, then the IMU never(?) overflows. + * 2) If we send 4 bytes per time (i.e. the full header), then the IMU could + * overflow, but it seem to sink all 4 bytes, then it returns error. + * 3) If we send more than 4 bytes, the IMU could overflow, and I saw it sending + * error after 4 bytes are sent; we have troubles in synchronizing again, + * because we are still sending data, and the IMU interprets it as the 1st + * byte of a new command. + * + * So, we workaround all this in the following way: + * In case of read we don't split the header but we rely on retries; This seems + * convenient for data read (where we TX only the hdr). + * For TX we split the transmission in 2-bytes chunks so that, we should not + * only avoid case 2 (which is still manageable), but we also hopefully avoid + * case 3, that would be by far worse. + */ + +/* + * Read operation overhead: + * 4 bytes req + 2byte resp hdr. + * 6 bytes = 60 bit (considering 1start + 1stop bits). + * 60/115200 = ~520uS. + * + * In 520uS we could read back about 34 bytes that means 3 samples, this means + * that in case of scattered read in which the gap is 3 samples or less it is + * still convenient to go for a burst. + * We have to take into account also IMU response time - IMU seems to be often + * reasonably quick to respond, but sometimes it seems to be in some "critical + * section" in which it delays handling of serial protocol. + * By experiment, it seems convenient to burst up to about 5/6-samples-long gap. + */ + +#define BNO055_SL_XFER_BURST_BREAK_THRESHOLD 6 + +struct bno055_sl_priv { + struct serdev_device *serdev; + struct completion cmd_complete; + enum { + CMD_NONE, + CMD_READ, + CMD_WRITE, + } expect_response; + int expected_data_len; + u8 *response_buf; + + /** + * enum cmd_status - represent the status of a command sent to the HW. + * @STATUS_OK: The command executed successfully. + * @STATUS_FAIL: The command failed: HW responded with an error. + * @STATUS_CRIT: The command failed: the serial communication failed. + */ + enum { + STATUS_OK = 0, + STATUS_FAIL = 1, + STATUS_CRIT = -1 + } cmd_status; + struct mutex lock; + + /* Only accessed in behalf of RX callback context. No lock needed. */ + struct { + enum { + RX_IDLE, + RX_START, + RX_DATA + } state; + int databuf_count; + int expected_len; + int type; + } rx; + + /* Never accessed in behalf of RX callback context. No lock needed */ + bool cmd_stale; +}; + +static int bno055_sl_send_chunk(struct bno055_sl_priv *priv, u8 *data, int len) +{ + int ret; + + dev_dbg(&priv->serdev->dev, "send (len: %d): %*ph", len, len, data); + ret = serdev_device_write(priv->serdev, data, len, + msecs_to_jiffies(25)); + if (ret < 0) + return ret; + + if (ret < len) + return -EIO; + + return 0; +} + +/* + * Sends a read or write command. + * 'data' can be NULL (used in read case). 'len' parameter is always valid; in + * case 'data' is non-NULL then it must match 'data' size. + */ +static int bno055_sl_do_send_cmd(struct bno055_sl_priv *priv, + int read, int addr, int len, u8 *data) +{ + int ret; + int chunk_len; + u8 hdr[] = {0xAA, !!read, addr, len}; + + if (read) { + ret = bno055_sl_send_chunk(priv, hdr, 4); + } else { + ret = bno055_sl_send_chunk(priv, hdr, 2); + if (ret) + goto fail; + + usleep_range(2000, 3000); + ret = bno055_sl_send_chunk(priv, hdr + 2, 2); + } + if (ret) + goto fail; + + if (data) { + while (len) { + chunk_len = min(len, 2); + usleep_range(2000, 3000); + ret = bno055_sl_send_chunk(priv, data, chunk_len); + if (ret) + goto fail; + data += chunk_len; + len -= chunk_len; + } + } + + return 0; +fail: + /* waiting more than 30mS should clear the BNO055 internal state */ + usleep_range(40000, 50000); + return ret; +} + +static int bno_sl_send_cmd(struct bno055_sl_priv *priv, + int read, int addr, int len, u8 *data) +{ + const int retry_max = 5; + int retry = retry_max; + int ret = 0; + + /* + * In case previous command was interrupted we still neet to wait it to + * complete before we can issue new commands + */ + if (priv->cmd_stale) { + ret = wait_for_completion_interruptible_timeout(&priv->cmd_complete, + msecs_to_jiffies(100)); + if (ret == -ERESTARTSYS) + return -ERESTARTSYS; + + priv->cmd_stale = false; + /* if serial protocol broke, bail out */ + if (priv->cmd_status == STATUS_CRIT) + goto exit; + } + + /* + * Try to convince the IMU to cooperate.. as explained in the comments + * at the top of this file, the IMU could also refuse the command (i.e. + * it is not ready yet); retry in this case. + */ + while (retry--) { + mutex_lock(&priv->lock); + priv->expect_response = read ? CMD_READ : CMD_WRITE; + reinit_completion(&priv->cmd_complete); + mutex_unlock(&priv->lock); + + if (retry != (retry_max - 1)) + dev_dbg(&priv->serdev->dev, "cmd retry: %d", + retry_max - retry); + ret = bno055_sl_do_send_cmd(priv, read, addr, len, data); + if (ret) + continue; + + ret = wait_for_completion_interruptible_timeout(&priv->cmd_complete, + msecs_to_jiffies(100)); + if (ret == -ERESTARTSYS) { + priv->cmd_stale = true; + return -ERESTARTSYS; + } else if (!ret) { + ret = -ETIMEDOUT; + break; + } + ret = 0; + + /* + * Poll if the IMU returns error (i.e busy), break if the IMU + * returns OK or if the serial communication broke + */ + if (priv->cmd_status <= 0) + break; + } + +exit: + if (ret) + return ret; + if (priv->cmd_status == STATUS_CRIT) + return -EIO; + if (priv->cmd_status == STATUS_FAIL) + return -EINVAL; + return 0; +} + +static int bno055_sl_write_reg(void *context, const void *data, size_t count) +{ + int ret; + int reg; + u8 *write_data = (u8 *)data + 1; + struct bno055_sl_priv *priv = context; + + if (count < 2) { + dev_err(&priv->serdev->dev, "Invalid write count %zu", count); + return -EINVAL; + } + + reg = ((u8 *)data)[0]; + dev_dbg(&priv->serdev->dev, "wr reg 0x%x = 0x%x", reg, ((u8 *)data)[1]); + ret = bno_sl_send_cmd(priv, 0, reg, count - 1, write_data); + + return ret; +} + +static int bno055_sl_read_reg(void *context, + const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + int ret; + int reg_addr; + struct bno055_sl_priv *priv = context; + + if (val_size > 128) { + dev_err(&priv->serdev->dev, "Invalid read valsize %d", + val_size); + return -EINVAL; + } + + reg_addr = ((u8 *)reg)[0]; + dev_dbg(&priv->serdev->dev, "rd reg 0x%x (len %d)", reg_addr, val_size); + mutex_lock(&priv->lock); + priv->expected_data_len = val_size; + priv->response_buf = val; + mutex_unlock(&priv->lock); + + ret = bno_sl_send_cmd(priv, 1, reg_addr, val_size, NULL); + + mutex_lock(&priv->lock); + priv->response_buf = NULL; + mutex_unlock(&priv->lock); + + return ret; +} + +/* + * Handler for received data; this is called from the reicever callback whenever + * it got some packet from the serial bus. The status tell us whether the + * packet is valid (i.e. header ok && received payload len consistent wrt the + * header). It's now our responsability to check whether this is what we + * expected, of whether we got some unexpected, yet valid, packet. + */ +static void bno055_sl_handle_rx(struct bno055_sl_priv *priv, int status) +{ + mutex_lock(&priv->lock); + switch (priv->expect_response) { + case CMD_NONE: + dev_warn(&priv->serdev->dev, "received unexpected, yet valid, data from sensor"); + mutex_unlock(&priv->lock); + return; + + case CMD_READ: + priv->cmd_status = status; + if (status == STATUS_OK && + priv->rx.databuf_count != priv->expected_data_len) { + /* + * If we got here, then the lower layer serial protocol + * seems consistent with itself; if we got an unexpected + * amount of data then signal it as a non critical error + */ + priv->cmd_status = STATUS_FAIL; + dev_warn(&priv->serdev->dev, "received an unexpected amount of, yet valid, data from sensor"); + } + break; + + case CMD_WRITE: + priv->cmd_status = status; + break; + } + + priv->expect_response = CMD_NONE; + complete(&priv->cmd_complete); + mutex_unlock(&priv->lock); +} + +/* + * Serdev receiver FSM. This tracks the serial communication and parse the + * header. It pushes packets to bno055_sl_handle_rx(), eventually communicating + * failures (i.e. malformed packets). + * Ideally it doesn't know anything about upper layer (i.e. if this is the + * packet we were really expecting), but since we copies the payload into the + * receiver buffer (that is not valid when i.e. we don't expect data), we + * snoop a bit in the upper layer.. + * Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything + * unless we require to AND we don't queue more than one request per time). + */ +static int bno055_sl_receive_buf(struct serdev_device *serdev, + const unsigned char *buf, size_t size) +{ + int status; + struct bno055_sl_priv *priv = serdev_device_get_drvdata(serdev); + int _size = size; + + if (size == 0) + return 0; + + dev_dbg(&priv->serdev->dev, "recv (len %zu): %*ph ", size, size, buf); + switch (priv->rx.state) { + case RX_IDLE: + /* + * New packet. + * Check for its 1st byte, that identifies the pkt type. + */ + if (buf[0] != 0xEE && buf[0] != 0xBB) { + dev_err(&priv->serdev->dev, + "Invalid packet start %x", buf[0]); + bno055_sl_handle_rx(priv, STATUS_CRIT); + break; + } + priv->rx.type = buf[0]; + priv->rx.state = RX_START; + size--; + buf++; + priv->rx.databuf_count = 0; + fallthrough; + + case RX_START: + /* + * Packet RX in progress, we expect either 1-byte len or 1-byte + * status depending by the packet type. + */ + if (size == 0) + break; + + if (priv->rx.type == 0xEE) { + if (size > 1) { + dev_err(&priv->serdev->dev, "EE pkt. Extra data received"); + status = STATUS_CRIT; + + } else { + status = (buf[0] == 1) ? STATUS_OK : STATUS_FAIL; + } + bno055_sl_handle_rx(priv, status); + priv->rx.state = RX_IDLE; + break; + + } else { + /*priv->rx.type == 0xBB */ + priv->rx.state = RX_DATA; + priv->rx.expected_len = buf[0]; + size--; + buf++; + } + fallthrough; + + case RX_DATA: + /* Header parsed; now receiving packet data payload */ + if (size == 0) + break; + + if (priv->rx.databuf_count + size > priv->rx.expected_len) { + /* + * This is a inconsistency in serial protocol, we lost + * sync and we don't know how to handle further data + */ + dev_err(&priv->serdev->dev, "BB pkt. Extra data received"); + bno055_sl_handle_rx(priv, STATUS_CRIT); + priv->rx.state = RX_IDLE; + break; + } + + mutex_lock(&priv->lock); + /* + * NULL e.g. when read cmd is stale or when no read cmd is + * actually pending. + */ + if (priv->response_buf && + /* + * Snoop on the upper layer protocol stuff to make sure not + * to write to an invalid memory. Apart for this, let's the + * upper layer manage any inconsistency wrt expected data + * len (as long as the serial protocol is consistent wrt + * itself (i.e. response header is consistent with received + * response len. + */ + (priv->rx.databuf_count + size <= priv->expected_data_len)) + memcpy(priv->response_buf + priv->rx.databuf_count, + buf, size); + mutex_unlock(&priv->lock); + + priv->rx.databuf_count += size; + + /* + * Reached expected len advertised by the IMU for the current + * packet. Pass it to the upper layer (for us it is just valid). + */ + if (priv->rx.databuf_count == priv->rx.expected_len) { + bno055_sl_handle_rx(priv, STATUS_OK); + priv->rx.state = RX_IDLE; + } + break; + } + + return _size; +} + +static const struct serdev_device_ops bno055_sl_serdev_ops = { + .receive_buf = bno055_sl_receive_buf, + .write_wakeup = serdev_device_write_wakeup, +}; + +static struct regmap_bus bno055_sl_regmap_bus = { + .write = bno055_sl_write_reg, + .read = bno055_sl_read_reg, +}; + +static int bno055_sl_probe(struct serdev_device *serdev) +{ + struct bno055_sl_priv *priv; + struct regmap *regmap; + int ret; + + priv = devm_kzalloc(&serdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + serdev_device_set_drvdata(serdev, priv); + priv->serdev = serdev; + mutex_init(&priv->lock); + init_completion(&priv->cmd_complete); + + serdev_device_set_client_ops(serdev, &bno055_sl_serdev_ops); + ret = devm_serdev_device_open(&serdev->dev, serdev); + if (ret) + return ret; + + if (serdev_device_set_baudrate(serdev, 115200) != 115200) { + dev_err(&serdev->dev, "Cannot set required baud rate"); + return -EIO; + } + + ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); + if (ret) { + dev_err(&serdev->dev, "Cannot set required parity setting"); + return ret; + } + serdev_device_set_flow_control(serdev, false); + + regmap = devm_regmap_init(&serdev->dev, &bno055_sl_regmap_bus, + priv, &bno055_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&serdev->dev, "Unable to init register map"); + return PTR_ERR(regmap); + } + + return bno055_probe(&serdev->dev, regmap, + BNO055_SL_XFER_BURST_BREAK_THRESHOLD); +} + +static const struct of_device_id bno055_sl_of_match[] = { + { .compatible = "bosch,bno055" }, + { } +}; +MODULE_DEVICE_TABLE(of, bno055_sl_of_match); + +static struct serdev_device_driver bno055_sl_driver = { + .driver = { + .name = "bno055-sl", + .of_match_table = bno055_sl_of_match, + }, + .probe = bno055_sl_probe, +}; +module_serdev_device_driver(bno055_sl_driver); + +MODULE_AUTHOR("Andrea Merello <andrea.merello@iit.it>"); +MODULE_DESCRIPTION("Bosch BNO055 serdev interface"); +MODULE_LICENSE("GPL v2"); -- 2.17.1 ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 09/10] iio: imu: add BNO055 serdev driver 2021-10-28 10:18 ` [v2 09/10] iio: imu: add BNO055 serdev driver Andrea Merello @ 2021-10-28 12:31 ` Jonathan Cameron 2021-11-09 15:33 ` Andrea Merello 2021-10-29 7:09 ` kernel test robot 2021-10-29 12:59 ` kernel test robot 2 siblings, 1 reply; 55+ messages in thread From: Jonathan Cameron @ 2021-10-28 12:31 UTC (permalink / raw) To: Andrea Merello Cc: mchehab+huawei, linux-iio, linux-kernel, devicetree, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello On Thu, 28 Oct 2021 12:18:39 +0200 Andrea Merello <andrea.merello@gmail.com> wrote: > This path adds a serdev driver for communicating to a BNO055 IMU via > serial bus, and it enables the BNO055 core driver to work in this > scenario. > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> Hi Andrea, Some comments inline. Note I'm not that familiar with the serial_dev interface so would definitely appreciate input from others on that part. Jonathan > --- > drivers/iio/imu/bno055/Kconfig | 5 + > drivers/iio/imu/bno055/Makefile | 1 + > drivers/iio/imu/bno055/bno055_sl.c | 568 +++++++++++++++++++++++++++++ > 3 files changed, 574 insertions(+) > create mode 100644 drivers/iio/imu/bno055/bno055_sl.c > > diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig > index d197310661af..941e43f0368d 100644 > --- a/drivers/iio/imu/bno055/Kconfig > +++ b/drivers/iio/imu/bno055/Kconfig > @@ -2,3 +2,8 @@ > > config BOSH_BNO055_IIO > tristate > + > +config BOSH_BNO055_SERIAL > + tristate "Bosh BNO055 attached via serial bus" > + depends on SERIAL_DEV_BUS > + select BOSH_BNO055_IIO > diff --git a/drivers/iio/imu/bno055/Makefile b/drivers/iio/imu/bno055/Makefile > index c55741d0e96f..7285ade2f4b9 100644 > --- a/drivers/iio/imu/bno055/Makefile > +++ b/drivers/iio/imu/bno055/Makefile > @@ -1,3 +1,4 @@ > # SPDX-License-Identifier: GPL-2.0 > > obj-$(CONFIG_BOSH_BNO055_IIO) += bno055.o > +obj-$(CONFIG_BOSH_BNO055_SERIAL) += bno055_sl.o > diff --git a/drivers/iio/imu/bno055/bno055_sl.c b/drivers/iio/imu/bno055/bno055_sl.c > new file mode 100644 > index 000000000000..1d1410fdaa7c > --- /dev/null > +++ b/drivers/iio/imu/bno055/bno055_sl.c > @@ -0,0 +1,568 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Serial line interface for Bosh BNO055 IMU (via serdev). > + * This file implements serial communication up to the register read/write > + * level. > + * > + * Copyright (C) 2021 Istituto Italiano di Tecnologia > + * Electronic Design Laboratory > + * Written by Andrea Merello <andrea.merello@iit.it> > + * > + * This driver is besed on > + * Plantower PMS7003 particulate matter sensor driver > + * Which is > + * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com> > + */ > + > +#include <linux/completion.h> > +#include <linux/device.h> > +#include <linux/errno.h> > +#include <linux/jiffies.h> > +#include <linux/kernel.h> > +#include <linux/mod_devicetable.h> > +#include <linux/module.h> > +#include <linux/mutex.h> > +#include <linux/regmap.h> > +#include <linux/serdev.h> > + > +#include "bno055.h" > + > +/* > + * Register writes cmd have the following format > + * +------+------+-----+-----+----- ... ----+ > + * | 0xAA | 0xOO | REG | LEN | payload[LEN] | > + * +------+------+-----+-----+----- ... ----+ > + * > + * Register write responses have the following format > + * +------+----------+ > + * | 0xEE | ERROCODE | > + * +------+----------+ > + * > + * Register read have the following format > + * +------+------+-----+-----+ > + * | 0xAA | 0xO1 | REG | LEN | > + * +------+------+-----+-----+ > + * > + * Successful register read response have the following format > + * +------+-----+----- ... ----+ > + * | 0xBB | LEN | payload[LEN] | > + * +------+-----+----- ... ----+ > + * > + * Failed register read response have the following format > + * +------+--------+ > + * | 0xEE | ERRCODE| (ERRCODE always > 1) > + * +------+--------+ > + * > + * Error codes are > + * 01: OK > + * 02: read/write FAIL > + * 04: invalid address > + * 05: write on RO > + * 06: wrong start byte > + * 07: bus overrun > + * 08: len too high > + * 09: len too low > + * 10: bus RX byte timeout (timeout is 30mS) > + * > + * > + * **WORKAROUND ALERT** > + * > + * Serial communication seems very fragile: the BNO055 buffer seems to overflow > + * very easy; BNO055 seems able to sink few bytes, then it needs a brief pause. > + * On the other hand, it is also picky on timeout: if there is a pause > 30mS in > + * between two bytes then the transaction fails (IMU internal RX FSM resets). > + * > + * BMU055 has been seen also failing to process commands in case we send them > + * too close each other (or if it is somehow busy?) > + * > + * One idea would be to split data in chunks, and then wait 1-2mS between > + * chunks (we hope not to exceed 30mS delay for any reason - which should > + * be pretty a lot of time for us), and eventually retry in case the BNO055 > + * gets upset for any reason. This seems to work in avoiding the overflow > + * errors, but indeed it seems slower than just perform a retry when an overflow > + * error occur. > + * In particular I saw these scenarios: > + * 1) If we send 2 bytes per time, then the IMU never(?) overflows. > + * 2) If we send 4 bytes per time (i.e. the full header), then the IMU could > + * overflow, but it seem to sink all 4 bytes, then it returns error. > + * 3) If we send more than 4 bytes, the IMU could overflow, and I saw it sending > + * error after 4 bytes are sent; we have troubles in synchronizing again, > + * because we are still sending data, and the IMU interprets it as the 1st > + * byte of a new command. > + * > + * So, we workaround all this in the following way: > + * In case of read we don't split the header but we rely on retries; This seems > + * convenient for data read (where we TX only the hdr). > + * For TX we split the transmission in 2-bytes chunks so that, we should not > + * only avoid case 2 (which is still manageable), but we also hopefully avoid > + * case 3, that would be by far worse. > + */ > + > +/* > + * Read operation overhead: > + * 4 bytes req + 2byte resp hdr. > + * 6 bytes = 60 bit (considering 1start + 1stop bits). > + * 60/115200 = ~520uS. > + * > + * In 520uS we could read back about 34 bytes that means 3 samples, this means > + * that in case of scattered read in which the gap is 3 samples or less it is > + * still convenient to go for a burst. > + * We have to take into account also IMU response time - IMU seems to be often > + * reasonably quick to respond, but sometimes it seems to be in some "critical > + * section" in which it delays handling of serial protocol. > + * By experiment, it seems convenient to burst up to about 5/6-samples-long gap. > + */ > + > +#define BNO055_SL_XFER_BURST_BREAK_THRESHOLD 6 > + > +struct bno055_sl_priv { > + struct serdev_device *serdev; > + struct completion cmd_complete; > + enum { > + CMD_NONE, > + CMD_READ, > + CMD_WRITE, > + } expect_response; > + int expected_data_len; > + u8 *response_buf; > + > + /** > + * enum cmd_status - represent the status of a command sent to the HW. > + * @STATUS_OK: The command executed successfully. > + * @STATUS_FAIL: The command failed: HW responded with an error. > + * @STATUS_CRIT: The command failed: the serial communication failed. > + */ > + enum { > + STATUS_OK = 0, > + STATUS_FAIL = 1, > + STATUS_CRIT = -1 > + } cmd_status; > + struct mutex lock; > + > + /* Only accessed in behalf of RX callback context. No lock needed. */ would "Only accessed in RX callback context. No lock needed." convey the same meaning? > + struct { > + enum { > + RX_IDLE, > + RX_START, > + RX_DATA > + } state; > + int databuf_count; > + int expected_len; > + int type; > + } rx; > + > + /* Never accessed in behalf of RX callback context. No lock needed */ > + bool cmd_stale; > +}; > + > +static int bno055_sl_send_chunk(struct bno055_sl_priv *priv, u8 *data, int len) > +{ > + int ret; > + > + dev_dbg(&priv->serdev->dev, "send (len: %d): %*ph", len, len, data); > + ret = serdev_device_write(priv->serdev, data, len, > + msecs_to_jiffies(25)); > + if (ret < 0) > + return ret; > + > + if (ret < len) > + return -EIO; > + > + return 0; > +} > + > +/* > + * Sends a read or write command. > + * 'data' can be NULL (used in read case). 'len' parameter is always valid; in > + * case 'data' is non-NULL then it must match 'data' size. > + */ > +static int bno055_sl_do_send_cmd(struct bno055_sl_priv *priv, > + int read, int addr, int len, u8 *data) Read is a bool, so give it that type. > +{ > + int ret; > + int chunk_len; > + u8 hdr[] = {0xAA, !!read, addr, len}; > + > + if (read) { > + ret = bno055_sl_send_chunk(priv, hdr, 4); > + } else { > + ret = bno055_sl_send_chunk(priv, hdr, 2); > + if (ret) > + goto fail; > + > + usleep_range(2000, 3000); > + ret = bno055_sl_send_chunk(priv, hdr + 2, 2); > + } > + if (ret) > + goto fail; > + > + if (data) { I would flip this condition to reduce indent and make it easy to see we are done in the no 'data' case. Also, does this correspond in all cases to read? If so I would use that as the variable to check. if (!data) return 0; while (len) { ... > + while (len) { > + chunk_len = min(len, 2); > + usleep_range(2000, 3000); > + ret = bno055_sl_send_chunk(priv, data, chunk_len); > + if (ret) > + goto fail; > + data += chunk_len; > + len -= chunk_len; > + } > + } > + > + return 0; > +fail: > + /* waiting more than 30mS should clear the BNO055 internal state */ > + usleep_range(40000, 50000); > + return ret; > +} > + > +static int bno_sl_send_cmd(struct bno055_sl_priv *priv, > + int read, int addr, int len, u8 *data) Read looks to be a bool to me not an integer. > +{ > + const int retry_max = 5; > + int retry = retry_max; > + int ret = 0; > + > + /* > + * In case previous command was interrupted we still neet to wait it to > + * complete before we can issue new commands > + */ > + if (priv->cmd_stale) { > + ret = wait_for_completion_interruptible_timeout(&priv->cmd_complete, > + msecs_to_jiffies(100)); > + if (ret == -ERESTARTSYS) > + return -ERESTARTSYS; > + > + priv->cmd_stale = false; > + /* if serial protocol broke, bail out */ > + if (priv->cmd_status == STATUS_CRIT) > + goto exit; return -EIO; > + } > + > + /* > + * Try to convince the IMU to cooperate.. as explained in the comments > + * at the top of this file, the IMU could also refuse the command (i.e. > + * it is not ready yet); retry in this case. > + */ > + while (retry--) { > + mutex_lock(&priv->lock); > + priv->expect_response = read ? CMD_READ : CMD_WRITE; > + reinit_completion(&priv->cmd_complete); > + mutex_unlock(&priv->lock); > + > + if (retry != (retry_max - 1)) > + dev_dbg(&priv->serdev->dev, "cmd retry: %d", > + retry_max - retry); > + ret = bno055_sl_do_send_cmd(priv, read, addr, len, data); > + if (ret) > + continue; > + > + ret = wait_for_completion_interruptible_timeout(&priv->cmd_complete, > + msecs_to_jiffies(100)); > + if (ret == -ERESTARTSYS) { > + priv->cmd_stale = true; > + return -ERESTARTSYS; > + } else if (!ret) { > + ret = -ETIMEDOUT; return -ETIMEDOUT; > + break; > + } > + ret = 0; > + > + /* > + * Poll if the IMU returns error (i.e busy), break if the IMU > + * returns OK or if the serial communication broke > + */ > + if (priv->cmd_status <= 0) I 'think' this is only place we can break out with status set to anything (with the suggested modifications above) so move the if statements from the error path here and drop the ret = 0 above. > + break; > + } > + > +exit: > + if (ret) > + return ret; > + if (priv->cmd_status == STATUS_CRIT) > + return -EIO; > + if (priv->cmd_status == STATUS_FAIL) > + return -EINVAL; > + return 0; > +} > + > +static int bno055_sl_write_reg(void *context, const void *data, size_t count) > +{ > + int ret; > + int reg; > + u8 *write_data = (u8 *)data + 1; Given you dereference data as a u8 * in several places, perhaps a local variable to allow you to do it once. > + struct bno055_sl_priv *priv = context; > + > + if (count < 2) { > + dev_err(&priv->serdev->dev, "Invalid write count %zu", count); > + return -EINVAL; > + } > + > + reg = ((u8 *)data)[0]; > + dev_dbg(&priv->serdev->dev, "wr reg 0x%x = 0x%x", reg, ((u8 *)data)[1]); > + ret = bno_sl_send_cmd(priv, 0, reg, count - 1, write_data); > + > + return ret; return bno_sl_send_cmd(...) > +} > + > +static int bno055_sl_read_reg(void *context, > + const void *reg, size_t reg_size, > + void *val, size_t val_size) > +{ > + int ret; > + int reg_addr; > + struct bno055_sl_priv *priv = context; > + > + if (val_size > 128) { > + dev_err(&priv->serdev->dev, "Invalid read valsize %d", > + val_size); > + return -EINVAL; > + } > + > + reg_addr = ((u8 *)reg)[0]; > + dev_dbg(&priv->serdev->dev, "rd reg 0x%x (len %d)", reg_addr, val_size); > + mutex_lock(&priv->lock); > + priv->expected_data_len = val_size; > + priv->response_buf = val; > + mutex_unlock(&priv->lock); > + > + ret = bno_sl_send_cmd(priv, 1, reg_addr, val_size, NULL); > + > + mutex_lock(&priv->lock); > + priv->response_buf = NULL; > + mutex_unlock(&priv->lock); > + > + return ret; > +} > + > +/* > + * Handler for received data; this is called from the reicever callback whenever > + * it got some packet from the serial bus. The status tell us whether the > + * packet is valid (i.e. header ok && received payload len consistent wrt the > + * header). It's now our responsability to check whether this is what we > + * expected, of whether we got some unexpected, yet valid, packet. > + */ > +static void bno055_sl_handle_rx(struct bno055_sl_priv *priv, int status) > +{ > + mutex_lock(&priv->lock); > + switch (priv->expect_response) { > + case CMD_NONE: > + dev_warn(&priv->serdev->dev, "received unexpected, yet valid, data from sensor"); > + mutex_unlock(&priv->lock); > + return; > + > + case CMD_READ: > + priv->cmd_status = status; > + if (status == STATUS_OK && > + priv->rx.databuf_count != priv->expected_data_len) { > + /* > + * If we got here, then the lower layer serial protocol > + * seems consistent with itself; if we got an unexpected > + * amount of data then signal it as a non critical error > + */ > + priv->cmd_status = STATUS_FAIL; > + dev_warn(&priv->serdev->dev, "received an unexpected amount of, yet valid, data from sensor"); > + } > + break; > + > + case CMD_WRITE: > + priv->cmd_status = status; > + break; > + } > + > + priv->expect_response = CMD_NONE; > + complete(&priv->cmd_complete); > + mutex_unlock(&priv->lock); > +} > + > +/* > + * Serdev receiver FSM. This tracks the serial communication and parse the > + * header. It pushes packets to bno055_sl_handle_rx(), eventually communicating > + * failures (i.e. malformed packets). > + * Ideally it doesn't know anything about upper layer (i.e. if this is the > + * packet we were really expecting), but since we copies the payload into the > + * receiver buffer (that is not valid when i.e. we don't expect data), we > + * snoop a bit in the upper layer.. > + * Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything > + * unless we require to AND we don't queue more than one request per time). > + */ > +static int bno055_sl_receive_buf(struct serdev_device *serdev, > + const unsigned char *buf, size_t size) > +{ > + int status; > + struct bno055_sl_priv *priv = serdev_device_get_drvdata(serdev); > + int _size = size; Why the local variable? > + > + if (size == 0) > + return 0; > + > + dev_dbg(&priv->serdev->dev, "recv (len %zu): %*ph ", size, size, buf); > + switch (priv->rx.state) { > + case RX_IDLE: > + /* > + * New packet. > + * Check for its 1st byte, that identifies the pkt type. > + */ > + if (buf[0] != 0xEE && buf[0] != 0xBB) { > + dev_err(&priv->serdev->dev, > + "Invalid packet start %x", buf[0]); > + bno055_sl_handle_rx(priv, STATUS_CRIT); > + break; > + } > + priv->rx.type = buf[0]; > + priv->rx.state = RX_START; > + size--; > + buf++; > + priv->rx.databuf_count = 0; > + fallthrough; > + > + case RX_START: > + /* > + * Packet RX in progress, we expect either 1-byte len or 1-byte > + * status depending by the packet type. > + */ > + if (size == 0) > + break; > + > + if (priv->rx.type == 0xEE) { > + if (size > 1) { > + dev_err(&priv->serdev->dev, "EE pkt. Extra data received"); > + status = STATUS_CRIT; > + > + } else { > + status = (buf[0] == 1) ? STATUS_OK : STATUS_FAIL; > + } > + bno055_sl_handle_rx(priv, status); > + priv->rx.state = RX_IDLE; > + break; > + > + } else { > + /*priv->rx.type == 0xBB */ > + priv->rx.state = RX_DATA; > + priv->rx.expected_len = buf[0]; > + size--; > + buf++; > + } > + fallthrough; > + > + case RX_DATA: > + /* Header parsed; now receiving packet data payload */ > + if (size == 0) > + break; > + > + if (priv->rx.databuf_count + size > priv->rx.expected_len) { > + /* > + * This is a inconsistency in serial protocol, we lost > + * sync and we don't know how to handle further data > + */ > + dev_err(&priv->serdev->dev, "BB pkt. Extra data received"); > + bno055_sl_handle_rx(priv, STATUS_CRIT); > + priv->rx.state = RX_IDLE; > + break; > + } > + > + mutex_lock(&priv->lock); > + /* > + * NULL e.g. when read cmd is stale or when no read cmd is > + * actually pending. > + */ > + if (priv->response_buf && > + /* > + * Snoop on the upper layer protocol stuff to make sure not > + * to write to an invalid memory. Apart for this, let's the > + * upper layer manage any inconsistency wrt expected data > + * len (as long as the serial protocol is consistent wrt > + * itself (i.e. response header is consistent with received > + * response len. > + */ > + (priv->rx.databuf_count + size <= priv->expected_data_len)) > + memcpy(priv->response_buf + priv->rx.databuf_count, > + buf, size); > + mutex_unlock(&priv->lock); > + > + priv->rx.databuf_count += size; > + > + /* > + * Reached expected len advertised by the IMU for the current > + * packet. Pass it to the upper layer (for us it is just valid). > + */ > + if (priv->rx.databuf_count == priv->rx.expected_len) { > + bno055_sl_handle_rx(priv, STATUS_OK); > + priv->rx.state = RX_IDLE; > + } > + break; > + } > + > + return _size; > +} > + > +static const struct serdev_device_ops bno055_sl_serdev_ops = { > + .receive_buf = bno055_sl_receive_buf, > + .write_wakeup = serdev_device_write_wakeup, > +}; > + > +static struct regmap_bus bno055_sl_regmap_bus = { > + .write = bno055_sl_write_reg, > + .read = bno055_sl_read_reg, > +}; > + > +static int bno055_sl_probe(struct serdev_device *serdev) > +{ > + struct bno055_sl_priv *priv; > + struct regmap *regmap; > + int ret; > + > + priv = devm_kzalloc(&serdev->dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + serdev_device_set_drvdata(serdev, priv); > + priv->serdev = serdev; > + mutex_init(&priv->lock); > + init_completion(&priv->cmd_complete); > + > + serdev_device_set_client_ops(serdev, &bno055_sl_serdev_ops); > + ret = devm_serdev_device_open(&serdev->dev, serdev); > + if (ret) > + return ret; > + > + if (serdev_device_set_baudrate(serdev, 115200) != 115200) { > + dev_err(&serdev->dev, "Cannot set required baud rate"); > + return -EIO; > + } > + > + ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); > + if (ret) { > + dev_err(&serdev->dev, "Cannot set required parity setting"); > + return ret; > + } > + serdev_device_set_flow_control(serdev, false); > + > + regmap = devm_regmap_init(&serdev->dev, &bno055_sl_regmap_bus, > + priv, &bno055_regmap_config); > + if (IS_ERR(regmap)) { > + dev_err(&serdev->dev, "Unable to init register map"); > + return PTR_ERR(regmap); > + } > + > + return bno055_probe(&serdev->dev, regmap, > + BNO055_SL_XFER_BURST_BREAK_THRESHOLD); > +} > + > +static const struct of_device_id bno055_sl_of_match[] = { > + { .compatible = "bosch,bno055" }, > + { } > +}; > +MODULE_DEVICE_TABLE(of, bno055_sl_of_match); > + > +static struct serdev_device_driver bno055_sl_driver = { > + .driver = { > + .name = "bno055-sl", > + .of_match_table = bno055_sl_of_match, > + }, > + .probe = bno055_sl_probe, > +}; > +module_serdev_device_driver(bno055_sl_driver); > + > +MODULE_AUTHOR("Andrea Merello <andrea.merello@iit.it>"); > +MODULE_DESCRIPTION("Bosch BNO055 serdev interface"); > +MODULE_LICENSE("GPL v2"); ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 09/10] iio: imu: add BNO055 serdev driver 2021-10-28 12:31 ` Jonathan Cameron @ 2021-11-09 15:33 ` Andrea Merello 2021-11-14 16:37 ` Jonathan Cameron 0 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-11-09 15:33 UTC (permalink / raw) To: Jonathan Cameron Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello Few inline comments. Ok for all the rest. Il giorno gio 28 ott 2021 alle ore 14:27 Jonathan Cameron <jic23@kernel.org> ha scritto: > > On Thu, 28 Oct 2021 12:18:39 +0200 > Andrea Merello <andrea.merello@gmail.com> wrote: > > > This path adds a serdev driver for communicating to a BNO055 IMU via > > serial bus, and it enables the BNO055 core driver to work in this > > scenario. > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > Hi Andrea, > > Some comments inline. Note I'm not that familiar with the serial_dev interface > so would definitely appreciate input from others on that part. > > Jonathan > > --- > > drivers/iio/imu/bno055/Kconfig | 5 + > > drivers/iio/imu/bno055/Makefile | 1 + > > drivers/iio/imu/bno055/bno055_sl.c | 568 +++++++++++++++++++++++++++++ > > 3 files changed, 574 insertions(+) > > create mode 100644 drivers/iio/imu/bno055/bno055_sl.c > > > > diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig > > index d197310661af..941e43f0368d 100644 > > --- a/drivers/iio/imu/bno055/Kconfig > > +++ b/drivers/iio/imu/bno055/Kconfig > > @@ -2,3 +2,8 @@ > > > > config BOSH_BNO055_IIO > > tristate > > + > > +config BOSH_BNO055_SERIAL > > + tristate "Bosh BNO055 attached via serial bus" > > + depends on SERIAL_DEV_BUS > > + select BOSH_BNO055_IIO > > diff --git a/drivers/iio/imu/bno055/Makefile b/drivers/iio/imu/bno055/Makefile > > index c55741d0e96f..7285ade2f4b9 100644 > > --- a/drivers/iio/imu/bno055/Makefile > > +++ b/drivers/iio/imu/bno055/Makefile > > @@ -1,3 +1,4 @@ > > # SPDX-License-Identifier: GPL-2.0 > > > > obj-$(CONFIG_BOSH_BNO055_IIO) += bno055.o > > +obj-$(CONFIG_BOSH_BNO055_SERIAL) += bno055_sl.o > > diff --git a/drivers/iio/imu/bno055/bno055_sl.c b/drivers/iio/imu/bno055/bno055_sl.c > > new file mode 100644 > > index 000000000000..1d1410fdaa7c > > --- /dev/null > > +++ b/drivers/iio/imu/bno055/bno055_sl.c > > @@ -0,0 +1,568 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Serial line interface for Bosh BNO055 IMU (via serdev). > > + * This file implements serial communication up to the register read/write > > + * level. > > + * > > + * Copyright (C) 2021 Istituto Italiano di Tecnologia > > + * Electronic Design Laboratory > > + * Written by Andrea Merello <andrea.merello@iit.it> > > + * > > + * This driver is besed on > > + * Plantower PMS7003 particulate matter sensor driver > > + * Which is > > + * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com> > > + */ > > + > > +#include <linux/completion.h> > > +#include <linux/device.h> > > +#include <linux/errno.h> > > +#include <linux/jiffies.h> > > +#include <linux/kernel.h> > > +#include <linux/mod_devicetable.h> > > +#include <linux/module.h> > > +#include <linux/mutex.h> > > +#include <linux/regmap.h> > > +#include <linux/serdev.h> > > + > > +#include "bno055.h" > > + > > +/* > > + * Register writes cmd have the following format > > + * +------+------+-----+-----+----- ... ----+ > > + * | 0xAA | 0xOO | REG | LEN | payload[LEN] | > > + * +------+------+-----+-----+----- ... ----+ > > + * > > + * Register write responses have the following format > > + * +------+----------+ > > + * | 0xEE | ERROCODE | > > + * +------+----------+ > > + * > > + * Register read have the following format > > + * +------+------+-----+-----+ > > + * | 0xAA | 0xO1 | REG | LEN | > > + * +------+------+-----+-----+ > > + * > > + * Successful register read response have the following format > > + * +------+-----+----- ... ----+ > > + * | 0xBB | LEN | payload[LEN] | > > + * +------+-----+----- ... ----+ > > + * > > + * Failed register read response have the following format > > + * +------+--------+ > > + * | 0xEE | ERRCODE| (ERRCODE always > 1) > > + * +------+--------+ > > + * > > + * Error codes are > > + * 01: OK > > + * 02: read/write FAIL > > + * 04: invalid address > > + * 05: write on RO > > + * 06: wrong start byte > > + * 07: bus overrun > > + * 08: len too high > > + * 09: len too low > > + * 10: bus RX byte timeout (timeout is 30mS) > > + * > > + * > > + * **WORKAROUND ALERT** > > + * > > + * Serial communication seems very fragile: the BNO055 buffer seems to overflow > > + * very easy; BNO055 seems able to sink few bytes, then it needs a brief pause. > > + * On the other hand, it is also picky on timeout: if there is a pause > 30mS in > > + * between two bytes then the transaction fails (IMU internal RX FSM resets). > > + * > > + * BMU055 has been seen also failing to process commands in case we send them > > + * too close each other (or if it is somehow busy?) > > + * > > + * One idea would be to split data in chunks, and then wait 1-2mS between > > + * chunks (we hope not to exceed 30mS delay for any reason - which should > > + * be pretty a lot of time for us), and eventually retry in case the BNO055 > > + * gets upset for any reason. This seems to work in avoiding the overflow > > + * errors, but indeed it seems slower than just perform a retry when an overflow > > + * error occur. > > + * In particular I saw these scenarios: > > + * 1) If we send 2 bytes per time, then the IMU never(?) overflows. > > + * 2) If we send 4 bytes per time (i.e. the full header), then the IMU could > > + * overflow, but it seem to sink all 4 bytes, then it returns error. > > + * 3) If we send more than 4 bytes, the IMU could overflow, and I saw it sending > > + * error after 4 bytes are sent; we have troubles in synchronizing again, > > + * because we are still sending data, and the IMU interprets it as the 1st > > + * byte of a new command. > > + * > > + * So, we workaround all this in the following way: > > + * In case of read we don't split the header but we rely on retries; This seems > > + * convenient for data read (where we TX only the hdr). > > + * For TX we split the transmission in 2-bytes chunks so that, we should not > > + * only avoid case 2 (which is still manageable), but we also hopefully avoid > > + * case 3, that would be by far worse. > > + */ > > + > > +/* > > + * Read operation overhead: > > + * 4 bytes req + 2byte resp hdr. > > + * 6 bytes = 60 bit (considering 1start + 1stop bits). > > + * 60/115200 = ~520uS. > > + * > > + * In 520uS we could read back about 34 bytes that means 3 samples, this means > > + * that in case of scattered read in which the gap is 3 samples or less it is > > + * still convenient to go for a burst. > > + * We have to take into account also IMU response time - IMU seems to be often > > + * reasonably quick to respond, but sometimes it seems to be in some "critical > > + * section" in which it delays handling of serial protocol. > > + * By experiment, it seems convenient to burst up to about 5/6-samples-long gap. > > + */ > > + > > +#define BNO055_SL_XFER_BURST_BREAK_THRESHOLD 6 > > + > > +struct bno055_sl_priv { > > + struct serdev_device *serdev; > > + struct completion cmd_complete; > > + enum { > > + CMD_NONE, > > + CMD_READ, > > + CMD_WRITE, > > + } expect_response; > > + int expected_data_len; > > + u8 *response_buf; > > + > > + /** > > + * enum cmd_status - represent the status of a command sent to the HW. > > + * @STATUS_OK: The command executed successfully. > > + * @STATUS_FAIL: The command failed: HW responded with an error. > > + * @STATUS_CRIT: The command failed: the serial communication failed. > > + */ > > + enum { > > + STATUS_OK = 0, > > + STATUS_FAIL = 1, > > + STATUS_CRIT = -1 > > + } cmd_status; > > + struct mutex lock; > > + > > + /* Only accessed in behalf of RX callback context. No lock needed. */ > > would "Only accessed in RX callback context. No lock needed." convey the same meaning? > > > + struct { > > + enum { > > + RX_IDLE, > > + RX_START, > > + RX_DATA > > + } state; > > + int databuf_count; > > + int expected_len; > > + int type; > > + } rx; > > + > > + /* Never accessed in behalf of RX callback context. No lock needed */ > > + bool cmd_stale; > > +}; > > + > > +static int bno055_sl_send_chunk(struct bno055_sl_priv *priv, u8 *data, int len) > > +{ > > + int ret; > > + > > + dev_dbg(&priv->serdev->dev, "send (len: %d): %*ph", len, len, data); > > + ret = serdev_device_write(priv->serdev, data, len, > > + msecs_to_jiffies(25)); > > + if (ret < 0) > > + return ret; > > + > > + if (ret < len) > > + return -EIO; > > + > > + return 0; > > +} > > + > > +/* > > + * Sends a read or write command. > > + * 'data' can be NULL (used in read case). 'len' parameter is always valid; in > > + * case 'data' is non-NULL then it must match 'data' size. > > + */ > > +static int bno055_sl_do_send_cmd(struct bno055_sl_priv *priv, > > + int read, int addr, int len, u8 *data) > > Read is a bool, so give it that type. > > > +{ > > + int ret; > > + int chunk_len; > > + u8 hdr[] = {0xAA, !!read, addr, len}; > > + > > + if (read) { > > + ret = bno055_sl_send_chunk(priv, hdr, 4); > > + } else { > > + ret = bno055_sl_send_chunk(priv, hdr, 2); > > + if (ret) > > + goto fail; > > + > > + usleep_range(2000, 3000); > > + ret = bno055_sl_send_chunk(priv, hdr + 2, 2); > > + } > > + if (ret) > > + goto fail; > > + > > + if (data) { > > I would flip this condition to reduce indent and make it easy to > see we are done in the no 'data' case. Also, does this correspond in > all cases to read? If so I would use that as the variable to check. > > if (!data) > return 0; > > while (len) { > ... > > > > + while (len) { > > + chunk_len = min(len, 2); > > + usleep_range(2000, 3000); > > + ret = bno055_sl_send_chunk(priv, data, chunk_len); > > + if (ret) > > + goto fail; > > + data += chunk_len; > > + len -= chunk_len; > > + } > > + } > > + > > + return 0; > > +fail: > > + /* waiting more than 30mS should clear the BNO055 internal state */ > > + usleep_range(40000, 50000); > > + return ret; > > +} > > + > > +static int bno_sl_send_cmd(struct bno055_sl_priv *priv, > > + int read, int addr, int len, u8 *data) > > Read looks to be a bool to me not an integer. > > > +{ > > + const int retry_max = 5; > > + int retry = retry_max; > > + int ret = 0; > > + > > + /* > > + * In case previous command was interrupted we still neet to wait it to > > + * complete before we can issue new commands > > + */ > > + if (priv->cmd_stale) { > > + ret = wait_for_completion_interruptible_timeout(&priv->cmd_complete, > > + msecs_to_jiffies(100)); > > + if (ret == -ERESTARTSYS) > > + return -ERESTARTSYS; > > + > > + priv->cmd_stale = false; > > + /* if serial protocol broke, bail out */ > > + if (priv->cmd_status == STATUS_CRIT) > > + goto exit; > > return -EIO; > > > + } > > + > > + /* > > + * Try to convince the IMU to cooperate.. as explained in the comments > > + * at the top of this file, the IMU could also refuse the command (i.e. > > + * it is not ready yet); retry in this case. > > + */ > > + while (retry--) { > > + mutex_lock(&priv->lock); > > + priv->expect_response = read ? CMD_READ : CMD_WRITE; > > + reinit_completion(&priv->cmd_complete); > > + mutex_unlock(&priv->lock); > > + > > + if (retry != (retry_max - 1)) > > + dev_dbg(&priv->serdev->dev, "cmd retry: %d", > > + retry_max - retry); > > + ret = bno055_sl_do_send_cmd(priv, read, addr, len, data); > > + if (ret) > > + continue; > > + > > + ret = wait_for_completion_interruptible_timeout(&priv->cmd_complete, > > + msecs_to_jiffies(100)); > > + if (ret == -ERESTARTSYS) { > > + priv->cmd_stale = true; > > + return -ERESTARTSYS; > > + } else if (!ret) { > > + ret = -ETIMEDOUT; > > return -ETIMEDOUT; > > > + break; > > + } > > + ret = 0; > > + > > + /* > > + * Poll if the IMU returns error (i.e busy), break if the IMU > > + * returns OK or if the serial communication broke > > + */ > > + if (priv->cmd_status <= 0) > I 'think' this is only place we can break out with status set to anything (with > the suggested modifications above) so move the if statements from the error path > here and drop the ret = 0 above. Hum. Looks like it always break here. Probably it's correct but the loop can be reduced just up to the "continue" or something like that. Have to rework this. > > > + break; > > + } > > + > > +exit: > > + if (ret) > > + return ret; > > + if (priv->cmd_status == STATUS_CRIT) > > + return -EIO; > > + if (priv->cmd_status == STATUS_FAIL) > > + return -EINVAL; > > + return 0; > > +} > > + > > +static int bno055_sl_write_reg(void *context, const void *data, size_t count) > > +{ > > + int ret; > > + int reg; > > + u8 *write_data = (u8 *)data + 1; > > Given you dereference data as a u8 * in several places, perhaps a local > variable to allow you to do it once. > > > + struct bno055_sl_priv *priv = context; > > + > > + if (count < 2) { > > + dev_err(&priv->serdev->dev, "Invalid write count %zu", count); > > + return -EINVAL; > > + } > > + > > + reg = ((u8 *)data)[0]; > > + dev_dbg(&priv->serdev->dev, "wr reg 0x%x = 0x%x", reg, ((u8 *)data)[1]); > > + ret = bno_sl_send_cmd(priv, 0, reg, count - 1, write_data); > > + > > + return ret; > > return bno_sl_send_cmd(...) > > > +} > > + > > +static int bno055_sl_read_reg(void *context, > > + const void *reg, size_t reg_size, > > + void *val, size_t val_size) > > +{ > > + int ret; > > + int reg_addr; > > + struct bno055_sl_priv *priv = context; > > + > > + if (val_size > 128) { > > + dev_err(&priv->serdev->dev, "Invalid read valsize %d", > > + val_size); > > + return -EINVAL; > > + } > > + > > + reg_addr = ((u8 *)reg)[0]; > > + dev_dbg(&priv->serdev->dev, "rd reg 0x%x (len %d)", reg_addr, val_size); > > + mutex_lock(&priv->lock); > > + priv->expected_data_len = val_size; > > + priv->response_buf = val; > > + mutex_unlock(&priv->lock); > > + > > + ret = bno_sl_send_cmd(priv, 1, reg_addr, val_size, NULL); > > + > > + mutex_lock(&priv->lock); > > + priv->response_buf = NULL; > > + mutex_unlock(&priv->lock); > > + > > + return ret; > > +} > > + > > +/* > > + * Handler for received data; this is called from the reicever callback whenever > > + * it got some packet from the serial bus. The status tell us whether the > > + * packet is valid (i.e. header ok && received payload len consistent wrt the > > + * header). It's now our responsability to check whether this is what we > > + * expected, of whether we got some unexpected, yet valid, packet. > > + */ > > +static void bno055_sl_handle_rx(struct bno055_sl_priv *priv, int status) > > +{ > > + mutex_lock(&priv->lock); > > + switch (priv->expect_response) { > > + case CMD_NONE: > > + dev_warn(&priv->serdev->dev, "received unexpected, yet valid, data from sensor"); > > + mutex_unlock(&priv->lock); > > + return; > > + > > + case CMD_READ: > > + priv->cmd_status = status; > > + if (status == STATUS_OK && > > + priv->rx.databuf_count != priv->expected_data_len) { > > + /* > > + * If we got here, then the lower layer serial protocol > > + * seems consistent with itself; if we got an unexpected > > + * amount of data then signal it as a non critical error > > + */ > > + priv->cmd_status = STATUS_FAIL; > > + dev_warn(&priv->serdev->dev, "received an unexpected amount of, yet valid, data from sensor"); > > + } > > + break; > > + > > + case CMD_WRITE: > > + priv->cmd_status = status; > > + break; > > + } > > + > > + priv->expect_response = CMD_NONE; > > + complete(&priv->cmd_complete); > > + mutex_unlock(&priv->lock); > > +} > > + > > +/* > > + * Serdev receiver FSM. This tracks the serial communication and parse the > > + * header. It pushes packets to bno055_sl_handle_rx(), eventually communicating > > + * failures (i.e. malformed packets). > > + * Ideally it doesn't know anything about upper layer (i.e. if this is the > > + * packet we were really expecting), but since we copies the payload into the > > + * receiver buffer (that is not valid when i.e. we don't expect data), we > > + * snoop a bit in the upper layer.. > > + * Also, we assume to RX one pkt per time (i.e. the HW doesn't send anything > > + * unless we require to AND we don't queue more than one request per time). > > + */ > > +static int bno055_sl_receive_buf(struct serdev_device *serdev, > > + const unsigned char *buf, size_t size) > > +{ > > + int status; > > + struct bno055_sl_priv *priv = serdev_device_get_drvdata(serdev); > > + int _size = size; > > Why the local variable? size variable gets modified, so we cache the value to return in case of success. > > + > > + if (size == 0) > > + return 0; > > + > > + dev_dbg(&priv->serdev->dev, "recv (len %zu): %*ph ", size, size, buf); > > + switch (priv->rx.state) { > > + case RX_IDLE: > > + /* > > + * New packet. > > + * Check for its 1st byte, that identifies the pkt type. > > + */ > > + if (buf[0] != 0xEE && buf[0] != 0xBB) { > > + dev_err(&priv->serdev->dev, > > + "Invalid packet start %x", buf[0]); > > + bno055_sl_handle_rx(priv, STATUS_CRIT); > > + break; > > + } > > + priv->rx.type = buf[0]; > > + priv->rx.state = RX_START; > > + size--; > > + buf++; > > + priv->rx.databuf_count = 0; > > + fallthrough; > > + > > + case RX_START: > > + /* > > + * Packet RX in progress, we expect either 1-byte len or 1-byte > > + * status depending by the packet type. > > + */ > > + if (size == 0) > > + break; > > + > > + if (priv->rx.type == 0xEE) { > > + if (size > 1) { > > + dev_err(&priv->serdev->dev, "EE pkt. Extra data received"); > > + status = STATUS_CRIT; > > + > > + } else { > > + status = (buf[0] == 1) ? STATUS_OK : STATUS_FAIL; > > + } > > + bno055_sl_handle_rx(priv, status); > > + priv->rx.state = RX_IDLE; > > + break; > > + > > + } else { > > + /*priv->rx.type == 0xBB */ > > + priv->rx.state = RX_DATA; > > + priv->rx.expected_len = buf[0]; > > + size--; > > + buf++; > > + } > > + fallthrough; > > + > > + case RX_DATA: > > + /* Header parsed; now receiving packet data payload */ > > + if (size == 0) > > + break; > > + > > + if (priv->rx.databuf_count + size > priv->rx.expected_len) { > > + /* > > + * This is a inconsistency in serial protocol, we lost > > + * sync and we don't know how to handle further data > > + */ > > + dev_err(&priv->serdev->dev, "BB pkt. Extra data received"); > > + bno055_sl_handle_rx(priv, STATUS_CRIT); > > + priv->rx.state = RX_IDLE; > > + break; > > + } > > + > > + mutex_lock(&priv->lock); > > + /* > > + * NULL e.g. when read cmd is stale or when no read cmd is > > + * actually pending. > > + */ > > + if (priv->response_buf && > > + /* > > + * Snoop on the upper layer protocol stuff to make sure not > > + * to write to an invalid memory. Apart for this, let's the > > + * upper layer manage any inconsistency wrt expected data > > + * len (as long as the serial protocol is consistent wrt > > + * itself (i.e. response header is consistent with received > > + * response len. > > + */ > > + (priv->rx.databuf_count + size <= priv->expected_data_len)) > > + memcpy(priv->response_buf + priv->rx.databuf_count, > > + buf, size); > > + mutex_unlock(&priv->lock); > > + > > + priv->rx.databuf_count += size; > > + > > + /* > > + * Reached expected len advertised by the IMU for the current > > + * packet. Pass it to the upper layer (for us it is just valid). > > + */ > > + if (priv->rx.databuf_count == priv->rx.expected_len) { > > + bno055_sl_handle_rx(priv, STATUS_OK); > > + priv->rx.state = RX_IDLE; > > + } > > + break; > > + } > > + > > + return _size; > > +} > > + > > +static const struct serdev_device_ops bno055_sl_serdev_ops = { > > + .receive_buf = bno055_sl_receive_buf, > > + .write_wakeup = serdev_device_write_wakeup, > > +}; > > + > > +static struct regmap_bus bno055_sl_regmap_bus = { > > + .write = bno055_sl_write_reg, > > + .read = bno055_sl_read_reg, > > +}; > > + > > +static int bno055_sl_probe(struct serdev_device *serdev) > > +{ > > + struct bno055_sl_priv *priv; > > + struct regmap *regmap; > > + int ret; > > + > > + priv = devm_kzalloc(&serdev->dev, sizeof(*priv), GFP_KERNEL); > > + if (!priv) > > + return -ENOMEM; > > + > > + serdev_device_set_drvdata(serdev, priv); > > + priv->serdev = serdev; > > + mutex_init(&priv->lock); > > + init_completion(&priv->cmd_complete); > > + > > + serdev_device_set_client_ops(serdev, &bno055_sl_serdev_ops); > > + ret = devm_serdev_device_open(&serdev->dev, serdev); > > + if (ret) > > + return ret; > > + > > + if (serdev_device_set_baudrate(serdev, 115200) != 115200) { > > + dev_err(&serdev->dev, "Cannot set required baud rate"); > > + return -EIO; > > + } > > + > > + ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); > > + if (ret) { > > + dev_err(&serdev->dev, "Cannot set required parity setting"); > > + return ret; > > + } > > + serdev_device_set_flow_control(serdev, false); > > + > > + regmap = devm_regmap_init(&serdev->dev, &bno055_sl_regmap_bus, > > + priv, &bno055_regmap_config); > > + if (IS_ERR(regmap)) { > > + dev_err(&serdev->dev, "Unable to init register map"); > > + return PTR_ERR(regmap); > > + } > > + > > + return bno055_probe(&serdev->dev, regmap, > > + BNO055_SL_XFER_BURST_BREAK_THRESHOLD); > > +} > > + > > +static const struct of_device_id bno055_sl_of_match[] = { > > + { .compatible = "bosch,bno055" }, > > + { } > > +}; > > +MODULE_DEVICE_TABLE(of, bno055_sl_of_match); > > + > > +static struct serdev_device_driver bno055_sl_driver = { > > + .driver = { > > + .name = "bno055-sl", > > + .of_match_table = bno055_sl_of_match, > > + }, > > + .probe = bno055_sl_probe, > > +}; > > +module_serdev_device_driver(bno055_sl_driver); > > + > > +MODULE_AUTHOR("Andrea Merello <andrea.merello@iit.it>"); > > +MODULE_DESCRIPTION("Bosch BNO055 serdev interface"); > > +MODULE_LICENSE("GPL v2"); > ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 09/10] iio: imu: add BNO055 serdev driver 2021-11-09 15:33 ` Andrea Merello @ 2021-11-14 16:37 ` Jonathan Cameron 0 siblings, 0 replies; 55+ messages in thread From: Jonathan Cameron @ 2021-11-14 16:37 UTC (permalink / raw) To: Andrea Merello Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On Tue, 9 Nov 2021 16:33:44 +0100 Andrea Merello <andrea.merello@gmail.com> wrote: ... > > > +static int bno055_sl_receive_buf(struct serdev_device *serdev, > > > + const unsigned char *buf, size_t size) > > > +{ > > > + int status; > > > + struct bno055_sl_priv *priv = serdev_device_get_drvdata(serdev); > > > + int _size = size; > > > > Why the local variable? > > size variable gets modified, so we cache the value to return in case of success. Ah - missed that as unusual way around. I'd modify the local variable instead and perhaps call it something like remaining to reflect how it is being used? > > > > + > > > + if (size == 0) > > > + return 0; > > > + > > > + dev_dbg(&priv->serdev->dev, "recv (len %zu): %*ph ", size, size, buf); > > > + switch (priv->rx.state) { > > > + case RX_IDLE: > > > + /* > > > + * New packet. > > > + * Check for its 1st byte, that identifies the pkt type. > > > + */ > > > + if (buf[0] != 0xEE && buf[0] != 0xBB) { > > > + dev_err(&priv->serdev->dev, > > > + "Invalid packet start %x", buf[0]); > > > + bno055_sl_handle_rx(priv, STATUS_CRIT); > > > + break; > > > + } > > > + priv->rx.type = buf[0]; > > > + priv->rx.state = RX_START; > > > + size--; > > > + buf++; > > > + priv->rx.databuf_count = 0; > > > + fallthrough; > > > + > > > + case RX_START: > > > + /* > > > + * Packet RX in progress, we expect either 1-byte len or 1-byte > > > + * status depending by the packet type. > > > + */ > > > + if (size == 0) > > > + break; > > > + > > > + if (priv->rx.type == 0xEE) { > > > + if (size > 1) { > > > + dev_err(&priv->serdev->dev, "EE pkt. Extra data received"); > > > + status = STATUS_CRIT; > > > + > > > + } else { > > > + status = (buf[0] == 1) ? STATUS_OK : STATUS_FAIL; > > > + } > > > + bno055_sl_handle_rx(priv, status); > > > + priv->rx.state = RX_IDLE; > > > + break; > > > + > > > + } else { > > > + /*priv->rx.type == 0xBB */ > > > + priv->rx.state = RX_DATA; > > > + priv->rx.expected_len = buf[0]; > > > + size--; > > > + buf++; > > > + } > > > + fallthrough; > > > + > > > + case RX_DATA: > > > + /* Header parsed; now receiving packet data payload */ > > > + if (size == 0) > > > + break; > > > + > > > + if (priv->rx.databuf_count + size > priv->rx.expected_len) { > > > + /* > > > + * This is a inconsistency in serial protocol, we lost > > > + * sync and we don't know how to handle further data > > > + */ > > > + dev_err(&priv->serdev->dev, "BB pkt. Extra data received"); > > > + bno055_sl_handle_rx(priv, STATUS_CRIT); > > > + priv->rx.state = RX_IDLE; > > > + break; > > > + } > > > + > > > + mutex_lock(&priv->lock); > > > + /* > > > + * NULL e.g. when read cmd is stale or when no read cmd is > > > + * actually pending. > > > + */ > > > + if (priv->response_buf && > > > + /* > > > + * Snoop on the upper layer protocol stuff to make sure not > > > + * to write to an invalid memory. Apart for this, let's the > > > + * upper layer manage any inconsistency wrt expected data > > > + * len (as long as the serial protocol is consistent wrt > > > + * itself (i.e. response header is consistent with received > > > + * response len. > > > + */ > > > + (priv->rx.databuf_count + size <= priv->expected_data_len)) > > > + memcpy(priv->response_buf + priv->rx.databuf_count, > > > + buf, size); > > > + mutex_unlock(&priv->lock); > > > + > > > + priv->rx.databuf_count += size; > > > + > > > + /* > > > + * Reached expected len advertised by the IMU for the current > > > + * packet. Pass it to the upper layer (for us it is just valid). > > > + */ > > > + if (priv->rx.databuf_count == priv->rx.expected_len) { > > > + bno055_sl_handle_rx(priv, STATUS_OK); > > > + priv->rx.state = RX_IDLE; > > > + } > > > + break; > > > + } > > > + > > > + return _size; > > > +} ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 09/10] iio: imu: add BNO055 serdev driver 2021-10-28 10:18 ` [v2 09/10] iio: imu: add BNO055 serdev driver Andrea Merello 2021-10-28 12:31 ` Jonathan Cameron @ 2021-10-29 7:09 ` kernel test robot 2021-10-29 12:59 ` kernel test robot 2 siblings, 0 replies; 55+ messages in thread From: kernel test robot @ 2021-10-29 7:09 UTC (permalink / raw) To: Andrea Merello, jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: kbuild-all, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex [-- Attachment #1: Type: text/plain, Size: 6416 bytes --] Hi Andrea, Thank you for the patch! Yet something to improve: [auto build test ERROR on linux/master] [also build test ERROR on linus/master v5.15-rc7] [cannot apply to jic23-iio/togreg next-20211028] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Andrea-Merello/utils_macro-introduce-find_closest_unsorted/20211028-191851 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2f111a6fd5b5297b4e92f53798ca086f7c7d33a4 config: arc-allyesconfig (attached as .config) compiler: arceb-elf-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/185166ebe83b933e30af55d4dc7972db6f9a8fb8 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Andrea-Merello/utils_macro-introduce-find_closest_unsorted/20211028-191851 git checkout 185166ebe83b933e30af55d4dc7972db6f9a8fb8 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross ARCH=arc If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): >> drivers/iio/imu/bno055/bno055.c:234:5: error: no previous prototype for 'bno055_calibration_load' [-Werror=missing-prototypes] 234 | int bno055_calibration_load(struct bno055_priv *priv, const struct firmware *fw) | ^~~~~~~~~~~~~~~~~~~~~~~ drivers/iio/imu/bno055/bno055.c: In function 'bno055_fusion_enable_store': >> drivers/iio/imu/bno055/bno055.c:917:13: error: variable 'ret' set but not used [-Werror=unused-but-set-variable] 917 | int ret = 0; | ^~~ drivers/iio/imu/bno055/bno055.c: At top level: >> drivers/iio/imu/bno055/bno055.c:1130:5: error: no previous prototype for 'bno055_debugfs_reg_access' [-Werror=missing-prototypes] 1130 | int bno055_debugfs_reg_access(struct iio_dev *iio_dev, unsigned int reg, | ^~~~~~~~~~~~~~~~~~~~~~~~~ drivers/iio/imu/bno055/bno055.c: In function 'bno055_trigger_handler': >> drivers/iio/imu/bno055/bno055.c:1330:9: error: implicit declaration of function 'for_each_set_bitrange'; did you mean 'for_each_set_bit'? [-Werror=implicit-function-declaration] 1330 | for_each_set_bitrange(start, end, iio_dev->active_scan_mask, | ^~~~~~~~~~~~~~~~~~~~~ | for_each_set_bit >> drivers/iio/imu/bno055/bno055.c:1331:51: error: expected ';' before '{' token 1331 | iio_dev->masklength) { | ^~ | ; >> drivers/iio/imu/bno055/bno055.c:1364:1: error: label 'done' defined but not used [-Werror=unused-label] 1364 | done: | ^~~~ >> drivers/iio/imu/bno055/bno055.c:1327:13: error: unused variable 'ret' [-Werror=unused-variable] 1327 | int ret; | ^~~ >> drivers/iio/imu/bno055/bno055.c:1326:13: error: unused variable 'quat' [-Werror=unused-variable] 1326 | int quat; | ^~~~ >> drivers/iio/imu/bno055/bno055.c:1325:14: error: unused variable 'thr_hit' [-Werror=unused-variable] 1325 | bool thr_hit; | ^~~~~~~ >> drivers/iio/imu/bno055/bno055.c:1324:13: error: unused variable 'buf_idx' [-Werror=unused-variable] 1324 | int buf_idx = 0; | ^~~~~~~ >> drivers/iio/imu/bno055/bno055.c:1323:23: error: unused variable 'mask' [-Werror=unused-variable] 1323 | unsigned long mask; | ^~~~ >> drivers/iio/imu/bno055/bno055.c:1322:14: error: unused variable 'first' [-Werror=unused-variable] 1322 | bool first = true; | ^~~~~ >> drivers/iio/imu/bno055/bno055.c:1321:14: error: unused variable 'xfer_pending' [-Werror=unused-variable] 1321 | bool xfer_pending = false; | ^~~~~~~~~~~~ >> drivers/iio/imu/bno055/bno055.c:1320:37: error: unused variable 'prev_end' [-Werror=unused-variable] 1320 | int xfer_start, start, end, prev_end; | ^~~~~~~~ >> drivers/iio/imu/bno055/bno055.c:1320:13: error: unused variable 'xfer_start' [-Werror=unused-variable] 1320 | int xfer_start, start, end, prev_end; | ^~~~~~~~~~ At top level: >> drivers/iio/imu/bno055/bno055.c:1262:12: error: 'bno055_scan_xfer' defined but not used [-Werror=unused-function] 1262 | static int bno055_scan_xfer(struct bno055_priv *priv, | ^~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors vim +/bno055_calibration_load +234 drivers/iio/imu/bno055/bno055.c 734efd9783b7759 Andrea Merello 2021-10-28 232 734efd9783b7759 Andrea Merello 2021-10-28 233 /* must be called in configuration mode */ 734efd9783b7759 Andrea Merello 2021-10-28 @234 int bno055_calibration_load(struct bno055_priv *priv, const struct firmware *fw) 734efd9783b7759 Andrea Merello 2021-10-28 235 { 734efd9783b7759 Andrea Merello 2021-10-28 236 if (fw->size != BNO055_CALDATA_LEN) { 734efd9783b7759 Andrea Merello 2021-10-28 237 dev_dbg(priv->dev, "Invalid calibration file size %d (expected %d)", 734efd9783b7759 Andrea Merello 2021-10-28 238 fw->size, BNO055_CALDATA_LEN); 734efd9783b7759 Andrea Merello 2021-10-28 239 return -EINVAL; 734efd9783b7759 Andrea Merello 2021-10-28 240 } 734efd9783b7759 Andrea Merello 2021-10-28 241 734efd9783b7759 Andrea Merello 2021-10-28 242 dev_dbg(priv->dev, "loading cal data: %*ph", BNO055_CALDATA_LEN, fw->data); 734efd9783b7759 Andrea Merello 2021-10-28 243 return regmap_bulk_write(priv->regmap, BNO055_CALDATA_START, 734efd9783b7759 Andrea Merello 2021-10-28 244 fw->data, BNO055_CALDATA_LEN); 734efd9783b7759 Andrea Merello 2021-10-28 245 } 734efd9783b7759 Andrea Merello 2021-10-28 246 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 69504 bytes --] ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 09/10] iio: imu: add BNO055 serdev driver 2021-10-28 10:18 ` [v2 09/10] iio: imu: add BNO055 serdev driver Andrea Merello 2021-10-28 12:31 ` Jonathan Cameron 2021-10-29 7:09 ` kernel test robot @ 2021-10-29 12:59 ` kernel test robot 2 siblings, 0 replies; 55+ messages in thread From: kernel test robot @ 2021-10-29 12:59 UTC (permalink / raw) To: Andrea Merello, jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: kbuild-all, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex [-- Attachment #1: Type: text/plain, Size: 6386 bytes --] Hi Andrea, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on linux/master] [also build test WARNING on linus/master v5.15-rc7] [cannot apply to jic23-iio/togreg next-20211029] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Andrea-Merello/utils_macro-introduce-find_closest_unsorted/20211028-191851 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2f111a6fd5b5297b4e92f53798ca086f7c7d33a4 config: m68k-randconfig-r011-20211029 (attached as .config) compiler: m68k-linux-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/185166ebe83b933e30af55d4dc7972db6f9a8fb8 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Andrea-Merello/utils_macro-introduce-find_closest_unsorted/20211028-191851 git checkout 185166ebe83b933e30af55d4dc7972db6f9a8fb8 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross ARCH=m68k If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): >> drivers/iio/imu/bno055/bno055.c:234:5: warning: no previous prototype for 'bno055_calibration_load' [-Wmissing-prototypes] 234 | int bno055_calibration_load(struct bno055_priv *priv, const struct firmware *fw) | ^~~~~~~~~~~~~~~~~~~~~~~ drivers/iio/imu/bno055/bno055.c: In function 'bno055_fusion_enable_store': >> drivers/iio/imu/bno055/bno055.c:917:13: warning: variable 'ret' set but not used [-Wunused-but-set-variable] 917 | int ret = 0; | ^~~ drivers/iio/imu/bno055/bno055.c: At top level: >> drivers/iio/imu/bno055/bno055.c:1188:5: warning: no previous prototype for 'bno055_debugfs_reg_access' [-Wmissing-prototypes] 1188 | int bno055_debugfs_reg_access(struct iio_dev *iio_dev, unsigned int reg, | ^~~~~~~~~~~~~~~~~~~~~~~~~ drivers/iio/imu/bno055/bno055.c: In function 'bno055_trigger_handler': drivers/iio/imu/bno055/bno055.c:1330:9: error: implicit declaration of function 'for_each_set_bitrange'; did you mean 'for_each_set_bit'? [-Werror=implicit-function-declaration] 1330 | for_each_set_bitrange(start, end, iio_dev->active_scan_mask, | ^~~~~~~~~~~~~~~~~~~~~ | for_each_set_bit drivers/iio/imu/bno055/bno055.c:1331:51: error: expected ';' before '{' token 1331 | iio_dev->masklength) { | ^~ | ; drivers/iio/imu/bno055/bno055.c:1364:1: warning: label 'done' defined but not used [-Wunused-label] 1364 | done: | ^~~~ drivers/iio/imu/bno055/bno055.c:1327:13: warning: unused variable 'ret' [-Wunused-variable] 1327 | int ret; | ^~~ drivers/iio/imu/bno055/bno055.c:1326:13: warning: unused variable 'quat' [-Wunused-variable] 1326 | int quat; | ^~~~ drivers/iio/imu/bno055/bno055.c:1325:14: warning: unused variable 'thr_hit' [-Wunused-variable] 1325 | bool thr_hit; | ^~~~~~~ drivers/iio/imu/bno055/bno055.c:1324:13: warning: unused variable 'buf_idx' [-Wunused-variable] 1324 | int buf_idx = 0; | ^~~~~~~ drivers/iio/imu/bno055/bno055.c:1323:23: warning: unused variable 'mask' [-Wunused-variable] 1323 | unsigned long mask; | ^~~~ drivers/iio/imu/bno055/bno055.c:1322:14: warning: unused variable 'first' [-Wunused-variable] 1322 | bool first = true; | ^~~~~ drivers/iio/imu/bno055/bno055.c:1321:14: warning: unused variable 'xfer_pending' [-Wunused-variable] 1321 | bool xfer_pending = false; | ^~~~~~~~~~~~ drivers/iio/imu/bno055/bno055.c:1320:37: warning: unused variable 'prev_end' [-Wunused-variable] 1320 | int xfer_start, start, end, prev_end; | ^~~~~~~~ drivers/iio/imu/bno055/bno055.c:1320:13: warning: unused variable 'xfer_start' [-Wunused-variable] 1320 | int xfer_start, start, end, prev_end; | ^~~~~~~~~~ At top level: drivers/iio/imu/bno055/bno055.c:1262:12: warning: 'bno055_scan_xfer' defined but not used [-Wunused-function] 1262 | static int bno055_scan_xfer(struct bno055_priv *priv, | ^~~~~~~~~~~~~~~~ cc1: some warnings being treated as errors vim +/bno055_calibration_load +234 drivers/iio/imu/bno055/bno055.c 734efd9783b7759 Andrea Merello 2021-10-28 232 734efd9783b7759 Andrea Merello 2021-10-28 233 /* must be called in configuration mode */ 734efd9783b7759 Andrea Merello 2021-10-28 @234 int bno055_calibration_load(struct bno055_priv *priv, const struct firmware *fw) 734efd9783b7759 Andrea Merello 2021-10-28 235 { 734efd9783b7759 Andrea Merello 2021-10-28 236 if (fw->size != BNO055_CALDATA_LEN) { 734efd9783b7759 Andrea Merello 2021-10-28 237 dev_dbg(priv->dev, "Invalid calibration file size %d (expected %d)", 734efd9783b7759 Andrea Merello 2021-10-28 238 fw->size, BNO055_CALDATA_LEN); 734efd9783b7759 Andrea Merello 2021-10-28 239 return -EINVAL; 734efd9783b7759 Andrea Merello 2021-10-28 240 } 734efd9783b7759 Andrea Merello 2021-10-28 241 734efd9783b7759 Andrea Merello 2021-10-28 242 dev_dbg(priv->dev, "loading cal data: %*ph", BNO055_CALDATA_LEN, fw->data); 734efd9783b7759 Andrea Merello 2021-10-28 243 return regmap_bulk_write(priv->regmap, BNO055_CALDATA_START, 734efd9783b7759 Andrea Merello 2021-10-28 244 fw->data, BNO055_CALDATA_LEN); 734efd9783b7759 Andrea Merello 2021-10-28 245 } 734efd9783b7759 Andrea Merello 2021-10-28 246 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 27609 bytes --] ^ permalink raw reply [flat|nested] 55+ messages in thread
* [v2 10/10] iio: imu: add BNO055 I2C driver 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello ` (8 preceding siblings ...) 2021-10-28 10:18 ` [v2 09/10] iio: imu: add BNO055 serdev driver Andrea Merello @ 2021-10-28 10:18 ` Andrea Merello 2021-10-28 11:10 ` Jonathan Cameron ` (2 more replies) 2021-10-28 10:35 ` [v2 00/10] Add support for Bosch BNO055 IMU Jonathan Cameron 10 siblings, 3 replies; 55+ messages in thread From: Andrea Merello @ 2021-10-28 10:18 UTC (permalink / raw) To: jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello, Andrea Merello This path adds an I2C driver for communicating to a BNO055 IMU via I2C bus and it enables the BNO055 core driver to work in this scenario. Signed-off-by: Andrea Merello <andrea.merello@iit.it> --- drivers/iio/imu/bno055/Kconfig | 6 ++++ drivers/iio/imu/bno055/Makefile | 1 + drivers/iio/imu/bno055/bno055_i2c.c | 54 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 drivers/iio/imu/bno055/bno055_i2c.c diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig index 941e43f0368d..87200787d548 100644 --- a/drivers/iio/imu/bno055/Kconfig +++ b/drivers/iio/imu/bno055/Kconfig @@ -7,3 +7,9 @@ config BOSH_BNO055_SERIAL tristate "Bosh BNO055 attached via serial bus" depends on SERIAL_DEV_BUS select BOSH_BNO055_IIO + +config BOSH_BNO055_I2C + tristate "Bosh BNO055 attached via I2C bus" + depends on I2C + select REGMAP_I2C + select BOSH_BNO055_IIO diff --git a/drivers/iio/imu/bno055/Makefile b/drivers/iio/imu/bno055/Makefile index 7285ade2f4b9..eaf24018cb28 100644 --- a/drivers/iio/imu/bno055/Makefile +++ b/drivers/iio/imu/bno055/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_BOSH_BNO055_IIO) += bno055.o obj-$(CONFIG_BOSH_BNO055_SERIAL) += bno055_sl.o +obj-$(CONFIG_BOSH_BNO055_I2C) += bno055_i2c.o diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c new file mode 100644 index 000000000000..eea0daa6a61d --- /dev/null +++ b/drivers/iio/imu/bno055/bno055_i2c.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * I2C interface for Bosh BNO055 IMU. + * This file implements I2C communication up to the register read/write + * level. + * + * Copyright (C) 2021 Istituto Italiano di Tecnologia + * Electronic Design Laboratory + * Written by Andrea Merello <andrea.merello@iit.it> + */ + +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/module.h> + +#include "bno055.h" + +#define BNO055_I2C_XFER_BURST_BREAK_THRESHOLD 3 /* FIXME */ + +static int bno055_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap = + devm_regmap_init_i2c(client, &bno055_regmap_config); + + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Unable to init register map"); + return PTR_ERR(regmap); + } + + return bno055_probe(&client->dev, regmap, + BNO055_I2C_XFER_BURST_BREAK_THRESHOLD); + + return 0; +} + +static const struct i2c_device_id bno055_i2c_id[] = { + {"bno055", 0}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, bno055_i2c_id); + +static struct i2c_driver bno055_driver = { + .driver = { + .name = "bno055-i2c", + }, + .probe = bno055_i2c_probe, + .id_table = bno055_i2c_id +}; +module_i2c_driver(bno055_driver); + +MODULE_AUTHOR("Andrea Merello"); +MODULE_DESCRIPTION("Bosch BNO055 I2C interface"); +MODULE_LICENSE("GPL v2"); -- 2.17.1 ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-10-28 10:18 ` [v2 10/10] iio: imu: add BNO055 I2C driver Andrea Merello @ 2021-10-28 11:10 ` Jonathan Cameron 2021-11-11 10:12 ` Andrea Merello 2021-10-28 22:04 ` Randy Dunlap 2021-10-29 13:30 ` kernel test robot 2 siblings, 1 reply; 55+ messages in thread From: Jonathan Cameron @ 2021-10-28 11:10 UTC (permalink / raw) To: Andrea Merello Cc: mchehab+huawei, linux-iio, linux-kernel, devicetree, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello On Thu, 28 Oct 2021 12:18:40 +0200 Andrea Merello <andrea.merello@gmail.com> wrote: > This path adds an I2C driver for communicating to a BNO055 IMU via I2C bus > and it enables the BNO055 core driver to work in this scenario. > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> Hi Andrea, A few minor things inline. Jonathan > --- > drivers/iio/imu/bno055/Kconfig | 6 ++++ > drivers/iio/imu/bno055/Makefile | 1 + > drivers/iio/imu/bno055/bno055_i2c.c | 54 +++++++++++++++++++++++++++++ > 3 files changed, 61 insertions(+) > create mode 100644 drivers/iio/imu/bno055/bno055_i2c.c > > diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig > index 941e43f0368d..87200787d548 100644 > --- a/drivers/iio/imu/bno055/Kconfig > +++ b/drivers/iio/imu/bno055/Kconfig > @@ -7,3 +7,9 @@ config BOSH_BNO055_SERIAL > tristate "Bosh BNO055 attached via serial bus" > depends on SERIAL_DEV_BUS > select BOSH_BNO055_IIO > + > +config BOSH_BNO055_I2C > + tristate "Bosh BNO055 attached via I2C bus" > + depends on I2C > + select REGMAP_I2C > + select BOSH_BNO055_IIO > diff --git a/drivers/iio/imu/bno055/Makefile b/drivers/iio/imu/bno055/Makefile > index 7285ade2f4b9..eaf24018cb28 100644 > --- a/drivers/iio/imu/bno055/Makefile > +++ b/drivers/iio/imu/bno055/Makefile > @@ -2,3 +2,4 @@ > > obj-$(CONFIG_BOSH_BNO055_IIO) += bno055.o > obj-$(CONFIG_BOSH_BNO055_SERIAL) += bno055_sl.o > +obj-$(CONFIG_BOSH_BNO055_I2C) += bno055_i2c.o > diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c > new file mode 100644 > index 000000000000..eea0daa6a61d > --- /dev/null > +++ b/drivers/iio/imu/bno055/bno055_i2c.c > @@ -0,0 +1,54 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * I2C interface for Bosh BNO055 IMU. > + * This file implements I2C communication up to the register read/write > + * level. Not really. It just uses regmap, so I'd drop this comment. > + * > + * Copyright (C) 2021 Istituto Italiano di Tecnologia > + * Electronic Design Laboratory > + * Written by Andrea Merello <andrea.merello@iit.it> > + */ > + > +#include <linux/i2c.h> Why? I'm not seeing an i2c specific calls in here. > +#include <linux/regmap.h> > +#include <linux/module.h> mod_devicetable.h for struct i2c_device_id > + > +#include "bno055.h" > + > +#define BNO055_I2C_XFER_BURST_BREAK_THRESHOLD 3 /* FIXME */ > + > +static int bno055_i2c_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct regmap *regmap = > + devm_regmap_init_i2c(client, &bno055_regmap_config); > + > + if (IS_ERR(regmap)) { > + dev_err(&client->dev, "Unable to init register map"); > + return PTR_ERR(regmap); > + } > + > + return bno055_probe(&client->dev, regmap, > + BNO055_I2C_XFER_BURST_BREAK_THRESHOLD); > + > + return 0; ? > +} > + > +static const struct i2c_device_id bno055_i2c_id[] = { > + {"bno055", 0}, > + { }, It's at terminator, so don't put a comma as we'll never add entries after this. > +}; > +MODULE_DEVICE_TABLE(i2c, bno055_i2c_id); > + > +static struct i2c_driver bno055_driver = { > + .driver = { > + .name = "bno055-i2c", > + }, > + .probe = bno055_i2c_probe, > + .id_table = bno055_i2c_id > +}; > +module_i2c_driver(bno055_driver); > + > +MODULE_AUTHOR("Andrea Merello"); > +MODULE_DESCRIPTION("Bosch BNO055 I2C interface"); > +MODULE_LICENSE("GPL v2"); ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-10-28 11:10 ` Jonathan Cameron @ 2021-11-11 10:12 ` Andrea Merello 2021-11-14 16:38 ` Jonathan Cameron 0 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-11-11 10:12 UTC (permalink / raw) To: Jonathan Cameron Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello Just an inline comment; OK for the rest. Il giorno gio 28 ott 2021 alle ore 13:05 Jonathan Cameron <jic23@kernel.org> ha scritto: > > On Thu, 28 Oct 2021 12:18:40 +0200 > Andrea Merello <andrea.merello@gmail.com> wrote: > > > This path adds an I2C driver for communicating to a BNO055 IMU via I2C bus > > and it enables the BNO055 core driver to work in this scenario. > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > Hi Andrea, > > A few minor things inline. > > Jonathan > > > --- > > drivers/iio/imu/bno055/Kconfig | 6 ++++ > > drivers/iio/imu/bno055/Makefile | 1 + > > drivers/iio/imu/bno055/bno055_i2c.c | 54 +++++++++++++++++++++++++++++ > > 3 files changed, 61 insertions(+) > > create mode 100644 drivers/iio/imu/bno055/bno055_i2c.c > > > > diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig > > index 941e43f0368d..87200787d548 100644 > > --- a/drivers/iio/imu/bno055/Kconfig > > +++ b/drivers/iio/imu/bno055/Kconfig > > @@ -7,3 +7,9 @@ config BOSH_BNO055_SERIAL > > tristate "Bosh BNO055 attached via serial bus" > > depends on SERIAL_DEV_BUS > > select BOSH_BNO055_IIO > > + > > +config BOSH_BNO055_I2C > > + tristate "Bosh BNO055 attached via I2C bus" > > + depends on I2C > > + select REGMAP_I2C > > + select BOSH_BNO055_IIO > > diff --git a/drivers/iio/imu/bno055/Makefile b/drivers/iio/imu/bno055/Makefile > > index 7285ade2f4b9..eaf24018cb28 100644 > > --- a/drivers/iio/imu/bno055/Makefile > > +++ b/drivers/iio/imu/bno055/Makefile > > @@ -2,3 +2,4 @@ > > > > obj-$(CONFIG_BOSH_BNO055_IIO) += bno055.o > > obj-$(CONFIG_BOSH_BNO055_SERIAL) += bno055_sl.o > > +obj-$(CONFIG_BOSH_BNO055_I2C) += bno055_i2c.o > > diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c > > new file mode 100644 > > index 000000000000..eea0daa6a61d > > --- /dev/null > > +++ b/drivers/iio/imu/bno055/bno055_i2c.c > > @@ -0,0 +1,54 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * I2C interface for Bosh BNO055 IMU. > > + * This file implements I2C communication up to the register read/write > > + * level. > > Not really. It just uses regmap, so I'd drop this comment. > > > + * > > + * Copyright (C) 2021 Istituto Italiano di Tecnologia > > + * Electronic Design Laboratory > > + * Written by Andrea Merello <andrea.merello@iit.it> > > + */ > > + > > +#include <linux/i2c.h> > > Why? I'm not seeing an i2c specific calls in here. Because of the definition of struct i2c_client, that is being accessed in lines like this dev_err(&client->dev, "Unable to init register map"); > > +#include <linux/regmap.h> > > +#include <linux/module.h> > > mod_devicetable.h for struct i2c_device_id > > > + > > +#include "bno055.h" > > + > > +#define BNO055_I2C_XFER_BURST_BREAK_THRESHOLD 3 /* FIXME */ > > + > > +static int bno055_i2c_probe(struct i2c_client *client, > > + const struct i2c_device_id *id) > > +{ > > + struct regmap *regmap = > > + devm_regmap_init_i2c(client, &bno055_regmap_config); > > + > > + if (IS_ERR(regmap)) { > > + dev_err(&client->dev, "Unable to init register map"); > > + return PTR_ERR(regmap); > > + } > > + > > + return bno055_probe(&client->dev, regmap, > > + BNO055_I2C_XFER_BURST_BREAK_THRESHOLD); > > + > > + return 0; > > ? > > > +} > > + > > +static const struct i2c_device_id bno055_i2c_id[] = { > > + {"bno055", 0}, > > + { }, > > It's at terminator, so don't put a comma as we'll never add entries after this. > > > +}; > > +MODULE_DEVICE_TABLE(i2c, bno055_i2c_id); > > + > > +static struct i2c_driver bno055_driver = { > > + .driver = { > > + .name = "bno055-i2c", > > + }, > > + .probe = bno055_i2c_probe, > > + .id_table = bno055_i2c_id > > +}; > > +module_i2c_driver(bno055_driver); > > + > > +MODULE_AUTHOR("Andrea Merello"); > > +MODULE_DESCRIPTION("Bosch BNO055 I2C interface"); > > +MODULE_LICENSE("GPL v2"); > ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-11-11 10:12 ` Andrea Merello @ 2021-11-14 16:38 ` Jonathan Cameron 0 siblings, 0 replies; 55+ messages in thread From: Jonathan Cameron @ 2021-11-14 16:38 UTC (permalink / raw) To: Andrea Merello Cc: Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On Thu, 11 Nov 2021 11:12:58 +0100 Andrea Merello <andrea.merello@gmail.com> wrote: > Just an inline comment; OK for the rest. > > > +#include <linux/i2c.h> > > > > Why? I'm not seeing an i2c specific calls in here. > > Because of the definition of struct i2c_client, that is being accessed > in lines like this > dev_err(&client->dev, "Unable to init register map"); doh. I was clearly being a bit unobservant that day. ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-10-28 10:18 ` [v2 10/10] iio: imu: add BNO055 I2C driver Andrea Merello 2021-10-28 11:10 ` Jonathan Cameron @ 2021-10-28 22:04 ` Randy Dunlap 2021-11-09 11:56 ` Andrea Merello 2021-10-29 13:30 ` kernel test robot 2 siblings, 1 reply; 55+ messages in thread From: Randy Dunlap @ 2021-10-28 22:04 UTC (permalink / raw) To: Andrea Merello, jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo, Andrea Merello On 10/28/21 3:18 AM, Andrea Merello wrote: > This path adds an I2C driver for communicating to a BNO055 IMU via I2C bus > and it enables the BNO055 core driver to work in this scenario. > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > --- > drivers/iio/imu/bno055/Kconfig | 6 ++++ > drivers/iio/imu/bno055/Makefile | 1 + > drivers/iio/imu/bno055/bno055_i2c.c | 54 +++++++++++++++++++++++++++++ > 3 files changed, 61 insertions(+) > create mode 100644 drivers/iio/imu/bno055/bno055_i2c.c > > diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig > index 941e43f0368d..87200787d548 100644 > --- a/drivers/iio/imu/bno055/Kconfig > +++ b/drivers/iio/imu/bno055/Kconfig > @@ -7,3 +7,9 @@ config BOSH_BNO055_SERIAL > tristate "Bosh BNO055 attached via serial bus" > depends on SERIAL_DEV_BUS > select BOSH_BNO055_IIO > + > +config BOSH_BNO055_I2C > + tristate "Bosh BNO055 attached via I2C bus" > + depends on I2C > + select REGMAP_I2C > + select BOSH_BNO055_IIO Hi, The config entries that have user prompt strings should also have help text. scripts/checkpatch.pl should have told you about that... -- ~Randy ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-10-28 22:04 ` Randy Dunlap @ 2021-11-09 11:56 ` Andrea Merello 2021-11-09 15:47 ` Randy Dunlap 0 siblings, 1 reply; 55+ messages in thread From: Andrea Merello @ 2021-11-09 11:56 UTC (permalink / raw) To: Randy Dunlap Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello Il giorno ven 29 ott 2021 alle ore 00:04 Randy Dunlap <rdunlap@infradead.org> ha scritto: > > On 10/28/21 3:18 AM, Andrea Merello wrote: > > This path adds an I2C driver for communicating to a BNO055 IMU via I2C bus > > and it enables the BNO055 core driver to work in this scenario. > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > --- > > drivers/iio/imu/bno055/Kconfig | 6 ++++ > > drivers/iio/imu/bno055/Makefile | 1 + > > drivers/iio/imu/bno055/bno055_i2c.c | 54 +++++++++++++++++++++++++++++ > > 3 files changed, 61 insertions(+) > > create mode 100644 drivers/iio/imu/bno055/bno055_i2c.c > > > > diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig > > index 941e43f0368d..87200787d548 100644 > > --- a/drivers/iio/imu/bno055/Kconfig > > +++ b/drivers/iio/imu/bno055/Kconfig > > @@ -7,3 +7,9 @@ config BOSH_BNO055_SERIAL > > tristate "Bosh BNO055 attached via serial bus" > > depends on SERIAL_DEV_BUS > > select BOSH_BNO055_IIO > > + > > +config BOSH_BNO055_I2C > > + tristate "Bosh BNO055 attached via I2C bus" > > + depends on I2C > > + select REGMAP_I2C > > + select BOSH_BNO055_IIO > > Hi, > > The config entries that have user prompt strings should also > have help text. scripts/checkpatch.pl should have told you > about that... I'll add it, thanks. But FYI checkpatch doesn't complain about that here. > -- > ~Randy ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-11-09 11:56 ` Andrea Merello @ 2021-11-09 15:47 ` Randy Dunlap 2021-11-09 18:21 ` Joe Perches 0 siblings, 1 reply; 55+ messages in thread From: Randy Dunlap @ 2021-11-09 15:47 UTC (permalink / raw) To: andrea.merello, joe@perches.com Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On 11/9/21 3:56 AM, Andrea Merello wrote: > Il giorno ven 29 ott 2021 alle ore 00:04 Randy Dunlap > <rdunlap@infradead.org> ha scritto: >> >> On 10/28/21 3:18 AM, Andrea Merello wrote: >>> This path adds an I2C driver for communicating to a BNO055 IMU via I2C bus >>> and it enables the BNO055 core driver to work in this scenario. >>> >>> Signed-off-by: Andrea Merello <andrea.merello@iit.it> >>> --- >>> drivers/iio/imu/bno055/Kconfig | 6 ++++ >>> drivers/iio/imu/bno055/Makefile | 1 + >>> drivers/iio/imu/bno055/bno055_i2c.c | 54 +++++++++++++++++++++++++++++ >>> 3 files changed, 61 insertions(+) >>> create mode 100644 drivers/iio/imu/bno055/bno055_i2c.c >>> >>> diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig >>> index 941e43f0368d..87200787d548 100644 >>> --- a/drivers/iio/imu/bno055/Kconfig >>> +++ b/drivers/iio/imu/bno055/Kconfig >>> @@ -7,3 +7,9 @@ config BOSH_BNO055_SERIAL >>> tristate "Bosh BNO055 attached via serial bus" >>> depends on SERIAL_DEV_BUS >>> select BOSH_BNO055_IIO >>> + >>> +config BOSH_BNO055_I2C >>> + tristate "Bosh BNO055 attached via I2C bus" >>> + depends on I2C >>> + select REGMAP_I2C >>> + select BOSH_BNO055_IIO >> >> Hi, >> >> The config entries that have user prompt strings should also >> have help text. scripts/checkpatch.pl should have told you >> about that... > > I'll add it, thanks. But FYI checkpatch doesn't complain about that here. Hm, thanks for adding it and telling me about that. checkpatch.pl does have some code for checking that but I confirmed that it does not catch this simple case. Joe, can you identify why checkpatch does not detect missing Kconfig help text is this simple case? Thanks. -- ~Randy ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-11-09 15:47 ` Randy Dunlap @ 2021-11-09 18:21 ` Joe Perches 2021-11-09 19:11 ` Randy Dunlap 0 siblings, 1 reply; 55+ messages in thread From: Joe Perches @ 2021-11-09 18:21 UTC (permalink / raw) To: Randy Dunlap, andrea.merello, Andi Kleen Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello (cc'ing Andi Kleen, who wrote this code a decade ago) On Tue, 2021-11-09 at 07:47 -0800, Randy Dunlap wrote: > On 11/9/21 3:56 AM, Andrea Merello wrote: > > Il giorno ven 29 ott 2021 alle ore 00:04 Randy Dunlap <rdunlap@infradead.org> ha scritto: > > > On 10/28/21 3:18 AM, Andrea Merello wrote: > > > > This path adds an I2C driver for communicating to a BNO055 IMU via I2C bus > > > > and it enables the BNO055 core driver to work in this scenario. > > > > > > > > Signed-off-by: Andrea Merello <andrea.merello@iit.it> > > > > --- > > > > drivers/iio/imu/bno055/Kconfig | 6 ++++ > > > > drivers/iio/imu/bno055/Makefile | 1 + [] > > > > diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig [] > > > > @@ -7,3 +7,9 @@ config BOSH_BNO055_SERIAL > > > > tristate "Bosh BNO055 attached via serial bus" > > > > depends on SERIAL_DEV_BUS > > > > select BOSH_BNO055_IIO > > > > + > > > > +config BOSH_BNO055_I2C > > > > + tristate "Bosh BNO055 attached via I2C bus" > > > > + depends on I2C > > > > + select REGMAP_I2C > > > > + select BOSH_BNO055_IIO [] > > > The config entries that have user prompt strings should also > > > have help text. scripts/checkpatch.pl should have told you > > > about that... > > > > I'll add it, thanks. But FYI checkpatch doesn't complain about that here. > > Hm, thanks for adding it and telling me about that. > > checkpatch.pl does have some code for checking that but I confirmed > that it does not catch this simple case. > > Joe, can you identify why checkpatch does not detect missing Kconfig > help text is this simple case? Original patch here: https://lore.kernel.org/all/20211028101840.24632-11-andrea.merello@gmail.com/raw checkpatch is counting the diff header lines that follow the config entry. Maybe this is clearer (better?) code: --- scripts/checkpatch.pl | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 1784921c645da..b3ce8e04d7df7 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3483,20 +3483,22 @@ sub process { my $cnt = $realcnt; my $ln = $linenr + 1; my $f; - my $is_start = 0; - my $is_end = 0; + my $needs_help = 0; + my $has_help = 0; for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) { $f = $lines[$ln - 1]; - $cnt-- if ($lines[$ln - 1] !~ /^-/); - $is_end = $lines[$ln - 1] =~ /^\+/; + $cnt-- if ($f !~ /^-/); next if ($f =~ /^-/); - last if (!$file && $f =~ /^\@\@/); + last if (!$file && $f =~ /^(?:\@\@|diff )/); - if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { - $is_start = 1; - } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) { - $length = -1; + if ($f =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { + $needs_help = 1; + next; + } elsif ($f =~ /^\+\s*help\s*$/) { + $length = 0; + $has_help = 1; + next; } $f =~ s/^.//; @@ -3510,16 +3512,16 @@ sub process { # common words in help texts if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice| if|endif|menu|endmenu|source)\b/x) { - $is_end = 1; last; } - $length++; + $length++ if ($has_help); } - if ($is_start && $is_end && $length < $min_conf_desc_length) { + if ($needs_help && + (!$has_help || + ($has_help && $length < $min_conf_desc_length))) { WARN("CONFIG_DESCRIPTION", "please write a paragraph that describes the config symbol fully\n" . $herecurr); } - #print "is_start<$is_start> is_end<$is_end> length<$length>\n"; } # check MAINTAINERS entries ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-11-09 18:21 ` Joe Perches @ 2021-11-09 19:11 ` Randy Dunlap 2021-11-09 20:46 ` Joe Perches 0 siblings, 1 reply; 55+ messages in thread From: Randy Dunlap @ 2021-11-09 19:11 UTC (permalink / raw) To: Joe Perches, andrea.merello, Andi Kleen Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On 11/9/21 10:21 AM, Joe Perches wrote: > (cc'ing Andi Kleen, who wrote this code a decade ago) > > On Tue, 2021-11-09 at 07:47 -0800, Randy Dunlap wrote: >> On 11/9/21 3:56 AM, Andrea Merello wrote: >>> Il giorno ven 29 ott 2021 alle ore 00:04 Randy Dunlap <rdunlap@infradead.org> ha scritto: >>>> On 10/28/21 3:18 AM, Andrea Merello wrote: >>>>> This path adds an I2C driver for communicating to a BNO055 IMU via I2C bus >>>>> and it enables the BNO055 core driver to work in this scenario. >>>>> >>>>> Signed-off-by: Andrea Merello <andrea.merello@iit.it> >>>>> --- >>>>> drivers/iio/imu/bno055/Kconfig | 6 ++++ >>>>> drivers/iio/imu/bno055/Makefile | 1 + > [] >>>>> diff --git a/drivers/iio/imu/bno055/Kconfig b/drivers/iio/imu/bno055/Kconfig > [] >>>>> @@ -7,3 +7,9 @@ config BOSH_BNO055_SERIAL >>>>> tristate "Bosh BNO055 attached via serial bus" >>>>> depends on SERIAL_DEV_BUS >>>>> select BOSH_BNO055_IIO >>>>> + >>>>> +config BOSH_BNO055_I2C >>>>> + tristate "Bosh BNO055 attached via I2C bus" >>>>> + depends on I2C >>>>> + select REGMAP_I2C >>>>> + select BOSH_BNO055_IIO > [] >>>> The config entries that have user prompt strings should also >>>> have help text. scripts/checkpatch.pl should have told you >>>> about that... >>> >>> I'll add it, thanks. But FYI checkpatch doesn't complain about that here. >> >> Hm, thanks for adding it and telling me about that. >> >> checkpatch.pl does have some code for checking that but I confirmed >> that it does not catch this simple case. >> >> Joe, can you identify why checkpatch does not detect missing Kconfig >> help text is this simple case? > > Original patch here: https://lore.kernel.org/all/20211028101840.24632-11-andrea.merello@gmail.com/raw > > checkpatch is counting the diff header lines that follow the config entry. > Maybe this is clearer (better?) code: > --- > scripts/checkpatch.pl | 28 +++++++++++++++------------- > 1 file changed, 15 insertions(+), 13 deletions(-) > > diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl > index 1784921c645da..b3ce8e04d7df7 100755 > --- a/scripts/checkpatch.pl > +++ b/scripts/checkpatch.pl > @@ -3483,20 +3483,22 @@ sub process { > my $cnt = $realcnt; > my $ln = $linenr + 1; > my $f; > - my $is_start = 0; > - my $is_end = 0; > + my $needs_help = 0; > + my $has_help = 0; > for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) { > $f = $lines[$ln - 1]; > - $cnt-- if ($lines[$ln - 1] !~ /^-/); > - $is_end = $lines[$ln - 1] =~ /^\+/; > + $cnt-- if ($f !~ /^-/); > > next if ($f =~ /^-/); > - last if (!$file && $f =~ /^\@\@/); > + last if (!$file && $f =~ /^(?:\@\@|diff )/); > > - if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { > - $is_start = 1; > - } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) { > - $length = -1; > + if ($f =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { > + $needs_help = 1; > + next; > + } elsif ($f =~ /^\+\s*help\s*$/) { > + $length = 0; > + $has_help = 1; > + next; > } > > $f =~ s/^.//; > @@ -3510,16 +3512,16 @@ sub process { > # common words in help texts > if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice| > if|endif|menu|endmenu|source)\b/x) { > - $is_end = 1; > last; > } > - $length++; > + $length++ if ($has_help); > } > - if ($is_start && $is_end && $length < $min_conf_desc_length) { > + if ($needs_help && > + (!$has_help || > + ($has_help && $length < $min_conf_desc_length))) { > WARN("CONFIG_DESCRIPTION", > "please write a paragraph that describes the config symbol fully\n" . $herecurr); > } > - #print "is_start<$is_start> is_end<$is_end> length<$length>\n"; > } > > # check MAINTAINERS entries > > Which now says: WARNING: please write a paragraph that describes the config symbol fully #16: FILE: drivers/iio/Kconfig:101: +config BOSH_BNO055_I2C (This is for a dummy entry that I made for testing, not from Andrea's patch.) Thanks, Joe. Tested-by: Randy Dunlap <rdunlap@infradead.org> Acked-by: Randy Dunlap <rdunlap@infradead.org> -- ~Randy ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-11-09 19:11 ` Randy Dunlap @ 2021-11-09 20:46 ` Joe Perches 2021-11-09 21:20 ` Randy Dunlap 0 siblings, 1 reply; 55+ messages in thread From: Joe Perches @ 2021-11-09 20:46 UTC (permalink / raw) To: Randy Dunlap, andrea.merello, Andi Kleen Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On Tue, 2021-11-09 at 11:11 -0800, Randy Dunlap wrote: > On 11/9/21 10:21 AM, Joe Perches wrote: > > (cc'ing Andi Kleen, who wrote this code a decade ago) > > > Joe, can you identify why checkpatch does not detect missing Kconfig > > > help text is this simple case? > > > > Original patch here: https://lore.kernel.org/all/20211028101840.24632-11-andrea.merello@gmail.com/raw > > > > checkpatch is counting the diff header lines that follow the config entry. > > Maybe this is clearer (better?) code: > > --- > Tested-by: Randy Dunlap <rdunlap@infradead.org> > Acked-by: Randy Dunlap <rdunlap@infradead.org> Hey Randy/Andi. I like this patch below a bit more. It shows the Kconfig context block in the output message and documents the code a bit more. Care to test it again? --- scripts/checkpatch.pl | 53 +++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 1784921c645da..0b5c0363119ff 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3480,46 +3480,49 @@ sub process { # (\b) rather than a whitespace character (\s) $line =~ /^\+\s*(?:config|menuconfig|choice)\b/) { my $length = 0; - my $cnt = $realcnt; - my $ln = $linenr + 1; - my $f; - my $is_start = 0; - my $is_end = 0; - for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) { - $f = $lines[$ln - 1]; - $cnt-- if ($lines[$ln - 1] !~ /^-/); - $is_end = $lines[$ln - 1] =~ /^\+/; + my $ln = $linenr; + my $needs_help = 0; + my $has_help = 0; + my $herecfg = $herecurr; + while (defined $lines[$ln]) { + my $f = $lines[$ln++]; next if ($f =~ /^-/); - last if (!$file && $f =~ /^\@\@/); + last if (!$file && $f =~ /^(?:\@\@|diff )/); - if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { - $is_start = 1; - } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) { - $length = -1; + $herecfg .= $rawlines[$ln - 1] . "\n"; + if ($f =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { + $needs_help = 1; + next; + } + if ($f =~ /^\+\s*help\s*$/) { + $has_help = 1; + next; } - $f =~ s/^.//; - $f =~ s/#.*//; - $f =~ s/^\s+//; - next if ($f =~ /^$/); + $f =~ s/^.//; # strip patch context [+ ] + $f =~ s/#.*//; # strip # directives + $f =~ s/^\s+//; # strip leading blanks + next if ($f =~ /^$/); # skip blank lines + # At the end of this Kconfig block: # This only checks context lines in the patch # and so hopefully shouldn't trigger false # positives, even though some of these are # common words in help texts - if ($f =~ /^\s*(?:config|menuconfig|choice|endchoice| - if|endif|menu|endmenu|source)\b/x) { - $is_end = 1; + if ($f =~ /^(?:config|menuconfig|choice|endchoice| + if|endif|menu|endmenu|source)\b/x) { + $herecfg =~ s/.*\n\Z//; # strip last line last; } - $length++; + $length++ if ($has_help); } - if ($is_start && $is_end && $length < $min_conf_desc_length) { + if ($needs_help && + (!$has_help || + ($has_help && $length < $min_conf_desc_length))) { WARN("CONFIG_DESCRIPTION", - "please write a paragraph that describes the config symbol fully\n" . $herecurr); + "please write a help paragraph that fully describes the config symbol\n" . $herecfg); } - #print "is_start<$is_start> is_end<$is_end> length<$length>\n"; } # check MAINTAINERS entries ^ permalink raw reply related [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-11-09 20:46 ` Joe Perches @ 2021-11-09 21:20 ` Randy Dunlap 0 siblings, 0 replies; 55+ messages in thread From: Randy Dunlap @ 2021-11-09 21:20 UTC (permalink / raw) To: Joe Perches, andrea.merello, Andi Kleen Cc: Jonathan Cameron, Mauro Carvalho Chehab, linux-iio, linux-kernel, devicetree, Lars-Peter Clausen, Rob Herring, Andy Shevchenko, Matt Ranostay, Alexandru Ardelean, Jacopo Mondi, Andrea Merello On 11/9/21 12:46 PM, Joe Perches wrote: > On Tue, 2021-11-09 at 11:11 -0800, Randy Dunlap wrote: >> On 11/9/21 10:21 AM, Joe Perches wrote: >>> (cc'ing Andi Kleen, who wrote this code a decade ago) >>>> Joe, can you identify why checkpatch does not detect missing Kconfig >>>> help text is this simple case? >>> >>> Original patch here: https://lore.kernel.org/all/20211028101840.24632-11-andrea.merello@gmail.com/raw >>> >>> checkpatch is counting the diff header lines that follow the config entry. >>> Maybe this is clearer (better?) code: >>> --- >> Tested-by: Randy Dunlap <rdunlap@infradead.org> >> Acked-by: Randy Dunlap <rdunlap@infradead.org> > > Hey Randy/Andi. > > I like this patch below a bit more. > > It shows the Kconfig context block in the output message and > documents the code a bit more. > > Care to test it again? > --- > scripts/checkpatch.pl | 53 +++++++++++++++++++++++++++------------------------ > 1 file changed, 28 insertions(+), 25 deletions(-) > Same tags from me, better output. Thanks! Tested-by: Randy Dunlap <rdunlap@infradead.org> Acked-by: Randy Dunlap <rdunlap@infradead.org> -- ~Randy ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 10/10] iio: imu: add BNO055 I2C driver 2021-10-28 10:18 ` [v2 10/10] iio: imu: add BNO055 I2C driver Andrea Merello 2021-10-28 11:10 ` Jonathan Cameron 2021-10-28 22:04 ` Randy Dunlap @ 2021-10-29 13:30 ` kernel test robot 2 siblings, 0 replies; 55+ messages in thread From: kernel test robot @ 2021-10-29 13:30 UTC (permalink / raw) To: Andrea Merello, jic23, mchehab+huawei, linux-iio, linux-kernel, devicetree Cc: kbuild-all, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex [-- Attachment #1: Type: text/plain, Size: 8517 bytes --] Hi Andrea, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on linux/master] [also build test WARNING on linus/master v5.15-rc7] [cannot apply to jic23-iio/togreg next-20211029] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Andrea-Merello/utils_macro-introduce-find_closest_unsorted/20211028-191851 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2f111a6fd5b5297b4e92f53798ca086f7c7d33a4 config: alpha-randconfig-r014-20211029 (attached as .config) compiler: alpha-linux-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/fab64510c8234ae8acfbc853cc8c433ae831f7b3 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Andrea-Merello/utils_macro-introduce-find_closest_unsorted/20211028-191851 git checkout fab64510c8234ae8acfbc853cc8c433ae831f7b3 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross ARCH=alpha If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): drivers/iio/imu/bno055/bno055.c:234:5: warning: no previous prototype for 'bno055_calibration_load' [-Wmissing-prototypes] 234 | int bno055_calibration_load(struct bno055_priv *priv, const struct firmware *fw) | ^~~~~~~~~~~~~~~~~~~~~~~ In file included from include/linux/printk.h:555, from include/linux/kernel.h:19, from include/linux/clk.h:13, from drivers/iio/imu/bno055/bno055.c:18: drivers/iio/imu/bno055/bno055.c: In function 'bno055_calibration_load': >> drivers/iio/imu/bno055/bno055.c:237:36: warning: format '%d' expects argument of type 'int', but argument 4 has type 'size_t' {aka 'long unsigned int'} [-Wformat=] 237 | dev_dbg(priv->dev, "Invalid calibration file size %d (expected %d)", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ include/linux/dynamic_debug.h:134:29: note: in definition of macro '__dynamic_func_call' 134 | func(&id, ##__VA_ARGS__); \ | ^~~~~~~~~~~ include/linux/dynamic_debug.h:166:9: note: in expansion of macro '_dynamic_func_call' 166 | _dynamic_func_call(fmt,__dynamic_dev_dbg, \ | ^~~~~~~~~~~~~~~~~~ include/linux/dev_printk.h:155:9: note: in expansion of macro 'dynamic_dev_dbg' 155 | dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__) | ^~~~~~~~~~~~~~~ include/linux/dev_printk.h:155:30: note: in expansion of macro 'dev_fmt' 155 | dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__) | ^~~~~~~ drivers/iio/imu/bno055/bno055.c:237:17: note: in expansion of macro 'dev_dbg' 237 | dev_dbg(priv->dev, "Invalid calibration file size %d (expected %d)", | ^~~~~~~ drivers/iio/imu/bno055/bno055.c:237:68: note: format string is defined here 237 | dev_dbg(priv->dev, "Invalid calibration file size %d (expected %d)", | ~^ | | | int | %ld drivers/iio/imu/bno055/bno055.c: In function 'bno055_fusion_enable_store': drivers/iio/imu/bno055/bno055.c:917:13: warning: variable 'ret' set but not used [-Wunused-but-set-variable] 917 | int ret = 0; | ^~~ drivers/iio/imu/bno055/bno055.c: At top level: drivers/iio/imu/bno055/bno055.c:1130:5: warning: no previous prototype for 'bno055_debugfs_reg_access' [-Wmissing-prototypes] 1130 | int bno055_debugfs_reg_access(struct iio_dev *iio_dev, unsigned int reg, | ^~~~~~~~~~~~~~~~~~~~~~~~~ drivers/iio/imu/bno055/bno055.c: In function 'bno055_trigger_handler': drivers/iio/imu/bno055/bno055.c:1330:9: error: implicit declaration of function 'for_each_set_bitrange'; did you mean 'for_each_set_bit'? [-Werror=implicit-function-declaration] 1330 | for_each_set_bitrange(start, end, iio_dev->active_scan_mask, | ^~~~~~~~~~~~~~~~~~~~~ | for_each_set_bit drivers/iio/imu/bno055/bno055.c:1331:51: error: expected ';' before '{' token 1331 | iio_dev->masklength) { | ^~ | ; drivers/iio/imu/bno055/bno055.c:1364:1: warning: label 'done' defined but not used [-Wunused-label] 1364 | done: | ^~~~ drivers/iio/imu/bno055/bno055.c:1327:13: warning: unused variable 'ret' [-Wunused-variable] 1327 | int ret; | ^~~ drivers/iio/imu/bno055/bno055.c:1326:13: warning: unused variable 'quat' [-Wunused-variable] 1326 | int quat; | ^~~~ drivers/iio/imu/bno055/bno055.c:1325:14: warning: unused variable 'thr_hit' [-Wunused-variable] 1325 | bool thr_hit; | ^~~~~~~ drivers/iio/imu/bno055/bno055.c:1324:13: warning: unused variable 'buf_idx' [-Wunused-variable] 1324 | int buf_idx = 0; | ^~~~~~~ drivers/iio/imu/bno055/bno055.c:1323:23: warning: unused variable 'mask' [-Wunused-variable] 1323 | unsigned long mask; | ^~~~ drivers/iio/imu/bno055/bno055.c:1322:14: warning: unused variable 'first' [-Wunused-variable] 1322 | bool first = true; | ^~~~~ drivers/iio/imu/bno055/bno055.c:1321:14: warning: unused variable 'xfer_pending' [-Wunused-variable] 1321 | bool xfer_pending = false; | ^~~~~~~~~~~~ drivers/iio/imu/bno055/bno055.c:1320:37: warning: unused variable 'prev_end' [-Wunused-variable] 1320 | int xfer_start, start, end, prev_end; | ^~~~~~~~ drivers/iio/imu/bno055/bno055.c:1320:13: warning: unused variable 'xfer_start' [-Wunused-variable] 1320 | int xfer_start, start, end, prev_end; | ^~~~~~~~~~ At top level: drivers/iio/imu/bno055/bno055.c:1262:12: warning: 'bno055_scan_xfer' defined but not used [-Wunused-function] 1262 | static int bno055_scan_xfer(struct bno055_priv *priv, | ^~~~~~~~~~~~~~~~ cc1: some warnings being treated as errors vim +237 drivers/iio/imu/bno055/bno055.c 734efd9783b7759 Andrea Merello 2021-10-28 232 734efd9783b7759 Andrea Merello 2021-10-28 233 /* must be called in configuration mode */ 734efd9783b7759 Andrea Merello 2021-10-28 @234 int bno055_calibration_load(struct bno055_priv *priv, const struct firmware *fw) 734efd9783b7759 Andrea Merello 2021-10-28 235 { 734efd9783b7759 Andrea Merello 2021-10-28 236 if (fw->size != BNO055_CALDATA_LEN) { 734efd9783b7759 Andrea Merello 2021-10-28 @237 dev_dbg(priv->dev, "Invalid calibration file size %d (expected %d)", 734efd9783b7759 Andrea Merello 2021-10-28 238 fw->size, BNO055_CALDATA_LEN); 734efd9783b7759 Andrea Merello 2021-10-28 239 return -EINVAL; 734efd9783b7759 Andrea Merello 2021-10-28 240 } 734efd9783b7759 Andrea Merello 2021-10-28 241 734efd9783b7759 Andrea Merello 2021-10-28 242 dev_dbg(priv->dev, "loading cal data: %*ph", BNO055_CALDATA_LEN, fw->data); 734efd9783b7759 Andrea Merello 2021-10-28 243 return regmap_bulk_write(priv->regmap, BNO055_CALDATA_START, 734efd9783b7759 Andrea Merello 2021-10-28 244 fw->data, BNO055_CALDATA_LEN); 734efd9783b7759 Andrea Merello 2021-10-28 245 } 734efd9783b7759 Andrea Merello 2021-10-28 246 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 36323 bytes --] ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 00/10] Add support for Bosch BNO055 IMU 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello ` (9 preceding siblings ...) 2021-10-28 10:18 ` [v2 10/10] iio: imu: add BNO055 I2C driver Andrea Merello @ 2021-10-28 10:35 ` Jonathan Cameron 2021-10-28 10:33 ` Andy Shevchenko 10 siblings, 1 reply; 55+ messages in thread From: Jonathan Cameron @ 2021-10-28 10:35 UTC (permalink / raw) To: Andrea Merello Cc: mchehab+huawei, linux-iio, linux-kernel, devicetree, lars, robh+dt, andy.shevchenko, matt.ranostay, ardeleanalex, jacopo Hi Andrea, I'd advise not sending new versions of a series with the in-reply-to set to an older version. It's a good way to ensure anyone using an email client handling threads never sees them... It also gets very messy if we happen to get replies to multiple versions overlapping. New version, new email thread. On Thu, 28 Oct 2021 12:18:30 +0200 Andrea Merello <andrea.merello@gmail.com> wrote: > This series (tries to) add support for Bosch BNO055 IMU to Linux IIO > subsystem. It is made up several patches: > > 1/10: introduces the generic helper find_closest_unsorted() > > 2/10 to 5/10: add some IIO modifiers, and their documentation, to the IIO > core layer, in order to being able to expose the linear > acceleration and Euler angles among standard attributes. > > 6/10 to 8/10: add the core IIO BNO055 driver and its documentation > (including documentation for DT bindings) > > 9/10: adds serdev BNO055 driver to actually use the IMU via serial line > > 10/10: adds I2C BNO055 driver to actually use the IMU via I2C wiring > > > Differences wrt v1: > > - Fixed GPL license version, which was wrong due to bad copy-pastes > > - Make less noise in log and get rid of some dev_dbg()s > > - Fix deferred probe handing and fix devm_add_action_or_reset() usage > > - Get rid of unneeded zeroing for driver data and some IIO "val2"s > > - Get rid of some leftovers of my attempt to support interrupts (which > don't fully work unless the IMU firmware gets updated) > > - Move IIO buffer off stack and make sure its first zeroed not to leak > kernel data > > - Hopefully addressed all maintainers and reviewers stylistic advices; > fixed some typos > > - Take advantage of more kernel helpers. Note: this series depends on > Yury Norov bitmap series i.e. "[PATCH 14/16] bitmap: unify find_bit > operations" > > - Make find_closest_unsorted() become an external generic helper > > - Reworked sysfs ABI as per maintainers advices > > - Added ABI documentation where needed > > - Added I2C support > > - Reworked DT documentation as per maintainers advices. Added I2C example > > The serial protocol handling have been criticized because it is not very > robust, however I couldn't really find any way to improve it; no changes > here wrt v1. I think the protocol itself is inherently weak and there is > nothing we can do about this (BTW here it is working fine). > > Differences wrt other BNO055 drivers: > > Previously at least another driver for the very same chip has been posted > to the Linux ML [0], but it has been never merged, and it seems no one > cared of it since quite a long time. > > This driver differs from the above driver on the following aspects: > > - This driver supports also serial access > > - The above driver tried to support all IMU HW modes by allowing to > choose one in the DT, and adapting IIO attributes accordingly. This > driver does not rely on DT for this, instead settings are done via > sysfs attributes. All IIO attributes are always exposed; more on this > later on. This driver however supports only a subset of the > HW-supported modes. > > - This driver has some support for managing the IMU calibration > > Supported operation modes: > > - AMG (accelerometer, magnetometer and gyroscope) mode, which provides > raw (uncalibrated) measurements from the said sensors, and allows for > setting some parameters about them (e.g. filter cut-off frequency, max > sensor ranges, etc). > > - Fusion mode, which still provides AMG measures, while it also provides > other data calculated by the IMU (e.g. rotation angles, linear > acceleration, etc). In this mode user has no freedom to set any sensor > parameter, since the HW locks them. Autocalibration and correction is > performed by the IMU. > > IIO attributes exposing sensors parameters are always present, but in > fusion modes the available values are constrained to just the one used by > the HW. This is reflected in the '*_available' IIO attributes. > > Trying to set a not-supported value always falls back to the closest > supported one, which in this case is just the one in use by the HW. > > IIO attributes for unavailable measurements (e.g. Euler angles in AMG > mode) just read zero (which is consistent WRT what you get when reading > from a buffer with those attributes enabled). > > IMU calibration: > > The IMU supports for two sets of calibration parameters: > > - SIC matrix. user-provided; this driver doesn't currently support it > > - Offset and radius parameters. The IMU automatically finds out them when > it is running in fusion mode; supported by this driver. > > The driver provides access to autocalibration flags (i.e. you can known > if the IMU has successfully autocalibrated) and to calibration data blob. > The user can save this blob in a "firmware" file (i.e. in /lib/firmware) > that the driver looks for at probe time. If found, then the IMU is > initialized with this calibration data. This saves the user from > performing the calibration procedure every time (which consist of moving > the IMU in various way). > > The driver looks for calibration data file using two different names: > first a file whose name is suffixed with the IMU unique ID is searched > for; this is useful when there is more than one IMU instance. If this > file is not found, then a "generic" calibration file is searched for > (which can be used when only one IMU is present, without struggling with > fancy names, that changes on each device). > > In AMG mode the IIO 'offset' attributes provide access to the offsets > from calibration data (if any), so that the user can apply them to the > accel, angvel and magn IIO attributes. In fusion mode they are not needed > and read as zero. > > > Access protocols and serdev module: > > The serial protocol is quite simple, but there are tricks to make it > really works. Those tricks and workarounds are documented in the driver > source file. > > The core BNO055 driver tries to group readings in burst when appropriate, > in order to optimize triggered buffer operation. The threshold for > splitting a burst (i.e. max number of unused bytes in the middle of a > burst that will be throw away) is provided to the core driver by the > lowlevel access driver (either serdev or I2C) at probe time. > > [0] https://www.spinics.net/lists/linux-iio/msg25508.html > > Andrea Merello (10): > utils_macro: introduce find_closest_unsorted() > iio: document linear acceleration modifiers > iio: document euler angles modifiers > iio: add modifiers for linear acceleration > iio: add modifers for pitch, yaw, roll > iio: document bno055 private sysfs attributes > iio: imu: add Bosch Sensortec BNO055 core driver > dt-bindings: iio: imu: add documentation for Bosch BNO055 bindings > iio: imu: add BNO055 serdev driver > iio: imu: add BNO055 I2C driver > > Documentation/ABI/testing/sysfs-bus-iio | 16 + > .../ABI/testing/sysfs-bus-iio-bno055 | 84 + > .../bindings/iio/imu/bosch,bno055.yaml | 59 + > drivers/iio/imu/Kconfig | 1 + > drivers/iio/imu/Makefile | 1 + > drivers/iio/imu/bno055/Kconfig | 15 + > drivers/iio/imu/bno055/Makefile | 5 + > drivers/iio/imu/bno055/bno055.c | 1485 +++++++++++++++++ > drivers/iio/imu/bno055/bno055.h | 12 + > drivers/iio/imu/bno055/bno055_i2c.c | 54 + > drivers/iio/imu/bno055/bno055_sl.c | 568 +++++++ > drivers/iio/industrialio-core.c | 6 + > include/linux/util_macros.h | 26 + > include/uapi/linux/iio/types.h | 7 +- > 14 files changed, 2338 insertions(+), 1 deletion(-) > create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-bno055 > create mode 100644 Documentation/devicetree/bindings/iio/imu/bosch,bno055.yaml > create mode 100644 drivers/iio/imu/bno055/Kconfig > create mode 100644 drivers/iio/imu/bno055/Makefile > create mode 100644 drivers/iio/imu/bno055/bno055.c > create mode 100644 drivers/iio/imu/bno055/bno055.h > create mode 100644 drivers/iio/imu/bno055/bno055_i2c.c > create mode 100644 drivers/iio/imu/bno055/bno055_sl.c > > -- > 2.17.1 ^ permalink raw reply [flat|nested] 55+ messages in thread
* Re: [v2 00/10] Add support for Bosch BNO055 IMU 2021-10-28 10:35 ` [v2 00/10] Add support for Bosch BNO055 IMU Jonathan Cameron @ 2021-10-28 10:33 ` Andy Shevchenko 0 siblings, 0 replies; 55+ messages in thread From: Andy Shevchenko @ 2021-10-28 10:33 UTC (permalink / raw) To: Jonathan Cameron Cc: Andrea Merello, Mauro Carvalho Chehab, linux-iio, Linux Kernel Mailing List, devicetree, Lars-Peter Clausen, Rob Herring, Matt Ranostay, Alexandru Ardelean, jmondi On Thu, Oct 28, 2021 at 1:30 PM Jonathan Cameron <jic23@kernel.org> wrote: > > Hi Andrea, > > I'd advise not sending new versions of a series with the in-reply-to set > to an older version. It's a good way to ensure anyone using an email client > handling threads never sees them... It also gets very messy if we happen > to get replies to multiple versions overlapping. > > New version, new email thread. +1 here, but since it will be a new version, let's leave it for a while so reviewers may have a chance to comment on something. -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 55+ messages in thread
end of thread, other threads:[~2022-01-22 18:02 UTC | newest] Thread overview: 55+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- [not found] <20210715141742.15072-1-andrea.merello@gmail.com> 2021-10-28 10:18 ` [v2 00/10] Add support for Bosch BNO055 IMU Andrea Merello 2021-10-28 10:18 ` [v2 01/10] utils_macro: introduce find_closest_unsorted() Andrea Merello 2021-10-28 10:25 ` Andy Shevchenko 2021-11-08 11:05 ` Andrea Merello 2021-10-28 10:18 ` [v2 02/10] iio: document linear acceleration modifiers Andrea Merello 2021-10-28 10:31 ` Andy Shevchenko 2021-11-09 7:48 ` Andrea Merello 2021-10-28 10:40 ` Jonathan Cameron 2021-11-09 8:00 ` Andrea Merello 2021-11-09 17:00 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 03/10] iio: document euler angles modifiers Andrea Merello 2021-10-28 10:33 ` Andy Shevchenko 2021-10-28 10:41 ` Jonathan Cameron 2021-11-09 8:15 ` Andrea Merello 2021-11-09 17:03 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 04/10] iio: add modifiers for linear acceleration Andrea Merello 2021-10-28 10:45 ` Jonathan Cameron 2021-11-09 9:58 ` Andrea Merello 2021-11-09 17:05 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 05/10] iio: add modifers for pitch, yaw, roll Andrea Merello 2021-10-28 10:47 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 06/10] iio: document bno055 private sysfs attributes Andrea Merello 2021-10-28 11:04 ` Jonathan Cameron 2021-11-09 10:22 ` Andrea Merello 2021-11-14 16:20 ` Jonathan Cameron 2022-01-04 11:42 ` Andrea Merello 2022-01-15 15:27 ` Jonathan Cameron 2022-01-17 9:37 ` Andrea Merello 2022-01-22 18:08 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 07/10] iio: imu: add Bosch Sensortec BNO055 core driver Andrea Merello 2021-10-28 13:31 ` Jonathan Cameron 2021-11-09 11:52 ` Andrea Merello 2021-11-14 16:33 ` Jonathan Cameron 2021-10-28 10:18 ` [v2 08/10] dt-bindings: iio: imu: add documentation for Bosch BNO055 bindings Andrea Merello 2021-10-28 12:25 ` Rob Herring 2021-10-28 10:18 ` [v2 09/10] iio: imu: add BNO055 serdev driver Andrea Merello 2021-10-28 12:31 ` Jonathan Cameron 2021-11-09 15:33 ` Andrea Merello 2021-11-14 16:37 ` Jonathan Cameron 2021-10-29 7:09 ` kernel test robot 2021-10-29 12:59 ` kernel test robot 2021-10-28 10:18 ` [v2 10/10] iio: imu: add BNO055 I2C driver Andrea Merello 2021-10-28 11:10 ` Jonathan Cameron 2021-11-11 10:12 ` Andrea Merello 2021-11-14 16:38 ` Jonathan Cameron 2021-10-28 22:04 ` Randy Dunlap 2021-11-09 11:56 ` Andrea Merello 2021-11-09 15:47 ` Randy Dunlap 2021-11-09 18:21 ` Joe Perches 2021-11-09 19:11 ` Randy Dunlap 2021-11-09 20:46 ` Joe Perches 2021-11-09 21:20 ` Randy Dunlap 2021-10-29 13:30 ` kernel test robot 2021-10-28 10:35 ` [v2 00/10] Add support for Bosch BNO055 IMU Jonathan Cameron 2021-10-28 10:33 ` Andy Shevchenko
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).