[PATCH v7 0/4] iio: accel: add MSA311 accelerometer driver

From: Dmitry Rokosov
Date: Mon Aug 22 2022 - 13:50:51 EST


MSA311 is a tri-axial, low-g accelerometer with I2C digital output for
sensitivity consumer applications. It has dynamic user-selectable full
scales range of +-2g/+-4g/+-8g/+-16g and allows acceleration measurements
with output data rates from 1Hz to 1000Hz.

Spec: https://cdn-shop.adafruit.com/product-files/5309/MSA311-V1.1-ENG.pdf

This driver supports following MSA311 features:
- IIO interface
- Different power modes: NORMAL and SUSPEND (using pm_runtime)
- ODR (Output Data Rate) selection
- Scale and samp_freq selection
- IIO triggered buffer, IIO reg access
- NEW_DATA interrupt + trigger

Below features to be done:
- Motion Events: ACTIVE, TAP, ORIENT, FREEFALL
- Low Power mode

Also this patchset has new vendor prefix for MEMSensing Microsystems and
MSA311 dt-binding schema.

You can test msa311 driver using libiio and gnuplot following below
instructions:
$ # Create hrtimer trigger object
$ mkdir /sys/kernel/config/iio/triggers/hrtimer/iio_hrtimer_trigger
$ # Read 4K samples using msa311-13-new-data trigger (irq) and
$ # buffer with depth equals to 64 samples and rotate device a little bit
$ iio_readdev -u "local:" -b 64 -s 4096 -t msa311-13-new-data -T 0 \
$ msa311-13 > /tmp/msa311.dat
$ # Or using hrtimer trigger instead of msa311-13-new-data trigger
$ iio_readdev -u "local:" -b 64 -s 4096 -t iio_hrtimer_trigger -T 0 \
$ msa311 > /data/local/tmp/msa311.dat
$ cat <<EOF >> msa311_data.gnu
set title "MSA311 Accel Data"

set key below

set xdata time
set format x "%H:%M\n%.4S"
set xlabel "timestamp"

set autoscale y

plot 'msa311.dat' binary endian=little \
format='%int16%int16%int16%uint16%uint64' using \
(\$5/1000000000):(int(\$1)/16) title "acc_x" \
with lines,\\
'msa311.dat' binary endian=little \
format='%int16%int16%int16%uint16%uint64' using \
(\$5/1000000000):(int(\$2)/16) title "acc_y" \
with lines,\\
'msa311.dat' binary endian=little \
format='%int16%int16%int16%uint16%uint64' using \
(\$5/1000000000):(int(\$3)/16) title "acc_z" with lines
EOF
$ gnuplot --persist msa311_data.gnu

Changes:
* v6->v7:
- replaced Spec: tag with Datasheet: in the commit message
- refactored some routines a little bit
- removed inline functions specifier
- used devm_kasprintf() instead of statically allocated byte array
- vdd-supply regulator reference is not optional anymore
- removed .owner i2c_driver initialization, it's redundant

* v5->v6:
- excluded hz units patch series because it was already merged by
Andrew Morton to linux-next through the nomm-unstable, refer to
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?id=0d8f705fc03e2629efa306ed62d5d19ae5c87de1
- deduplicated val/val2 anonymous struct to iio_decimal_fract struct
- update pm_runtime information before error handling inside
msa311_read_raw_data()
- removed null terminator after scnprintf() usage
- reworked disabling and unmapping all interrupts to regmap bulk
operations
- wrapped up some multiline calls a little bit
- added zero padding to fractional part of odr logs
- replaced blank lines between reg fields definitions with registers
names
- s/cannot/can't/g

* v4->v5:
- used chip_name for IRQ and trigger name generation in the form
msa311-%partid%-*
- split generic with IIO headers
- fixup some mathematical forms inside comments
- provided small code refactoring for commas, comments, and logs
- removed errno value logging from dev_err_probe() calls per
Christophe suggestion to avoid extra errno string output
- returned INDIO_DIRECT_MODE default initializer for indio_dev->modes
- provided pm_runtime_set_active() call during msa311 probing to let
runtime PM know that we are starting up with msa311 chip turned on
as Jonathan suggested
- used HZ units for hz calculations
- removed logging contractions
- removed double calling of regulator_disable() in the probe error
path
- used postfix increment operations instead of prefix form :)
- used %pe specifier to print errno as a string in the dev_err()
- merged with HZ units patchset from
https://lore.kernel.org/linux-iio/20220801143811.14817-1-ddrokosov@xxxxxxxxxxxxxx/
- merged with Andy's str_read_write() patch from
https://lore.kernel.org/linux-i2c/20220703154232.55549-1-andriy.shevchenko@xxxxxxxxxxxxxxx/
- used str_read_write() string helper inside driver implementation

* v3->v4:
- totally reworked pm_runtime flow based on Jonathan suggestions
- replaced temporary field variable with tmp pointer to field in the
MSA311_GENMASK macro helper
- removed i2c pointer from MSA311 private context, retrieved it from
msa311 object, if anything
- added struct device *dev reference to MSA311 private context for
easier msa311->dev translation
- moved regmap pointer to the beginning of MSA311 private context to
save some instructions
- refactored 'if' conditions to be positive and shorter
- moved msa311_check_partid() and msa311_soft_reset() to separate
routines and call them before powerup IP logic during probe()
execution
- used str_enable_disable() string helper as Andy suggested
- used msa311_pwr_modes const char * array to translate power modes
to strings
- reworked hz->ms translation, used MICROHZ_PER_HZ from the
following review:
https://lore.kernel.org/linux-iio/20220801143811.14817-1-ddrokosov@xxxxxxxxxxxxxx/
- moved dev_dbg() log about MSA311 compatible chip finding under
partid check
- refactored stack variables definitions based on "longer lines
first" thumb
- used 0 instead of INDIO_DIRECT_MODE before iio buffer setup
- moved i2c->irq check to msa311_setup_interrupts()
- removed dev_dbg() prints from ->resume() and ->suspend() callbacks
- removed "description" fields from "interrupts" and i2c "reg" YAML
schema nodes
- implemented simple power supply for MSA311 (vdd-supply)
- reworked shared_by_all info mask to shared_by_type for MSA311
accel channels
- tagged datasheet URL link in the commit message
- made mutex-based critical section shorter inside odr and fs loop as
Jonathan suggested
- fixed wording in the commit messages and comments a little bit,
refactored some indentations
- replaced blank lines between register offset definitions with
short comments

* v2->v3:
- removed MSA311_TIMESTAMP_CHANNEL() macro, used IIO_CHAN_SOFT_TIMESTAMP
directly
- do not call dev_err_probe() inside functions, which is used not only
from probe() path
- simplified error handling a little bit
- used iio_device_claim_direct_mode() and
iio_device_release_direct_mode() to lock attributes when buffer mode
is enabled
- prohibited sampling frequency changing during buffer usage because
otherwise sometimes MSA311 returns outliers when frequency values
grow up in the read operation moment
- allowed scale value changing when buffer mode is enabled
- removed IRQF_TRIGGER_RISING irq flag from irg registration because
it's provided from device tree directly
- do not switch off autosuspend from powerdown() devm callback,
because it's already done from pm_runtime_disable() during
devm pm_runtime actions
- provided more information why we need force suspend state for MSA311
in the powerdown flow
- reworked comments stuff: removed obvious extra comments, provided
more details in the complex driver code places

* v1->v2:
- memsensing vendor prefix was moved to right place by
alphabetical order
- LOW mode mention was deleted, because LOW mode isn't supported
in the current driver version
- reworked some enums with gaps to defines
- reworked register names as Jonathan mentioned in the v1
- do not use regmap_field API for entire registers
- deleted all extra comments
- supported info_mask_*_avail bitmaps instead of explicit IIO attrs
definitions, implemented read_avail() callback for samp_freq and
scale values
- msa311 mutex is still used to protect msa311 power transitions,
samp_freq/scale tune and axes data handling; described this lock
more informative
- ask new_data interruption status from appropriate register,
do not hold atomic variable for that
- optimized reads of axes data by I2C using regmap_bulk API
- use dev_err_probe() instead of dev_err() for all probe() code paths
- from now all I2C bus communication failures are interpreted as errors
- described wait_from_next() semantic better
- deleted all unneeded pm wrappers
- interpreter all axes data as __le16 type and adjust them to right
format (endianness + sign) for raw() flow only
- redesigned msa311_fs_table[] to 2D matrix (it's more comfortable
format for read_avail() callback)
- align and initialize msa311 buffer before pushing properly
- use pm_runtime resume and suspend from buffer preenable/postdisable,
deleted them from trigger set_state
- supported multiple trigger usage (tested with external hrtimer
trigger and internal new_data trigger)
- moved all irq related stuff to msa311_setup_interrupts() routine
- implemented msa311_powerdown() devm release action
- reworked initialization of pm_runtime msa311 flow, use
autosuspend logic
- purged driver remove() callback, because of devm release logic runs
all deinit stuff fully
- fixed dts bindings problems
- changed irq type in the dt-binding description, because interrupt
type for msa311 should have the same type as i2c irq, for example
using the gpio_intc it's IRQ_TYPE_EDGE_RISING usually. Otherwise
we may lose irq map on the second and further insmod attempts

Andy Shevchenko (1):
lib/string_helpers: Add str_read_write() helper

Dmitry Rokosov (3):
dt-bindings: vendor-prefixes: add MEMSensing Microsystems Co., Ltd.
iio: add MEMSensing MSA311 3-axis accelerometer driver
dt-bindings: iio: accel: add dt-binding schema for msa311 accel driver

.../bindings/iio/accel/memsensing,msa311.yaml | 53 +
.../devicetree/bindings/vendor-prefixes.yaml | 2 +
MAINTAINERS | 7 +
drivers/iio/accel/Kconfig | 13 +
drivers/iio/accel/Makefile | 2 +
drivers/iio/accel/msa311.c | 1321 +++++++++++++++++
include/linux/string_helpers.h | 5 +
7 files changed, 1403 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/accel/memsensing,msa311.yaml
create mode 100644 drivers/iio/accel/msa311.c

--
2.36.0