iio: Support ROHM/Kionix kx022a
Subsystems (3)
Matti Vaittinen
maintainerv3 cover iio: Support ROHM/Kionix kx022a
Add initial support for ROHM/Kionix kx022a accelerometer
About the HW:
KX022A accelerometer is a sensor which:
- supports G-ranges of (+/-) 2, 4, 8, and 16G
- can be connected to I2C or SPI
- has internal HW FIFO buffer
- supports various ODRs (output data rates)
- support detecting special events like double tap or motion
- can be configured to wake-up system when events are detected.
About the series:
This series adds support for only getting the accelerometer data and configuring the G-range / ODR via IIO. Motion detection or double-tap detection are not supported by the series. The other quite important but still missing piece is the runtime PM. Nevertheless, the driver should be usable and brings the basic support for getting accelerometer data.
Changelog v3: (More detailed log in individual patches)
- dt-bindings: fixed as suggested by Krzysztof
- KX022A: multiple fixes as suggested by Andy
- Fair to mention that couple of suggested changes are not done (Some styling, boilerplate text in KConfig) as there has been no consensus whether the suggested changes improve situation. Ultimately the decision whether these changes are mandatory lay on the shoulders of the maintainers... Sorry for that.
- Enable the FIFO without module param now that the "FIFO stuck" issue can be prevented.
- Fix potential race with time-stamp calculation when user-space invokes the fifo flush.
- Drop the already merged regulator patches.
Changelog v2: (More detailed log in individual patches)
- dt-bindings: fixed as suggested by Krzysztof
- dt-bindings: support both INT1 and INT2
- KX022A: multiple fixes as suggested by Jonathan
- fixed SPI driver after some testing
---
Matti Vaittinen (3):
dt-bindings: iio: Add KX022A accelerometer
iio: accel: Support Kionix/ROHM KX022A accelerometer
MAINTAINERS: Add KX022A maintainer entry
.../bindings/iio/accel/kionix,kx022a.yaml | 65 + MAINTAINERS | 5 + drivers/iio/accel/Kconfig | 21 + drivers/iio/accel/Makefile | 3 + drivers/iio/accel/kionix-kx022a-i2c.c | 52 + drivers/iio/accel/kionix-kx022a-spi.c | 59 + drivers/iio/accel/kionix-kx022a.c | 1147 +++++++++++++++++ drivers/iio/accel/kionix-kx022a.h | 82 ++ 8 files changed, 1434 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml create mode 100644 drivers/iio/accel/kionix-kx022a-i2c.c create mode 100644 drivers/iio/accel/kionix-kx022a-spi.c create mode 100644 drivers/iio/accel/kionix-kx022a.c create mode 100644 drivers/iio/accel/kionix-kx022a.h
13,411 lines not shown · raw message
Part of this message is not shown here. View the raw message.
Matti Vaittinen
maintainerPATCH v3 1/3 dt-bindings: iio: Add KX022A accelerometer
KX022A is a 3-axis Accelerometer from ROHM/Kionix. The sensor features include variable ODRs, I2C and SPI control, FIFO/LIFO with watermark IRQ, tap/motion detection, wake-up & back-to-sleep events, four acceleration ranges (2, 4, 8 and 16g) and probably some other cool features.
Add the basic device tree description for the accelerometer. Only basic accelerometer features are considered as of now - new properties may or may not be needed in the future when rest of the features are supported.
---
v2 => v3 as suggested by Krzysztof:
- better check interrupt-names
RFCv1 => v2:
Based on a review by Krzysztof:
- fix a typo from commit message
- const compatible
- drop unnecessary descriptions/words
- io_vdd-supply => io-vdd-supply
- fix the binding example indentiation
Also,
- change my email address
- support both INT pins
--- .../bindings/iio/accel/kionix,kx022a.yaml | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml
Documentation/devicetree/bindings/iio/accel/kionix,kx022a.yaml new file +65 -0
@@ -0,0 +1,65 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/accel/kionix,kx022a.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM/Kionix KX022A Accelerometer + +maintainers: + - Matti Vaittinen <[email protected]> + +description: | + KX022A is a 3-axis accelerometer supporting +/- 2G, 4G, 8G and 16G ranges, + output data-rates from 0.78Hz to 1600Hz and a hardware-fifo buffering. + KX022A can be accessed either via I2C or SPI. + +properties: + compatible: + const: kionix,kx022a + + reg: + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 2 + + interrupt-names: + minItems: 1 + items: + - enum: [INT1, INT2] + - const: INT2 + + vdd-supply: true + io-vdd-supply: true + + mount-matrix: + description: | + an optional 3x3 mounting rotation matrix. + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + accel@1f { + compatible = "kionix,kx022a"; + reg = <0x1f>; + + interrupt-parent = <&gpio1>; + interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "INT1"; + + io-vdd-supply = <&iovdd>; + vdd-supply = <&vdd>; + }; + };
Signature · 14 lines
2.37.3 -- Matti Vaittinen, Linux device drivers ROHM Semiconductors, Finland SWDC Kiviharjunlenkki 1E 90220 OULU FINLAND ~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~ Simon says - in Latin please. ~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~ Thanks to Simon Glass for the translation =]
Re: [PATCH v3 1/3] dt-bindings: iio: Add KX022A accelerometer
Quoted 10 lines · Matti Vaittinen
KX022A is a 3-axis Accelerometer from ROHM/Kionix. The sensor features include variable ODRs, I2C and SPI control, FIFO/LIFO with watermark IRQ, tap/motion detection, wake-up & back-to-sleep events, four acceleration ranges (2, 4, 8 and 16g) and probably some other cool features.
Add the basic device tree description for the accelerometer. Only basic accelerometer features are considered as of now - new properties may or may not be needed in the future when rest of the features are supported.
Signed-off-by Matti Vaittinen <[email protected]>
Best regards,
Krzysztof
Matti Vaittinen
maintainerPATCH v3 2/3 iio: accel: Support Kionix/ROHM KX022A accelerometer
In reply to Matti VaittinenKX022A is a 3-axis accelerometer from ROHM/Kionix. The sensor features include variable ODRs, I2C and SPI control, FIFO/LIFO with watermark IRQ, tap/motion detection, wake-up & back-to-sleep events, four acceleration ranges (2, 4, 8 and 16g) and probably some other cool features.
Add support for the basic accelerometer features such as getting the acceleration data via IIO. (raw reads, triggered buffer [data-ready] or using the WMI IRQ).
Important things to be added include the double-tap, motion detection and wake-up as well as the runtime power management.
---
v2 => v3 Mostly fixes suggested by Andy
- styling issues
- spell-checks
- use namespaces for exported symbols
- drop module param
- document the lock
- change value written when clearing fifo
- drop WARN_ON()
- correctly check the return value from fwnode_irq_get_byname()
- do not emphasize config Y over M
- reorder struct kx022a_data from potential optimization
- IIO_DEVICE_ATTR_RO instead of IIO_DEVICE_ATTR where applicable
- directly include bits.h for BIT()
- use sysfs_emit() for sysfs
- use unique name for IRQ
- convert read_raw() values to CPU endianess
- fix HW-fifo size to 258 bytes
- kx022a-spi, Fix kconfig dependency
- disable irq (to protect timestamp / sample amount calculation) when the fifo flush is iniriated by user-space
RFCv1 => v2 (mostly based on feedback from Jonathan):
- Fix bunch of typos from the commit message.
- Add missing break; to the kx022a_write_raw()
- Fix SPI driver to use of_match_table
- Fix indentiation in I2C driver
- Drop struct kx022a_trigger
- Drop cross references from Kconfig
- Use /* */ also in file header comments
- Misc minor styling
- Do sensor-reset at probe
- Support both IRQ pins
- Implement read_avail callback
- Use dma aligned buffers for bulk-reads
- Use iio_trigger_poll_chained()
- Use devm consistently
- Drop inclusion of device.h
- Add SPI device ID for module loading
- Add module param for hw fifo / watermark IRQ usage
- Fix io-vdd-supply name to match one in the bindings
--- drivers/iio/accel/Kconfig | 21 + drivers/iio/accel/Makefile | 3 + drivers/iio/accel/kionix-kx022a-i2c.c | 52 ++ drivers/iio/accel/kionix-kx022a-spi.c | 59 ++ drivers/iio/accel/kionix-kx022a.c | 1147 +++++++++++++++++++++++++ drivers/iio/accel/kionix-kx022a.h | 82 ++ 6 files changed, 1364 insertions(+) create mode 100644 drivers/iio/accel/kionix-kx022a-i2c.c create mode 100644 drivers/iio/accel/kionix-kx022a-spi.c create mode 100644 drivers/iio/accel/kionix-kx022a.c create mode 100644 drivers/iio/accel/kionix-kx022a.h
drivers/iio/accel/Kconfig +21 -0
@@ -409,6 +409,27 @@ config IIO_ST_ACCEL_SPI_3AXIS To compile this driver as a module, choose M here. The module will be called st_accel_spi. +config IIO_KX022A + tristate + +config IIO_KX022A_SPI + tristate "Kionix KX022A tri-axis digital accelerometer" + depends on SPI + select IIO_KX022A + select REGMAP_SPI + help + Enable support for the Kionix KX022A digital tri-axis + accelerometer connected to I2C interface. + +config IIO_KX022A_I2C + tristate "Kionix KX022A tri-axis digital accelerometer" + depends on I2C + select IIO_KX022A + select REGMAP_I2C + help + Enable support for the Kionix KX022A digital tri-axis + accelerometer connected to I2C interface. + config KXSD9 tristate "Kionix KXSD9 Accelerometer Driver" select IIO_BUFFER
drivers/iio/accel/Makefile +3 -0
@@ -40,6 +40,9 @@ obj-$(CONFIG_FXLS8962AF) += fxls8962af-core.o obj-$(CONFIG_FXLS8962AF_I2C) += fxls8962af-i2c.o obj-$(CONFIG_FXLS8962AF_SPI) += fxls8962af-spi.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o +obj-$(CONFIG_IIO_KX022A) += kionix-kx022a.o +obj-$(CONFIG_IIO_KX022A_I2C) += kionix-kx022a-i2c.o +obj-$(CONFIG_IIO_KX022A_SPI) += kionix-kx022a-spi.o obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o obj-$(CONFIG_KXSD9_SPI) += kxsd9-spi.o
drivers/iio/accel/kionix-kx022a-i2c.c new file +52 -0
52 lines not on this page · raw message
drivers/iio/accel/kionix-kx022a-spi.c new file +59 -0
59 lines not on this page · raw message
drivers/iio/accel/kionix-kx022a.c new file +1147 -0
1,147 lines not on this page · raw message
drivers/iio/accel/kionix-kx022a.h new file +82 -0
82 lines not on this page · raw message
Signature · 14 lines
2.37.3 -- Matti Vaittinen, Linux device drivers ROHM Semiconductors, Finland SWDC Kiviharjunlenkki 1E 90220 OULU FINLAND ~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~ Simon says - in Latin please. ~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~ Thanks to Simon Glass for the translation =]
Re: [PATCH v3 2/3] iio: accel: Support Kionix/ROHM KX022A accelerometer
Quoted 11 lines · Matti Vaittinen
KX022A is a 3-axis accelerometer from ROHM/Kionix. The sensor features include variable ODRs, I2C and SPI control, FIFO/LIFO with watermark IRQ, tap/motion detection, wake-up & back-to-sleep events, four acceleration ranges (2, 4, 8 and 16g) and probably some other cool features.
Add support for the basic accelerometer features such as getting the acceleration data via IIO. (raw reads, triggered buffer [data-ready] or using the WMI IRQ).
Important things to be added include the double-tap, motion detection and wake-up as well as the runtime power management.
...
drivers/iio/accel/kionix-kx022a-i2c.c line 22
Quoted 3 lines
drivers/iio/accel/kionix-kx022a-i2c.c new file +3
-0+if (!i2c->irq) { +dev_err (dev,"No IRQ configured\n" ); +return -EINVAL ;
At least
return dev_err_probe(...);
for know error codes (or when we know that there won't be EPROBE_DEFER), takes less LoCs in the source file.
Quoted 1 line
(quoted diff) +1
-0+ }
...
drivers/iio/accel/kionix-kx022a-i2c.c line 28
Quoted 4 lines
drivers/iio/accel/kionix-kx022a-i2c.c new file +4
-0+ regmap =devm_regmap_init_i2c (i2c, &kx022a_regmap); +if (IS_ERR (regmap)) { +dev_err (dev,"Failed to initialize Regmap\n" ); +return PTR_ERR (regmap);
Ditto here and anywhere else for the similar cases.
Quoted 1 line
(quoted diff) +1
-0+ }
...
drivers/iio/accel/kionix-kx022a.c line 304
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +10
-0+case IIO_CHAN_INFO_SAMP_FREQ : + *vals = (const int *)kx022a_accel_samp_freq_table; + *length =ARRAY_SIZE (kx022a_accel_samp_freq_table) *2 ; + *type =IIO_VAL_INT_PLUS_MICRO ; +return IIO_AVAIL_LIST ; +case IIO_CHAN_INFO_SCALE : + *vals = (const int *)kx022a_scale_table; + *length =ARRAY_SIZE (kx022a_scale_table) *2 ; + *type =IIO_VAL_INT_PLUS_MICRO ; +return IIO_AVAIL_LIST ;
These ' * 2' can be replaced with respective ARRAY_SIZE() of nested element for robustness, but I don't think it worth it. What we need is to provide IIO specific type for these tables and use it.
...
Quoted 4 lines
drivers/iio/accel/kionix-kx022a.c new file +4
-0+static int kx022a_turn_on_off_unlocked (struct kx022a_data *data,bool on) +{ +int ret; +
drivers/iio/accel/kionix-kx022a.c line 341
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +10
-0+if (on) + ret =regmap_set_bits (data->regmap,KX022A_REG_CNTL , +KX022A_MASK_PC1 ); +else + ret =regmap_clear_bits (data->regmap,KX022A_REG_CNTL , +KX022A_MASK_PC1 ); + +if (ret) +dev_err (data->dev,"Turn %s fail %d\n" , (on) ?"ON" :"OFF" , + ret);
str_on_off() ?
Quoted 3 lines
drivers/iio/accel/kionix-kx022a.c new file +3
-0+return ret; + +}
...
drivers/iio/accel/kionix-kx022a.c line 395
Quoted 7 lines
drivers/iio/accel/kionix-kx022a.c new file +7
-0+switch (mask) { +case IIO_CHAN_INFO_SAMP_FREQ : + n =ARRAY_SIZE (kx022a_accel_samp_freq_table); + +while (n--) +if (val == kx022a_accel_samp_freq_table[n][0 ] && + kx022a_accel_samp_freq_table[n][1 ] == val2)
Why not to use the same kind of l and r arguments in == lines? In current form it's a bit harder to see what the catch here.
Quoted 11 lines
drivers/iio/accel/kionix-kx022a.c new file +11
-0+break ; +if (n <0 ) { + ret = -EINVAL ; + goto unlock_out; + } + ret =kx022a_turn_off_lock (data); +if (ret) +break ; + + ret = regmap_update_bits(data->regmap, + KX022A_REG_ODCNTL,
drivers/iio/accel/kionix-kx022a.c line 416
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +10
-0+ KX022A_MASK_ODR, n); + data->odr_ns = kx022a_odrs[n]; +kx022a_turn_on_unlock (data); +break ; +case IIO_CHAN_INFO_SCALE : + n =ARRAY_SIZE (kx022a_scale_table); + +while (n-- >0 ) +if (val == kx022a_scale_table[n][0 ] && + kx022a_scale_table[n][1 ] == val2)
Ditto.
Quoted 19 lines
drivers/iio/accel/kionix-kx022a.c new file +19
-0+break ; +if (n <0 ) { + ret = -EINVAL ; + goto unlock_out; + } + + ret =kx022a_turn_off_lock (data); +if (ret) +break ; + + ret =regmap_update_bits (data->regmap,KX022A_REG_CNTL , +KX022A_MASK_GSEL , + n <<KX022A_GSEL_SHIFT ); +kx022a_turn_on_unlock (data); +break ; +default : + ret = -EINVAL ; +break ; + }
...
drivers/iio/accel/kionix-kx022a.c line 464
Quoted 12 lines
drivers/iio/accel/kionix-kx022a.c new file +12
-0+static int kx022a_get_axis (struct kx022a_data *data, +struct iio_chan_spec const *chan, +int *val) +{ +int ret; + + ret =regmap_bulk_read (data->regmap, chan->address, &data->buffer, +sizeof (__le16)); +if (ret) +return ret; + + *val =le16_to_cpu (data->buffer[0 ]);
'p'-variant of the above would look better
*val = le16_to_cpup(data->buffer);
since it will be the same as above address without any additional arithmetics.
Quoted 2 lines
(quoted diff) +2
-0+ return IIO_VAL_INT; +}
...
Quoted 6 lines
drivers/iio/accel/kionix-kx022a.c new file +6
-0+case IIO_CHAN_INFO_SAMP_FREQ : + ret =regmap_read (data->regmap,KX022A_REG_ODCNTL , ®val); +if (ret) +return ret; + + if ((regval & KX022A_MASK_ODR) >
drivers/iio/accel/kionix-kx022a.c line 504
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +9
-0+ ARRAY_SIZE(kx022a_accel_samp_freq_table)) { +dev_err (data->dev,"Invalid ODR\n" ); +return -EINVAL ; + } + +kx022a_reg2freq (regval, val, val2); + ret =IIO_VAL_INT_PLUS_MICRO ; + +break ;
return IIO_VAL_INT_PLUS_MICRO;
drivers/iio/accel/kionix-kx022a.c line 514
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +10
-0+ +case IIO_CHAN_INFO_SCALE : + ret =regmap_read (data->regmap,KX022A_REG_CNTL , ®val); +if (ret <0 ) +return ret; + +kx022a_reg2scale (regval, val, val2); + + ret =IIO_VAL_INT_PLUS_MICRO ; +break ;
Ditto.
...
drivers/iio/accel/kionix-kx022a.c line 597
Quoted 1 line
drivers/iio/accel/kionix-kx022a.c new file +1
-0+return regmap_write (data->regmap,KX022A_REG_BUF_CLEAR ,0x0 );
Would simple '0' suffice?
...
drivers/iio/accel/kionix-kx022a.c line 691
Quoted 3 lines
drivers/iio/accel/kionix-kx022a.c new file +3
-0+for (i =0 ; i < count; i++) { +int bit; +u16 *samples = &buffer[i *3 ];
I would put it as
u16 *samples = &buffer[i * 3]; int bit;
drivers/iio/accel/kionix-kx022a.c line 695
Quoted 3 lines
drivers/iio/accel/kionix-kx022a.c new file +3
-0+for_each_set_bit (bit, idev->active_scan_mask,AXIS_MAX ) +memcpy (&data->scan.channels[bit], &samples[bit], +sizeof (data->scan.channels[0 ]));
Why not use bit instead of 0 for the sake of consistency?
Also might be good to have a temporary for channels:
... *chs = data->scan.channels; for_each_set_bit(bit, idev->active_scan_mask, AXIS_MAX) memcpy(&chs[bit], &samples[bit], sizeof(chs[bit]));
Quoted 4 lines
drivers/iio/accel/kionix-kx022a.c new file +4
-0+iio_push_to_buffers_with_timestamp (idev, &data->scan, tstamp); + + tstamp += sample_period; + }
...
Review
Quoted 2 lines
(quoted diff) +2
-0+ ret = regmap_clear_bits(data->regmap, data->ien_reg, + KX022A_MASK_WMI);
I don't see why it's not on a single line. Even if you are a conservative adept of 80.
Maybe other lines also need to be revised?
Quoted 2 lines
(quoted diff) +2
-0+ if (ret) + goto unlock_out;
...
Quoted 4 lines
drivers/iio/accel/kionix-kx022a.c new file +4
-0+int ret =IRQ_NONE ; + +mutex_lock (&data->mutex); +
drivers/iio/accel/kionix-kx022a.c line 910
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +9
-0+if (data->trigger_enabled) { +iio_trigger_poll_chained (data->trig); + ret =IRQ_HANDLED ; + } + +if (data->state &KX022A_STATE_FIFO ) { + ret =__kx022a_fifo_flush (idev,KX022A_FIFO_LENGTH , true); +if (ret >0 ) + ret =IRQ_HANDLED ;
I don't like it. Perhaps
bool handled = false; int ret; ... ret = ... if (ret > 0) handled = true; ... return IRQ_RETVAL(handled);
Quoted 5 lines
drivers/iio/accel/kionix-kx022a.c new file +5
-0+ } + +mutex_unlock (&data->mutex); + +return ret;
...
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (!dev) + return -ENODEV;
Do you really need this check?
...
drivers/iio/accel/kionix-kx022a.c line 1045
Quoted 3 lines
drivers/iio/accel/kionix-kx022a.c new file +3
-0+ fw =dev_fwnode (dev); +if (!fw) +return -ENODEV ;
You may combine these two in one.
struct fwnode_handle *fwnode; fwnode = dev ? dev_fwnode(dev) : NULL; if (!fwnode) return -ENODEV;
And please, call it fwnode.
...
drivers/iio/accel/kionix-kx022a.c line 1052
Quoted 6 lines
drivers/iio/accel/kionix-kx022a.c new file +6
-0+ irq =fwnode_irq_get_byname (fw,"INT1" ); +if (irq >0 ) { + data->inc_reg =KX022A_REG_INC1 ; + data->ien_reg =KX022A_REG_INC4 ; + +if (fwnode_irq_get_byname (dev_fwnode (dev),"INT2" ) >0 )
Why not use fwnode again
drivers/iio/accel/kionix-kx022a.c line 1055
Quoted 3 lines
drivers/iio/accel/kionix-kx022a.c new file +3
-0+dev_warn (dev,"Only one IRQ supported\n" ); + }else { + irq =fwnode_irq_get_byname (dev_fwnode (dev),"INT2" );
Ditto.
Quoted 6 lines
drivers/iio/accel/kionix-kx022a.c new file +6
-0+if (irq <=0 ) +return dev_err_probe (dev, irq,"No suitable IRQ\n" ); + + data->inc_reg =KX022A_REG_INC5 ; + data->ien_reg =KX022A_REG_INC6 ; + }
...
drivers/iio/accel/kionix-kx022a.c line 1107
Quoted 4 lines
drivers/iio/accel/kionix-kx022a.c new file +4
-0+if (ret) +return dev_err_probe (data->dev, ret, +"iio_triggered_buffer_setup_ext FAIL %d\n" , + ret);
Drop dup ret at the end, dev_err_probe() has been adding it to each message.
...
drivers/iio/accel/kionix-kx022a.c line 1133
Quoted 6 lines
drivers/iio/accel/kionix-kx022a.c new file +6
-0+/* +* No need to check for NULL. request_threadedI_irq() defaults to +* dev_name() should the alloc fail. +*/ + name =devm_kasprintf (data->dev,GFP_KERNEL ,"%s-kx022a" , +dev_name (data->dev));
It's not clear why do you need a suffix here.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Matti Vaittinen
maintainerRe: [PATCH v3 2/3] iio: accel: Support Kionix/ROHM KX022A accelerometer
Hi Andy & All,
Thanks again for the review.
Quoted 21 lines · Andy Shevchenko
Quoted 11 lines · Matti Vaittinen
KX022A is a 3-axis accelerometer from ROHM/Kionix. The sensor features include variable ODRs, I2C and SPI control, FIFO/LIFO with watermark IRQ, tap/motion detection, wake-up & back-to-sleep events, four acceleration ranges (2, 4, 8 and 16g) and probably some other cool features.
Add support for the basic accelerometer features such as getting the acceleration data via IIO. (raw reads, triggered buffer [data-ready] or using the WMI IRQ).
Important things to be added include the double-tap, motion detection and wake-up as well as the runtime power management.
...
drivers/iio/accel/kionix-kx022a-i2c.c line 22
Quoted 3 lines
drivers/iio/accel/kionix-kx022a-i2c.c new file +3
-0+if (!i2c->irq) { +dev_err (dev,"No IRQ configured\n" ); +return -EINVAL ;At least
Quoted 4 lines
return dev_err_probe(...);for know error codes (or when we know that there won't be
EPROBE_DEFER), takes less LoCs in the source file.
I think we discussed this already (and disagreed). To me it looks plain ugly to have hard-coded return value in dev_err_probe(). That's why I prefer the
Quoted 2 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ dev_err(dev, "No IRQ configured\n"); + return -EINVAL;
when -EINVAL is hard-coded. On the other hand, your comment below is very valid...
Quoted 10 lines
Quoted 2 lines
(quoted diff) +1
-0+ }...
Quoted 5 lines
drivers/iio/accel/kionix-kx022a-i2c.c new file +4
-0+ regmap =devm_regmap_init_i2c (i2c, &kx022a_regmap); +if (IS_ERR (regmap)) { +dev_err (dev,"Failed to initialize Regmap\n" ); +return PTR_ERR (regmap);Ditto here and anywhere else for the similar cases.
...Yes. This is different from the case above, and I agree the dev_err_probe() should be used here. Thanks for pointing it out. I'll change this and the one in SPI driver as well.
Quoted 5 lines
Quoted 2 lines
(quoted diff) +1
-0+ }...
Quoted 12 lines
drivers/iio/accel/kionix-kx022a.c line 304
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +10
-0+case IIO_CHAN_INFO_SAMP_FREQ : + *vals = (const int *)kx022a_accel_samp_freq_table; + *length =ARRAY_SIZE (kx022a_accel_samp_freq_table) *2 ; + *type =IIO_VAL_INT_PLUS_MICRO ; +return IIO_AVAIL_LIST ; +case IIO_CHAN_INFO_SCALE : + *vals = (const int *)kx022a_scale_table; + *length =ARRAY_SIZE (kx022a_scale_table) *2 ; + *type =IIO_VAL_INT_PLUS_MICRO ; +return IIO_AVAIL_LIST ;These ' * 2' can be replaced with respective
ARRAY_SIZE()of nested element
To me this sounds good. I'll see how it would look like.
Quoted 19 lines
...
Quoted 4 lines
drivers/iio/accel/kionix-kx022a.c new file +4
-0+static int kx022a_turn_on_off_unlocked (struct kx022a_data *data,bool on) +{ +int ret; +drivers/iio/accel/kionix-kx022a.c line 341
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +10
-0+if (on) + ret =regmap_set_bits (data->regmap,KX022A_REG_CNTL , +KX022A_MASK_PC1 ); +else + ret =regmap_clear_bits (data->regmap,KX022A_REG_CNTL , +KX022A_MASK_PC1 ); + +if (ret) +dev_err (data->dev,"Turn %s fail %d\n" , (on) ?"ON" :"OFF" , + ret);
str_on_off()?
Never heard of that before. Seems we have all kinds of gadgets in kernel :) I deeply dislike how ternary looks like so I will gladly hide it in str_on_off() - thanks!
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c line 395
Quoted 7 lines
drivers/iio/accel/kionix-kx022a.c new file +7
-0+switch (mask) { +case IIO_CHAN_INFO_SAMP_FREQ : + n =ARRAY_SIZE (kx022a_accel_samp_freq_table); + +while (n--) +if (val == kx022a_accel_samp_freq_table[n][0 ] && + kx022a_accel_samp_freq_table[n][1 ] == val2)Why not to use the same kind of l and r arguments in == lines? In current form it's a bit harder to see what the catch here.
As to why I didn't - because for me the order does not matter regarding how hard it is to catch the meaning here. However, there is no problem changing this because the order does not matter for me :)
Quoted 18 lines
...
drivers/iio/accel/kionix-kx022a.c line 464
Quoted 12 lines
drivers/iio/accel/kionix-kx022a.c new file +12
-0+static int kx022a_get_axis (struct kx022a_data *data, +struct iio_chan_spec const *chan, +int *val) +{ +int ret; + + ret =regmap_bulk_read (data->regmap, chan->address, &data->buffer, +sizeof (__le16)); +if (ret) +return ret; + + *val =le16_to_cpu (data->buffer[0 ]);'p'-variant of the above would look better
Quoted 4 lines
*val = le16_to_cpup(data->buffer);since it will be the same as above address without any additional arithmetics.
I guess there is no significant performance difference? To my eye the le16_to_cpu(data->buffer[0]) is much more clear. I see right from the call that we have an array here and use the first member. If there is no obvious technical merit for using le16_to_cpup(data->buffer) over le16_to_cpu(data->buffer[0]), then I do really prefer the latter for clarity.
Quoted 9 lines
Quoted 2 lines
(quoted diff) +2
-0+ return IIO_VAL_INT; +}...
drivers/iio/accel/kionix-kx022a.c line 597
Quoted 1 line
drivers/iio/accel/kionix-kx022a.c new file +1
-0+return regmap_write (data->regmap,KX022A_REG_BUF_CLEAR ,0x0 );Would simple '0' suffice?
Technically, yes. I however prefer having the register values in hex - unless they directly map to some meaningful physical world entity that is easier to understand when in decimal. (For example, a register which content would directly represent millivolts or divider or any such meaningful physical entity).
Quoted 10 lines
...
drivers/iio/accel/kionix-kx022a.c line 691
Quoted 3 lines
drivers/iio/accel/kionix-kx022a.c new file +3
-0+for (i =0 ; i < count; i++) { +int bit; +u16 *samples = &buffer[i *3 ];I would put it as
u16 *samples = &buffer[i * 3]; int bit;
Well, you know my opinion but Ok ;)
Now I also noticed that the name of the block scoped variable 'samples' collides with the function scoped variable of same name. I'll rename the block scoped 'samples' just to avoid confusion.
Quoted 6 lines
drivers/iio/accel/kionix-kx022a.c line 695
Quoted 4 lines
drivers/iio/accel/kionix-kx022a.c new file +3
-0+for_each_set_bit (bit, idev->active_scan_mask,AXIS_MAX ) +memcpy (&data->scan.channels[bit], &samples[bit], +sizeof (data->scan.channels[0 ]));Why not use bit instead of 0 for the sake of consistency?
Because, again, using 0 is clearer to me. It leaves zero room for wondering :)
Quoted 4 lines
Also might be good to have a temporary for channels:
... *chs = data->scan.channels;
I think we have discussed this too previously somewhere. I do dislike hiding things in temporary variables. I like seeing that we are really using the driver private data and not some stack variable and only use temporary variables when they significantly reduce the line count.
However, in this particular case I can scope the temporary variable in this smallish block of code - which makes it pretty easy to spot we are using the data->scan.channel underneath (as the chs is assigned just a row above). And it helps us avoid line split so ... Ok.
Quoted 12 lines
for_each_set_bit(bit, idev->active_scan_mask, AXIS_MAX) memcpy(&chs[bit], &samples[bit], sizeof(chs[bit]));Quoted 4 lines
drivers/iio/accel/kionix-kx022a.c new file +4
-0+iio_push_to_buffers_with_timestamp (idev, &data->scan, tstamp); + + tstamp += sample_period; + }...
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ ret = regmap_clear_bits(data->regmap, data->ien_reg, + KX022A_MASK_WMI);I don't see why it's not on a single line. Even if you are a conservative adept of 80.
Good catch. Thanks.
Quoted 19 lines
...
Quoted 4 lines
drivers/iio/accel/kionix-kx022a.c new file +4
-0+int ret =IRQ_NONE ; + +mutex_lock (&data->mutex); +drivers/iio/accel/kionix-kx022a.c line 910
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +9
-0+if (data->trigger_enabled) { +iio_trigger_poll_chained (data->trig); + ret =IRQ_HANDLED ; + } + +if (data->state &KX022A_STATE_FIFO ) { + ret =__kx022a_fifo_flush (idev,KX022A_FIFO_LENGTH , true); +if (ret >0 ) + ret =IRQ_HANDLED ;I don't like it. Perhaps
Quoted 10 lines
bool handled = false; int ret; ... ret = ... if (ret > 0) handled = true; ... return IRQ_RETVAL(handled);
I don't see the benefit of adding another variable 'handled'.
If I understand correctly, it just introduces one extra 'if' in IRQ thread handling while hiding the return value in IRQ_RETVAL() - macro.
I do like seeing the IRQ_NONE being returned by default and IRQ_HANDLED only when "handlers" are successfully executed. Adding extra variable just obfuscates this (from my eyes) while adding also the additional 'if'.
Quoted 9 lines
Quoted 6 lines
drivers/iio/accel/kionix-kx022a.c new file +5
-0+ } + +mutex_unlock (&data->mutex); + +return ret;...
Quoted 4 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (!dev) + return -ENODEV;Do you really need this check?
Good question. In principle I do like checking the parameters of exported calls. OTOH, this export is now done using the driver namespace so yes, I think we can drop the check.
Quoted 9 lines
...
drivers/iio/accel/kionix-kx022a.c line 1045
Quoted 3 lines
drivers/iio/accel/kionix-kx022a.c new file +3
-0+ fw =dev_fwnode (dev); +if (!fw) +return -ENODEV ;You may combine these two in one.
Quoted 6 lines
struct fwnode_handle *fwnode; fwnode = dev ? dev_fwnode(dev) : NULL; if (!fwnode) return -ENODEV;
I just drop the check for !dev. But even if I didn't, I wouldn't use ternary here - to me it is _much_ harder to read compared to two separate ifs while giving no obvious benefits.
Quoted 1 line
And please, call it fwnode.
Ok. I personally like fw more - probably because I'm used to that - but I guess the 'fwnode' is used in number of other places. Thanks.
Quoted 10 lines
...
drivers/iio/accel/kionix-kx022a.c line 1052
Quoted 6 lines
drivers/iio/accel/kionix-kx022a.c new file +6
-0+ irq =fwnode_irq_get_byname (fw,"INT1" ); +if (irq >0 ) { + data->inc_reg =KX022A_REG_INC1 ; + data->ien_reg =KX022A_REG_INC4 ; + +if (fwnode_irq_get_byname (dev_fwnode (dev),"INT2" ) >0 )Why not use fwnode again
I think I've beeen distracted while writing this part :) I guess I have added the temporary variable 'fw' just for the purpose of being able to call the dev_fwnode() just once. So, Thanks!
Quoted 9 lines
...
drivers/iio/accel/kionix-kx022a.c line 1107
Quoted 4 lines
drivers/iio/accel/kionix-kx022a.c new file +4
-0+if (ret) +return dev_err_probe (data->dev, ret, +"iio_triggered_buffer_setup_ext FAIL %d\n" , + ret);Drop dup ret at the end,
dev_err_probe()has been adding it to each message.
Thanks!
Quoted 12 lines
...
drivers/iio/accel/kionix-kx022a.c line 1133
Quoted 6 lines
drivers/iio/accel/kionix-kx022a.c new file +6
-0+/* +* No need to check for NULL. request_threadedI_irq() defaults to +* dev_name() should the alloc fail. +*/ + name =devm_kasprintf (data->dev,GFP_KERNEL ,"%s-kx022a" , +dev_name (data->dev));It's not clear why do you need a suffix here.
Because for example just "spi0,0" is much less informative compared to "spi0.0-kx022a". As an user I like seeing the device generating the IRQ. I don't wan't to dig out details like which bus/chipselect my device is connected to - especially if I have only one accelerometer connected. The dev_name() is used just to make this unique for cases where we could have multiple similar devices connected to the system (as you suggested in previous review).
Once again, thanks for the review! I appreciate your help/suggestions.
Yours
-- Matti
Signature · 5 lines
Matti Vaittinen Linux kernel developer at ROHM Semiconductors Oulu Finland ~~ When things go utterly wrong vim users can always type :help! ~~
Re: [PATCH v3 2/3] iio: accel: Support Kionix/ROHM KX022A accelerometer
Quoted 2 lines · Matti Vaittinen
Quoted 1 line · Andy Shevchenko
On Thu, Oct 20, 2022 at 02:37:15PM +0300, Matti Vaittinen wrote:
...
Quoted 14 lines
Quoted 9 lines
drivers/iio/accel/kionix-kx022a.c line 464
Quoted 6 lines
drivers/iio/accel/kionix-kx022a.c new file +6
-0+ ret =regmap_bulk_read (data->regmap, chan->address, &data->buffer, +sizeof (__le16)); +if (ret) +return ret; + + *val =le16_to_cpu (data->buffer[0 ]);'p'-variant of the above would look better
Quoted 4 lines
*val = le16_to_cpup(data->buffer);since it will be the same as above address without any additional arithmetics.
Quoted 6 lines
I guess there is no significant performance difference? To my eye the
le16_to_cpu(data->buffer[0])is much more clear. I see right from the call that we have an array here and use the first member. If there is no obvious technical merit for usingle16_to_cpup(data->buffer)overle16_to_cpu(data->buffer[0]), then I do really prefer the latter for clarity.
Then you probably wanted to have &data->buffer[0] as a parameter to regmap_bulk_read()?
...
Quoted 24 lines
Quoted 13 lines
drivers/iio/accel/kionix-kx022a.c line 910
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +9
-0+if (data->trigger_enabled) { +iio_trigger_poll_chained (data->trig); + ret =IRQ_HANDLED ; + } + +if (data->state &KX022A_STATE_FIFO ) { + ret =__kx022a_fifo_flush (idev,KX022A_FIFO_LENGTH , true); +if (ret >0 ) + ret =IRQ_HANDLED ;I don't like it. Perhaps
Quoted 10 lines
bool handled = false; int ret; ... ret = ... if (ret > 0) handled = true; ... return IRQ_RETVAL(handled);
Quoted 7 lines
I don't see the benefit of adding another variable 'handled'. If I understand correctly, it just introduces one extra 'if' in IRQ thread handling while hiding the return value in
IRQ_RETVAL()- macro.I do like seeing the
IRQ_NONEbeing returned by default andIRQ_HANDLEDonly when "handlers" are successfully executed. Adding extra variable just obfuscates this (from my eyes) while adding also the additional 'if'.
You assigning semantically different values to the same variable inside the function.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Matti Vaittinen
maintainerRe: [PATCH v3 2/3] iio: accel: Support Kionix/ROHM KX022A accelerometer
Quoted 27 lines · Andy Shevchenko
Quoted 2 lines · Matti Vaittinen
Quoted 1 line · Andy Shevchenko
On Thu, Oct 20, 2022 at 02:37:15PM +0300, Matti Vaittinen wrote:
...
Quoted 14 lines
Quoted 9 lines
drivers/iio/accel/kionix-kx022a.c line 464
Quoted 6 lines
drivers/iio/accel/kionix-kx022a.c new file +6
-0+ ret =regmap_bulk_read (data->regmap, chan->address, &data->buffer, +sizeof (__le16)); +if (ret) +return ret; + + *val =le16_to_cpu (data->buffer[0 ]);'p'-variant of the above would look better
Quoted 4 lines
*val = le16_to_cpup(data->buffer);since it will be the same as above address without any additional arithmetics.
Quoted 6 lines
I guess there is no significant performance difference? To my eye the
le16_to_cpu(data->buffer[0])is much more clear. I see right from the call that we have an array here and use the first member. If there is no obvious technical merit for usingle16_to_cpup(data->buffer)overle16_to_cpu(data->buffer[0]), then I do really prefer the latter for clarity.
Quoted 2 lines
Then you probably wanted to have &data->buffer[0] as a parameter to
regmap_bulk_read()?
Yes! Thanks.
Quoted 31 lines
...
Quoted 28 lines
Quoted 13 lines
drivers/iio/accel/kionix-kx022a.c line 910
Quoted 10 lines
drivers/iio/accel/kionix-kx022a.c new file +9
-0+if (data->trigger_enabled) { +iio_trigger_poll_chained (data->trig); + ret =IRQ_HANDLED ; + } + +if (data->state &KX022A_STATE_FIFO ) { + ret =__kx022a_fifo_flush (idev,KX022A_FIFO_LENGTH , true); +if (ret >0 ) + ret =IRQ_HANDLED ;I don't like it. Perhaps
Quoted 10 lines
bool handled = false; int ret; ... ret = ... if (ret > 0) handled = true; ... return IRQ_RETVAL(handled);I don't see the benefit of adding another variable 'handled'. If I understand correctly, it just introduces one extra 'if' in IRQ thread handling while hiding the return value in
IRQ_RETVAL()- macro.
Quoted 6 lines
Quoted 3 lines
I do like seeing the
IRQ_NONEbeing returned by default andIRQ_HANDLEDonly when "handlers" are successfully executed. Adding extra variable just obfuscates this (from my eyes) while adding also the additional 'if'.You assigning semantically different values to the same variable inside the function.
Ah, yes! This was really a bug making it way in. I guess you may just have saved me from some not-that-funny debugging session... Well spotted!
I still don't like hiding the IRQ_HANDLED / IRQ_NONE. I'll just go for
if (data->state & KX022A_STATE_FIFO) {
int ok;
ok = __kx022a_fifo_flush(idev, KX022A_FIFO_LENGTH,
true);
if (ok > 0)
ret = IRQ_HANDLED;
}for v4. (Which I try to send still today before my memory is flushed by the weekend :])
Thanks a lot!
Yours
-- Matti
Signature · 5 lines
Matti Vaittinen Linux kernel developer at ROHM Semiconductors Oulu Finland ~~ When things go utterly wrong vim users can always type :help! ~~
Matti Vaittinen
maintainerPATCH v3 3/3 MAINTAINERS: Add KX022A maintainer entry
In reply to Matti VaittinenAdd maintainer entry for ROHM/Kionix KX022A accelerometer sensor driver.
--- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+)
MAINTAINERS +5 -0
@@ -11435,6 +11435,11 @@ F: drivers/mfd/khadas-mcu.c F: include/linux/mfd/khadas-mcu.h F: drivers/thermal/khadas_mcu_fan.c +KIONIX/ROHM KX022A ACCELEROMETER +R: Matti Vaittinen <[email protected]> +S: Supported +F: drivers/iio/accel/kionix-kx022a* + KMEMLEAK M: Catalin Marinas <[email protected]> S: Maintained
Signature · 14 lines
2.37.3 -- Matti Vaittinen, Linux device drivers ROHM Semiconductors, Finland SWDC Kiviharjunlenkki 1E 90220 OULU FINLAND ~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~ Simon says - in Latin please. ~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~ Thanks to Simon Glass for the translation =]
Matti Vaittinen
maintainerQuoted 11 lines · Matti Vaittinen
Add initial support for ROHM/Kionix kx022a accelerometer
About the HW:
KX022A accelerometer is a sensor which:
- supports G-ranges of (+/-) 2, 4, 8, and 16G
- can be connected to I2C or SPI
- has internal HW FIFO buffer
- supports various ODRs (output data rates)
- support detecting special events like double tap or motion
- can be configured to wake-up system when events are detected.
Quoted 8 lines
About the series:
This series adds support for only getting the accelerometer data and configuring the G-range / ODR via IIO. Motion detection or double-tap detection are not supported by the series. The other quite important but still missing piece is the runtime PM. Nevertheless, the driver should be usable and brings the basic support for getting accelerometer data.
// snip
Quoted 4 lines
base-commit:
568035b01cfb107af8d2e4bd2fb9aea22cf5b868
prerequisite-patch-id:f692b7ef9ce0a0b016fb5ac1c5733e562baa4ae2
prerequisite-patch-id:cc2e849e2b3fe553fe955f21a4b995681e04383f
prerequisite-patch-id:f136637f7a8fe92dc4f60b908e2e7aa24aac3f43
// Snip.
Sorry folks! I don't know what happened with my format-patch :( I Should've noted this before sending. My apologies.
Signature · 5 lines
Matti Vaittinen Linux kernel developer at ROHM Semiconductors Oulu Finland ~~ When things go utterly wrong vim users can always type :help! ~~
Matti Vaittinen
maintainerQuoted 4 lines · Matti Vaittinen
Quoted 2 lines · Matti Vaittinen
Add initial support for ROHM/Kionix kx022a accelerometer
Sorry folks! I don't know what happened with my format-patch :(
And now I see it. -EINVALID_USER. I typoed the --base and used --base=v6.0-rc1 not --base=v6.1-rc1
Sorry once again - I hope I didn't kill your build scripts / inboxes :(
Yours
-- Matti
Signature · 5 lines
Matti Vaittinen Linux kernel developer at ROHM Semiconductors Oulu Finland ~~ When things go utterly wrong vim users can always type :help! ~~