* [PATCH v2 0/6] iio: bmi160: cleanups and hardware fifo support @ 2016-12-08 14:22 Marcin Niestroj [not found] ` <20161208142259.26230-1-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Marcin Niestroj @ 2016-12-08 14:22 UTC (permalink / raw) To: Jonathan Cameron Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Marcin Niestroj Hi, This patch series consists of cleanups, of device tables, device-tree bindings documentation and finally support for hardware FIFO. Patches have been rebased and tested on 4.9.0-rc8. Changes v1 -> v2: * add of device tables for spi and i2c (suggested by Jonathan) * device-tree bindings documentation: remove "gpio" keyword from interrupts property description, describe "INT1" and "INT2" cases for interrupt-names property (suggested by Rob) * introduce mutex protection of data transmission as a separate patch (suggested by Peter) * fix time needed to sleep after command execution * add __ prefix to all functions that should be called with mutex held (suggested by Peter) * get rid of non-constant array size (suggested by Peter) * disable irq on init failure and module removal (suggested by Peter) * make bmi160_buffer_predisable() the reverse order of the bmi160_buffer_postenable() (suggested by Jonathan) * remove realignment for iio_info structs (suggested by Jonathan) Marcin Niestroj (6): iio: bmi160: Add of device table for i2c iio: bmi160: Add of device table for spi Documentation: DT: Add bmi160 imu binding iio: bmi160: Protect data transmission with mutex iio: bmi160: Fix time needed to sleep after command execution iio: bmi160: Support hardware fifo .../devicetree/bindings/iio/imu/bmi160.txt | 36 ++ drivers/iio/imu/bmi160/bmi160.h | 3 +- drivers/iio/imu/bmi160/bmi160_core.c | 678 +++++++++++++++++++-- drivers/iio/imu/bmi160/bmi160_i2c.c | 21 +- drivers/iio/imu/bmi160/bmi160_spi.c | 21 +- 5 files changed, 711 insertions(+), 48 deletions(-) create mode 100644 Documentation/devicetree/bindings/iio/imu/bmi160.txt -- 2.10.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <20161208142259.26230-1-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org>]
* [PATCH v2 1/6] iio: bmi160: Add of device table for i2c [not found] ` <20161208142259.26230-1-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> @ 2016-12-08 14:22 ` Marcin Niestroj [not found] ` <20161208142259.26230-2-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-08 14:22 ` [PATCH v2 2/6] iio: bmi160: Add of device table for spi Marcin Niestroj ` (4 subsequent siblings) 5 siblings, 1 reply; 14+ messages in thread From: Marcin Niestroj @ 2016-12-08 14:22 UTC (permalink / raw) To: Jonathan Cameron Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Marcin Niestroj >From now on we can add bmi160 device to device-tree by specifying compatible string. Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> --- Patch introduced in v2 drivers/iio/imu/bmi160/bmi160_i2c.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 07a179d..155a31f 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -11,10 +11,11 @@ * - 0x68 if SDO is pulled to GND * - 0x69 if SDO is pulled to VDDIO */ -#include <linux/module.h> +#include <linux/acpi.h> #include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> #include <linux/regmap.h> -#include <linux/acpi.h> #include "bmi160.h" @@ -56,10 +57,19 @@ static const struct acpi_device_id bmi160_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match); +#ifdef CONFIG_OF +static const struct of_device_id bmi160_of_match[] = { + { .compatible = "bosch,bmi160" }, + { }, +}; +MODULE_DEVICE_TABLE(of, bmi160_of_match); +#endif + static struct i2c_driver bmi160_i2c_driver = { .driver = { .name = "bmi160_i2c", .acpi_match_table = ACPI_PTR(bmi160_acpi_match), + .of_match_table = of_match_ptr(bmi160_of_match), }, .probe = bmi160_i2c_probe, .remove = bmi160_i2c_remove, -- 2.10.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <20161208142259.26230-2-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org>]
* Re: [PATCH v2 1/6] iio: bmi160: Add of device table for i2c [not found] ` <20161208142259.26230-2-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> @ 2016-12-30 10:47 ` Jonathan Cameron 0 siblings, 0 replies; 14+ messages in thread From: Jonathan Cameron @ 2016-12-30 10:47 UTC (permalink / raw) To: Marcin Niestroj Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA On 08/12/16 14:22, Marcin Niestroj wrote: > From now on we can add bmi160 device to device-tree by specifying > compatible string. > > Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> Other than the fact this should really have been two patches, this looks good. Applied to the togreg branch of iio.git and pushed out as testing for the autobuilders to play with it. Thanks, Jonathan > --- > Patch introduced in v2 > > drivers/iio/imu/bmi160/bmi160_i2c.c | 14 ++++++++++++-- > 1 file changed, 12 insertions(+), 2 deletions(-) > > diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c > index 07a179d..155a31f 100644 > --- a/drivers/iio/imu/bmi160/bmi160_i2c.c > +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c > @@ -11,10 +11,11 @@ > * - 0x68 if SDO is pulled to GND > * - 0x69 if SDO is pulled to VDDIO > */ > -#include <linux/module.h> > +#include <linux/acpi.h> > #include <linux/i2c.h> > +#include <linux/module.h> > +#include <linux/of.h> > #include <linux/regmap.h> > -#include <linux/acpi.h> Whilst I have no objection to reordering headers so they are alphabetical (as long as not clarity is lost) it should really be in it's own patch... > > #include "bmi160.h" > > @@ -56,10 +57,19 @@ static const struct acpi_device_id bmi160_acpi_match[] = { > }; > MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match); > > +#ifdef CONFIG_OF > +static const struct of_device_id bmi160_of_match[] = { > + { .compatible = "bosch,bmi160" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, bmi160_of_match); > +#endif > + > static struct i2c_driver bmi160_i2c_driver = { > .driver = { > .name = "bmi160_i2c", > .acpi_match_table = ACPI_PTR(bmi160_acpi_match), > + .of_match_table = of_match_ptr(bmi160_of_match), > }, > .probe = bmi160_i2c_probe, > .remove = bmi160_i2c_remove, > -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 2/6] iio: bmi160: Add of device table for spi [not found] ` <20161208142259.26230-1-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-08 14:22 ` [PATCH v2 1/6] iio: bmi160: Add of device table for i2c Marcin Niestroj @ 2016-12-08 14:22 ` Marcin Niestroj 2016-12-08 14:22 ` [PATCH v2 3/6] Documentation: DT: Add bmi160 imu binding Marcin Niestroj ` (3 subsequent siblings) 5 siblings, 0 replies; 14+ messages in thread From: Marcin Niestroj @ 2016-12-08 14:22 UTC (permalink / raw) To: Jonathan Cameron Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Marcin Niestroj >From now on we can add bmi160 device to device-tree by specifying compatible string. Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> --- Patch introduced in v2 drivers/iio/imu/bmi160/bmi160_spi.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index 1ec8b12..d34dfdf 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -7,10 +7,11 @@ * the GNU General Public License. See the file COPYING in the main * directory of this archive for more details. */ +#include <linux/acpi.h> #include <linux/module.h> -#include <linux/spi/spi.h> +#include <linux/of.h> #include <linux/regmap.h> -#include <linux/acpi.h> +#include <linux/spi/spi.h> #include "bmi160.h" @@ -47,13 +48,22 @@ static const struct acpi_device_id bmi160_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match); +#ifdef CONFIG_OF +static const struct of_device_id bmi160_of_match[] = { + { .compatible = "bosch,bmi160" }, + { }, +}; +MODULE_DEVICE_TABLE(of, bmi160_of_match); +#endif + static struct spi_driver bmi160_spi_driver = { .probe = bmi160_spi_probe, .remove = bmi160_spi_remove, .id_table = bmi160_spi_id, .driver = { - .acpi_match_table = ACPI_PTR(bmi160_acpi_match), - .name = "bmi160_spi", + .acpi_match_table = ACPI_PTR(bmi160_acpi_match), + .of_match_table = of_match_ptr(bmi160_of_match), + .name = "bmi160_spi", }, }; module_spi_driver(bmi160_spi_driver); -- 2.10.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 3/6] Documentation: DT: Add bmi160 imu binding [not found] ` <20161208142259.26230-1-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-08 14:22 ` [PATCH v2 1/6] iio: bmi160: Add of device table for i2c Marcin Niestroj 2016-12-08 14:22 ` [PATCH v2 2/6] iio: bmi160: Add of device table for spi Marcin Niestroj @ 2016-12-08 14:22 ` Marcin Niestroj [not found] ` <20161208142259.26230-4-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-08 14:22 ` [PATCH v2 4/6] iio: bmi160: Protect data transmission with mutex Marcin Niestroj ` (2 subsequent siblings) 5 siblings, 1 reply; 14+ messages in thread From: Marcin Niestroj @ 2016-12-08 14:22 UTC (permalink / raw) To: Jonathan Cameron Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Marcin Niestroj This adds documentation for Bosch BMI160 Inertial Measurement Unit device-tree bindings. Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> --- Changes v1 -> v2 (suggested by Rob): * remove "gpio" keyword from interrupts property description * describe "INT1" and "INT2" cases for interrupt-names property .../devicetree/bindings/iio/imu/bmi160.txt | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/bmi160.txt diff --git a/Documentation/devicetree/bindings/iio/imu/bmi160.txt b/Documentation/devicetree/bindings/iio/imu/bmi160.txt new file mode 100644 index 0000000..ae0112c --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/bmi160.txt @@ -0,0 +1,36 @@ +Bosch BMI160 - Inertial Measurement Unit with Accelerometer, Gyroscope +and externally connectable Magnetometer + +https://www.bosch-sensortec.com/bst/products/all_products/bmi160 + +Required properties: + - compatible : should be "bosch,bmi160" + - reg : the I2C address or SPI chip select number of the sensor + - spi-max-frequency : set maximum clock frequency (only for SPI) + +Optional properties: + - interrupt-parent : should be the phandle of the interrupt controller + - interrupts : interrupt mapping for IRQ, must be IRQ_TYPE_LEVEL_LOW + - interrupt-names : set to "INT1" if INT1 pin should be used as interrupt + input, set to "INT2" if INT2 pin should be used instead + +Examples: + +bmi160@68 { + compatible = "bosch,bmi160"; + reg = <0x68>; + + interrupt-parent = <&gpio4>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "INT1"; +}; + +bmi160@0 { + compatible = "bosch,bmi160"; + reg = <0>; + spi-max-frequency = <10000000>; + + interrupt-parent = <&gpio2>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + interrupt-names = "INT2"; +}; -- 2.10.2 ^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <20161208142259.26230-4-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org>]
* Re: [PATCH v2 3/6] Documentation: DT: Add bmi160 imu binding [not found] ` <20161208142259.26230-4-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> @ 2016-12-12 17:15 ` Rob Herring 2016-12-30 10:40 ` Jonathan Cameron 0 siblings, 1 reply; 14+ messages in thread From: Rob Herring @ 2016-12-12 17:15 UTC (permalink / raw) To: Marcin Niestroj Cc: Jonathan Cameron, Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA On Thu, Dec 08, 2016 at 03:22:56PM +0100, Marcin Niestroj wrote: > This adds documentation for Bosch BMI160 Inertial Measurement Unit > device-tree bindings. > > Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> > --- > Changes v1 -> v2 (suggested by Rob): > * remove "gpio" keyword from interrupts property description > * describe "INT1" and "INT2" cases for interrupt-names property > > .../devicetree/bindings/iio/imu/bmi160.txt | 36 ++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > create mode 100644 Documentation/devicetree/bindings/iio/imu/bmi160.txt Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> > > diff --git a/Documentation/devicetree/bindings/iio/imu/bmi160.txt b/Documentation/devicetree/bindings/iio/imu/bmi160.txt > new file mode 100644 > index 0000000..ae0112c > --- /dev/null > +++ b/Documentation/devicetree/bindings/iio/imu/bmi160.txt > @@ -0,0 +1,36 @@ > +Bosch BMI160 - Inertial Measurement Unit with Accelerometer, Gyroscope > +and externally connectable Magnetometer > + > +https://www.bosch-sensortec.com/bst/products/all_products/bmi160 > + > +Required properties: > + - compatible : should be "bosch,bmi160" > + - reg : the I2C address or SPI chip select number of the sensor > + - spi-max-frequency : set maximum clock frequency (only for SPI) > + > +Optional properties: > + - interrupt-parent : should be the phandle of the interrupt controller > + - interrupts : interrupt mapping for IRQ, must be IRQ_TYPE_LEVEL_LOW > + - interrupt-names : set to "INT1" if INT1 pin should be used as interrupt > + input, set to "INT2" if INT2 pin should be used instead > + > +Examples: > + > +bmi160@68 { > + compatible = "bosch,bmi160"; > + reg = <0x68>; > + > + interrupt-parent = <&gpio4>; > + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; > + interrupt-names = "INT1"; > +}; > + > +bmi160@0 { > + compatible = "bosch,bmi160"; > + reg = <0>; > + spi-max-frequency = <10000000>; > + > + interrupt-parent = <&gpio2>; > + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; > + interrupt-names = "INT2"; > +}; > -- > 2.10.2 > ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 3/6] Documentation: DT: Add bmi160 imu binding 2016-12-12 17:15 ` Rob Herring @ 2016-12-30 10:40 ` Jonathan Cameron 0 siblings, 0 replies; 14+ messages in thread From: Jonathan Cameron @ 2016-12-30 10:40 UTC (permalink / raw) To: Rob Herring, Marcin Niestroj Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA On 12/12/16 17:15, Rob Herring wrote: > On Thu, Dec 08, 2016 at 03:22:56PM +0100, Marcin Niestroj wrote: >> This adds documentation for Bosch BMI160 Inertial Measurement Unit >> device-tree bindings. >> >> Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> >> --- >> Changes v1 -> v2 (suggested by Rob): >> * remove "gpio" keyword from interrupts property description >> * describe "INT1" and "INT2" cases for interrupt-names property >> >> .../devicetree/bindings/iio/imu/bmi160.txt | 36 ++++++++++++++++++++++ >> 1 file changed, 36 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/iio/imu/bmi160.txt > > Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> Applied to the togreg branch of iio.git - initially pushed out as testing for the autobuilders to completely ignore this patch. Thanks, Jonathan > >> >> diff --git a/Documentation/devicetree/bindings/iio/imu/bmi160.txt b/Documentation/devicetree/bindings/iio/imu/bmi160.txt >> new file mode 100644 >> index 0000000..ae0112c >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/iio/imu/bmi160.txt >> @@ -0,0 +1,36 @@ >> +Bosch BMI160 - Inertial Measurement Unit with Accelerometer, Gyroscope >> +and externally connectable Magnetometer >> + >> +https://www.bosch-sensortec.com/bst/products/all_products/bmi160 >> + >> +Required properties: >> + - compatible : should be "bosch,bmi160" >> + - reg : the I2C address or SPI chip select number of the sensor >> + - spi-max-frequency : set maximum clock frequency (only for SPI) >> + >> +Optional properties: >> + - interrupt-parent : should be the phandle of the interrupt controller >> + - interrupts : interrupt mapping for IRQ, must be IRQ_TYPE_LEVEL_LOW >> + - interrupt-names : set to "INT1" if INT1 pin should be used as interrupt >> + input, set to "INT2" if INT2 pin should be used instead >> + >> +Examples: >> + >> +bmi160@68 { >> + compatible = "bosch,bmi160"; >> + reg = <0x68>; >> + >> + interrupt-parent = <&gpio4>; >> + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; >> + interrupt-names = "INT1"; >> +}; >> + >> +bmi160@0 { >> + compatible = "bosch,bmi160"; >> + reg = <0>; >> + spi-max-frequency = <10000000>; >> + >> + interrupt-parent = <&gpio2>; >> + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; >> + interrupt-names = "INT2"; >> +}; >> -- >> 2.10.2 >> ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 4/6] iio: bmi160: Protect data transmission with mutex [not found] ` <20161208142259.26230-1-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> ` (2 preceding siblings ...) 2016-12-08 14:22 ` [PATCH v2 3/6] Documentation: DT: Add bmi160 imu binding Marcin Niestroj @ 2016-12-08 14:22 ` Marcin Niestroj [not found] ` <20161208142259.26230-5-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-08 14:22 ` [PATCH v2 5/6] iio: bmi160: Fix time needed to sleep after command execution Marcin Niestroj 2016-12-08 14:22 ` [PATCH v2 6/6] iio: bmi160: Support hardware fifo Marcin Niestroj 5 siblings, 1 reply; 14+ messages in thread From: Marcin Niestroj @ 2016-12-08 14:22 UTC (permalink / raw) To: Jonathan Cameron Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Marcin Niestroj There are currently two possible cases for data transmission with the sensor: read/write by iio sysfs and read in trigger interrupt handler. Hence we need to protect data transmission using regmap_* functions with mutex. Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> --- Patch introduced in v2 drivers/iio/imu/bmi160/bmi160_core.c | 39 +++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index e0251b8..095533c 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -2,6 +2,7 @@ * BMI160 - Bosch IMU (accel, gyro plus external magnetometer) * * Copyright (c) 2016, Intel Corporation. + * Copyright (c) 2016, Grinn * * This file is subject to the terms and conditions of version 2 of * the GNU General Public License. See the file COPYING in the main @@ -112,6 +113,7 @@ enum bmi160_sensor_type { struct bmi160_data { struct regmap *regmap; + struct mutex mutex; }; const struct regmap_config bmi160_regmap_config = { @@ -285,7 +287,9 @@ int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t, else cmd = bmi160_regs[t].pmu_cmd_suspend; + mutex_lock(&data->mutex); ret = regmap_write(data->regmap, BMI160_REG_CMD, cmd); + mutex_unlock(&data->mutex); if (ret < 0) return ret; @@ -298,6 +302,7 @@ static int bmi160_set_scale(struct bmi160_data *data, enum bmi160_sensor_type t, int uscale) { + int ret; int i; for (i = 0; i < bmi160_scale_table[t].num; i++) @@ -307,8 +312,12 @@ int bmi160_set_scale(struct bmi160_data *data, enum bmi160_sensor_type t, if (i == bmi160_scale_table[t].num) return -EINVAL; - return regmap_write(data->regmap, bmi160_regs[t].range, - bmi160_scale_table[t].tbl[i].bits); + mutex_lock(&data->mutex); + ret = regmap_write(data->regmap, bmi160_regs[t].range, + bmi160_scale_table[t].tbl[i].bits); + mutex_unlock(&data->mutex); + + return ret; } static @@ -317,7 +326,9 @@ int bmi160_get_scale(struct bmi160_data *data, enum bmi160_sensor_type t, { int i, ret, val; + mutex_lock(&data->mutex); ret = regmap_read(data->regmap, bmi160_regs[t].range, &val); + mutex_unlock(&data->mutex); if (ret < 0) return ret; @@ -340,7 +351,9 @@ static int bmi160_get_data(struct bmi160_data *data, int chan_type, reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(__le16); + mutex_lock(&data->mutex); ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(__le16)); + mutex_unlock(&data->mutex); if (ret < 0) return ret; @@ -353,6 +366,7 @@ static int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t, int odr, int uodr) { + int ret; int i; for (i = 0; i < bmi160_odr_table[t].num; i++) @@ -363,10 +377,14 @@ int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t, if (i >= bmi160_odr_table[t].num) return -EINVAL; - return regmap_update_bits(data->regmap, - bmi160_regs[t].config, - bmi160_regs[t].config_odr_mask, - bmi160_odr_table[t].tbl[i].bits); + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, + bmi160_regs[t].config, + bmi160_regs[t].config_odr_mask, + bmi160_odr_table[t].tbl[i].bits); + mutex_unlock(&data->mutex); + + return ret; } static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, @@ -374,7 +392,9 @@ static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, { int i, val, ret; + mutex_lock(&data->mutex); ret = regmap_read(data->regmap, bmi160_regs[t].config, &val); + mutex_unlock(&data->mutex); if (ret < 0) return ret; @@ -402,14 +422,18 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p) int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L; __le16 sample; + mutex_lock(&data->mutex); for_each_set_bit(i, indio_dev->active_scan_mask, indio_dev->masklength) { ret = regmap_bulk_read(data->regmap, base + i * sizeof(__le16), &sample, sizeof(__le16)); - if (ret < 0) + if (ret < 0) { + mutex_unlock(&data->mutex); goto done; + } buf[j++] = sample; } + mutex_unlock(&data->mutex); iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns(indio_dev)); @@ -575,6 +599,7 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, data = iio_priv(indio_dev); dev_set_drvdata(dev, indio_dev); data->regmap = regmap; + mutex_init(&data->mutex); ret = bmi160_chip_init(data, use_spi); if (ret < 0) -- 2.10.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <20161208142259.26230-5-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org>]
* Re: [PATCH v2 4/6] iio: bmi160: Protect data transmission with mutex [not found] ` <20161208142259.26230-5-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> @ 2016-12-30 10:47 ` Jonathan Cameron 0 siblings, 0 replies; 14+ messages in thread From: Jonathan Cameron @ 2016-12-30 10:47 UTC (permalink / raw) To: Marcin Niestroj Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA On 08/12/16 14:22, Marcin Niestroj wrote: > There are currently two possible cases for data transmission with the > sensor: read/write by iio sysfs and read in trigger interrupt > handler. Hence we need to protect data transmission using regmap_* > functions with mutex. Except that the regmap functions themselves have build in protection against any such clashes. Hence I don't 'think' this is necessary as we don't have any open coded read / update loops in here that I can see. Jonathan > > Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> > --- > Patch introduced in v2 > > drivers/iio/imu/bmi160/bmi160_core.c | 39 +++++++++++++++++++++++++++++------- > 1 file changed, 32 insertions(+), 7 deletions(-) > > diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c > index e0251b8..095533c 100644 > --- a/drivers/iio/imu/bmi160/bmi160_core.c > +++ b/drivers/iio/imu/bmi160/bmi160_core.c > @@ -2,6 +2,7 @@ > * BMI160 - Bosch IMU (accel, gyro plus external magnetometer) > * > * Copyright (c) 2016, Intel Corporation. > + * Copyright (c) 2016, Grinn > * > * This file is subject to the terms and conditions of version 2 of > * the GNU General Public License. See the file COPYING in the main > @@ -112,6 +113,7 @@ enum bmi160_sensor_type { > > struct bmi160_data { > struct regmap *regmap; > + struct mutex mutex; > }; > > const struct regmap_config bmi160_regmap_config = { > @@ -285,7 +287,9 @@ int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t, > else > cmd = bmi160_regs[t].pmu_cmd_suspend; > > + mutex_lock(&data->mutex); > ret = regmap_write(data->regmap, BMI160_REG_CMD, cmd); > + mutex_unlock(&data->mutex); > if (ret < 0) > return ret; > > @@ -298,6 +302,7 @@ static > int bmi160_set_scale(struct bmi160_data *data, enum bmi160_sensor_type t, > int uscale) > { > + int ret; > int i; > > for (i = 0; i < bmi160_scale_table[t].num; i++) > @@ -307,8 +312,12 @@ int bmi160_set_scale(struct bmi160_data *data, enum bmi160_sensor_type t, > if (i == bmi160_scale_table[t].num) > return -EINVAL; > > - return regmap_write(data->regmap, bmi160_regs[t].range, > - bmi160_scale_table[t].tbl[i].bits); > + mutex_lock(&data->mutex); > + ret = regmap_write(data->regmap, bmi160_regs[t].range, > + bmi160_scale_table[t].tbl[i].bits); > + mutex_unlock(&data->mutex); > + > + return ret; > } > > static > @@ -317,7 +326,9 @@ int bmi160_get_scale(struct bmi160_data *data, enum bmi160_sensor_type t, > { > int i, ret, val; > > + mutex_lock(&data->mutex); > ret = regmap_read(data->regmap, bmi160_regs[t].range, &val); > + mutex_unlock(&data->mutex); > if (ret < 0) > return ret; > > @@ -340,7 +351,9 @@ static int bmi160_get_data(struct bmi160_data *data, int chan_type, > > reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(__le16); > > + mutex_lock(&data->mutex); > ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(__le16)); > + mutex_unlock(&data->mutex); > if (ret < 0) > return ret; > > @@ -353,6 +366,7 @@ static > int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t, > int odr, int uodr) > { > + int ret; > int i; > > for (i = 0; i < bmi160_odr_table[t].num; i++) > @@ -363,10 +377,14 @@ int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t, > if (i >= bmi160_odr_table[t].num) > return -EINVAL; > > - return regmap_update_bits(data->regmap, > - bmi160_regs[t].config, > - bmi160_regs[t].config_odr_mask, > - bmi160_odr_table[t].tbl[i].bits); > + mutex_lock(&data->mutex); > + ret = regmap_update_bits(data->regmap, > + bmi160_regs[t].config, > + bmi160_regs[t].config_odr_mask, > + bmi160_odr_table[t].tbl[i].bits); > + mutex_unlock(&data->mutex); > + > + return ret; > } > > static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, > @@ -374,7 +392,9 @@ static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, > { > int i, val, ret; > > + mutex_lock(&data->mutex); > ret = regmap_read(data->regmap, bmi160_regs[t].config, &val); > + mutex_unlock(&data->mutex); > if (ret < 0) > return ret; > > @@ -402,14 +422,18 @@ static irqreturn_t bmi160_trigger_handler(int irq, void *p) > int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L; > __le16 sample; > > + mutex_lock(&data->mutex); > for_each_set_bit(i, indio_dev->active_scan_mask, > indio_dev->masklength) { > ret = regmap_bulk_read(data->regmap, base + i * sizeof(__le16), > &sample, sizeof(__le16)); > - if (ret < 0) > + if (ret < 0) { > + mutex_unlock(&data->mutex); > goto done; > + } > buf[j++] = sample; > } > + mutex_unlock(&data->mutex); > > iio_push_to_buffers_with_timestamp(indio_dev, buf, > iio_get_time_ns(indio_dev)); > @@ -575,6 +599,7 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, > data = iio_priv(indio_dev); > dev_set_drvdata(dev, indio_dev); > data->regmap = regmap; > + mutex_init(&data->mutex); > > ret = bmi160_chip_init(data, use_spi); > if (ret < 0) > -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 5/6] iio: bmi160: Fix time needed to sleep after command execution [not found] ` <20161208142259.26230-1-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> ` (3 preceding siblings ...) 2016-12-08 14:22 ` [PATCH v2 4/6] iio: bmi160: Protect data transmission with mutex Marcin Niestroj @ 2016-12-08 14:22 ` Marcin Niestroj [not found] ` <20161208142259.26230-6-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-08 14:22 ` [PATCH v2 6/6] iio: bmi160: Support hardware fifo Marcin Niestroj 5 siblings, 1 reply; 14+ messages in thread From: Marcin Niestroj @ 2016-12-08 14:22 UTC (permalink / raw) To: Jonathan Cameron Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Marcin Niestroj Datasheet specifies typical and maximum execution times for which CMD register is occupied after previous command execution. We took these values as minimum and maximum time for usleep_range() call before making a new command execution. To be sure, that the CMD register is no longer occupied we need to wait *at least* the maximum time specified by datasheet. Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> --- Patch introduced in v2 drivers/iio/imu/bmi160/bmi160_core.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 095533c..88bcf3f 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -67,10 +67,8 @@ #define BMI160_REG_DUMMY 0x7F -#define BMI160_ACCEL_PMU_MIN_USLEEP 3200 -#define BMI160_ACCEL_PMU_MAX_USLEEP 3800 -#define BMI160_GYRO_PMU_MIN_USLEEP 55000 -#define BMI160_GYRO_PMU_MAX_USLEEP 80000 +#define BMI160_ACCEL_PMU_MIN_USLEEP 3800 +#define BMI160_GYRO_PMU_MIN_USLEEP 80000 #define BMI160_SOFTRESET_USLEEP 1000 #define BMI160_CHANNEL(_type, _axis, _index) { \ @@ -153,20 +151,9 @@ static struct bmi160_regs bmi160_regs[] = { }, }; -struct bmi160_pmu_time { - unsigned long min; - unsigned long max; -}; - -static struct bmi160_pmu_time bmi160_pmu_time[] = { - [BMI160_ACCEL] = { - .min = BMI160_ACCEL_PMU_MIN_USLEEP, - .max = BMI160_ACCEL_PMU_MAX_USLEEP - }, - [BMI160_GYRO] = { - .min = BMI160_GYRO_PMU_MIN_USLEEP, - .max = BMI160_GYRO_PMU_MIN_USLEEP, - }, +static unsigned long bmi160_pmu_time[] = { + [BMI160_ACCEL] = BMI160_ACCEL_PMU_MIN_USLEEP, + [BMI160_GYRO] = BMI160_GYRO_PMU_MIN_USLEEP, }; struct bmi160_scale { @@ -293,7 +280,7 @@ int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t, if (ret < 0) return ret; - usleep_range(bmi160_pmu_time[t].min, bmi160_pmu_time[t].max); + usleep_range(bmi160_pmu_time[t], bmi160_pmu_time[t] + 1000); return 0; } -- 2.10.2 ^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <20161208142259.26230-6-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org>]
* Re: [PATCH v2 5/6] iio: bmi160: Fix time needed to sleep after command execution [not found] ` <20161208142259.26230-6-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> @ 2016-12-30 10:49 ` Jonathan Cameron [not found] ` <7668f191-dafd-e616-171a-cafc52791292-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> 0 siblings, 1 reply; 14+ messages in thread From: Jonathan Cameron @ 2016-12-30 10:49 UTC (permalink / raw) To: Marcin Niestroj Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA On 08/12/16 14:22, Marcin Niestroj wrote: > Datasheet specifies typical and maximum execution times for which CMD > register is occupied after previous command execution. We took these > values as minimum and maximum time for usleep_range() call before making > a new command execution. > > To be sure, that the CMD register is no longer occupied we need to wait > *at least* the maximum time specified by datasheet. > > Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> This looks like a definite bug that we would want to fix in stable as well. If possible, could you ensure this is the first patch in the updated series? Thanks, Jonathan > --- > Patch introduced in v2 > > drivers/iio/imu/bmi160/bmi160_core.c | 25 ++++++------------------- > 1 file changed, 6 insertions(+), 19 deletions(-) > > diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c > index 095533c..88bcf3f 100644 > --- a/drivers/iio/imu/bmi160/bmi160_core.c > +++ b/drivers/iio/imu/bmi160/bmi160_core.c > @@ -67,10 +67,8 @@ > > #define BMI160_REG_DUMMY 0x7F > > -#define BMI160_ACCEL_PMU_MIN_USLEEP 3200 > -#define BMI160_ACCEL_PMU_MAX_USLEEP 3800 > -#define BMI160_GYRO_PMU_MIN_USLEEP 55000 > -#define BMI160_GYRO_PMU_MAX_USLEEP 80000 > +#define BMI160_ACCEL_PMU_MIN_USLEEP 3800 > +#define BMI160_GYRO_PMU_MIN_USLEEP 80000 > #define BMI160_SOFTRESET_USLEEP 1000 > > #define BMI160_CHANNEL(_type, _axis, _index) { \ > @@ -153,20 +151,9 @@ static struct bmi160_regs bmi160_regs[] = { > }, > }; > > -struct bmi160_pmu_time { > - unsigned long min; > - unsigned long max; > -}; > - > -static struct bmi160_pmu_time bmi160_pmu_time[] = { > - [BMI160_ACCEL] = { > - .min = BMI160_ACCEL_PMU_MIN_USLEEP, > - .max = BMI160_ACCEL_PMU_MAX_USLEEP > - }, > - [BMI160_GYRO] = { > - .min = BMI160_GYRO_PMU_MIN_USLEEP, > - .max = BMI160_GYRO_PMU_MIN_USLEEP, > - }, > +static unsigned long bmi160_pmu_time[] = { > + [BMI160_ACCEL] = BMI160_ACCEL_PMU_MIN_USLEEP, > + [BMI160_GYRO] = BMI160_GYRO_PMU_MIN_USLEEP, > }; > > struct bmi160_scale { > @@ -293,7 +280,7 @@ int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t, > if (ret < 0) > return ret; > > - usleep_range(bmi160_pmu_time[t].min, bmi160_pmu_time[t].max); > + usleep_range(bmi160_pmu_time[t], bmi160_pmu_time[t] + 1000); > > return 0; > } > ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <7668f191-dafd-e616-171a-cafc52791292-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>]
* Re: [PATCH v2 5/6] iio: bmi160: Fix time needed to sleep after command execution [not found] ` <7668f191-dafd-e616-171a-cafc52791292-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> @ 2016-12-30 10:51 ` Jonathan Cameron 0 siblings, 0 replies; 14+ messages in thread From: Jonathan Cameron @ 2016-12-30 10:51 UTC (permalink / raw) To: Marcin Niestroj Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA On 30/12/16 10:49, Jonathan Cameron wrote: > On 08/12/16 14:22, Marcin Niestroj wrote: >> Datasheet specifies typical and maximum execution times for which CMD >> register is occupied after previous command execution. We took these >> values as minimum and maximum time for usleep_range() call before making >> a new command execution. >> >> To be sure, that the CMD register is no longer occupied we need to wait >> *at least* the maximum time specified by datasheet. >> >> Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> > This looks like a definite bug that we would want to fix in stable as well. > If possible, could you ensure this is the first patch in the updated series? Actually don't worry. It applies cleanly to my fixes-togreg-post-rc1 branch anyway so I'll take it that way and send upstream asap. Applied to the fixes-togreg-post-rc1 branch and marked for stable. Thanks, Jonathan > > Thanks, > > Jonathan >> --- >> Patch introduced in v2 >> >> drivers/iio/imu/bmi160/bmi160_core.c | 25 ++++++------------------- >> 1 file changed, 6 insertions(+), 19 deletions(-) >> >> diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c >> index 095533c..88bcf3f 100644 >> --- a/drivers/iio/imu/bmi160/bmi160_core.c >> +++ b/drivers/iio/imu/bmi160/bmi160_core.c >> @@ -67,10 +67,8 @@ >> >> #define BMI160_REG_DUMMY 0x7F >> >> -#define BMI160_ACCEL_PMU_MIN_USLEEP 3200 >> -#define BMI160_ACCEL_PMU_MAX_USLEEP 3800 >> -#define BMI160_GYRO_PMU_MIN_USLEEP 55000 >> -#define BMI160_GYRO_PMU_MAX_USLEEP 80000 >> +#define BMI160_ACCEL_PMU_MIN_USLEEP 3800 >> +#define BMI160_GYRO_PMU_MIN_USLEEP 80000 >> #define BMI160_SOFTRESET_USLEEP 1000 >> >> #define BMI160_CHANNEL(_type, _axis, _index) { \ >> @@ -153,20 +151,9 @@ static struct bmi160_regs bmi160_regs[] = { >> }, >> }; >> >> -struct bmi160_pmu_time { >> - unsigned long min; >> - unsigned long max; >> -}; >> - >> -static struct bmi160_pmu_time bmi160_pmu_time[] = { >> - [BMI160_ACCEL] = { >> - .min = BMI160_ACCEL_PMU_MIN_USLEEP, >> - .max = BMI160_ACCEL_PMU_MAX_USLEEP >> - }, >> - [BMI160_GYRO] = { >> - .min = BMI160_GYRO_PMU_MIN_USLEEP, >> - .max = BMI160_GYRO_PMU_MIN_USLEEP, >> - }, >> +static unsigned long bmi160_pmu_time[] = { >> + [BMI160_ACCEL] = BMI160_ACCEL_PMU_MIN_USLEEP, >> + [BMI160_GYRO] = BMI160_GYRO_PMU_MIN_USLEEP, >> }; >> >> struct bmi160_scale { >> @@ -293,7 +280,7 @@ int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t, >> if (ret < 0) >> return ret; >> >> - usleep_range(bmi160_pmu_time[t].min, bmi160_pmu_time[t].max); >> + usleep_range(bmi160_pmu_time[t], bmi160_pmu_time[t] + 1000); >> >> return 0; >> } >> > > -- > To unsubscribe from this list: send the line "unsubscribe linux-iio" in > the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 6/6] iio: bmi160: Support hardware fifo [not found] ` <20161208142259.26230-1-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> ` (4 preceding siblings ...) 2016-12-08 14:22 ` [PATCH v2 5/6] iio: bmi160: Fix time needed to sleep after command execution Marcin Niestroj @ 2016-12-08 14:22 ` Marcin Niestroj [not found] ` <20161208142259.26230-7-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 5 siblings, 1 reply; 14+ messages in thread From: Marcin Niestroj @ 2016-12-08 14:22 UTC (permalink / raw) To: Jonathan Cameron Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Marcin Niestroj This patch was developed primarily based on bmc150_accel hardware fifo implementation. IRQ handler was added, which for now is responsible only for handling watermark interrupts. The BMI160 chip has two interrupt outputs. By default INT is considered to be connected. If INT2 is used instead, the interrupt-names device-tree property can be used to specify that. Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> --- Depends on patch 4 in series Changes v1 -> v2: * add __ prefix to all functions that should be called with mutex held (suggested by Peter) * get rid of non-constant array size (suggested by Peter) * disable irq on init failure and module removal (suggested by Peter) * make bmi160_buffer_predisable() the reverse order of the bmi160_buffer_postenable() (suggested by Jonathan) * remove realignment for iio_info structs (suggested by Jonathan) drivers/iio/imu/bmi160/bmi160.h | 3 +- drivers/iio/imu/bmi160/bmi160_core.c | 618 ++++++++++++++++++++++++++++++++++- drivers/iio/imu/bmi160/bmi160_i2c.c | 7 +- drivers/iio/imu/bmi160/bmi160_spi.c | 3 +- 4 files changed, 613 insertions(+), 18 deletions(-) diff --git a/drivers/iio/imu/bmi160/bmi160.h b/drivers/iio/imu/bmi160/bmi160.h index d2ae6ed..4a7c10e 100644 --- a/drivers/iio/imu/bmi160/bmi160.h +++ b/drivers/iio/imu/bmi160/bmi160.h @@ -4,7 +4,8 @@ extern const struct regmap_config bmi160_regmap_config; int bmi160_core_probe(struct device *dev, struct regmap *regmap, - const char *name, bool use_spi); + const char *name, int irq, + bool use_spi, bool block_supported); void bmi160_core_remove(struct device *dev); #endif /* BMI160_H_ */ diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 88bcf3f..26404b4 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -10,7 +10,7 @@ * * IIO core driver for BMI160, with support for I2C/SPI busses * - * TODO: magnetometer, interrupts, hardware FIFO + * TODO: magnetometer, interrupts */ #include <linux/module.h> #include <linux/regmap.h> @@ -23,8 +23,12 @@ #include <linux/iio/buffer.h> #include <linux/iio/sysfs.h> +#include <linux/of_irq.h> + #include "bmi160.h" +#define BMI160_IRQ_NAME "bmi160_event" + #define BMI160_REG_CHIP_ID 0x00 #define BMI160_CHIP_ID_VAL 0xD1 @@ -35,6 +39,21 @@ #define BMI160_REG_DATA_GYRO_XOUT_L 0x0C #define BMI160_REG_DATA_ACCEL_XOUT_L 0x12 +#define BMI160_REG_STATUS 0x1B +#define BMI160_STATUS_MAG_MAN_OP BIT(2) + +#define BMI160_REG_INT_STATUS0 0x1C + +#define BMI160_REG_INT_STATUS1 0x1D +#define BMI160_INT_STATUS_FWM BIT(6) + +#define BMI160_REG_INT_STATUS2 0x1E + +#define BMI160_REG_INT_STATUS3 0x1F + +#define BMI160_REG_FIFO_LENGTH 0x22 +#define BMI160_REG_FIFO_DATA 0x24 + #define BMI160_REG_ACCEL_CONFIG 0x40 #define BMI160_ACCEL_CONFIG_ODR_MASK GENMASK(3, 0) #define BMI160_ACCEL_CONFIG_BWP_MASK GENMASK(6, 4) @@ -56,6 +75,36 @@ #define BMI160_GYRO_RANGE_250DPS 0x03 #define BMI160_GYRO_RANGE_125DPS 0x04 +#define BMI160_REG_FIFO_CONFIG_0 0x46 + +#define BMI160_REG_FIFO_CONFIG_1 0x47 +#define BMI160_FIFO_GYRO_EN BIT(7) +#define BMI160_FIFO_ACCEL_EN BIT(6) +#define BMI160_FIFO_MAGN_EN BIT(5) +#define BMI160_FIFO_HEADER_EN BIT(4) +#define BMI160_FIFO_TAG_INT1_EN BIT(3) +#define BMI160_FIFO_TAG_INT2_EN BIT(2) +#define BMI160_FIFO_TIME_EN BIT(1) + +#define BMI160_REG_INT_EN_1 0x51 +#define BMI160_INT_FWM_EN BIT(6) +#define BMI160_INT_FFULL_EN BIT(5) +#define BMI160_INT_DRDY_EN BIT(4) + +#define BMI160_REG_INT_OUT_CTRL 0x53 +#define BMI160_INT2_OUTPUT_EN BIT(7) +#define BMI160_INT1_OUTPUT_EN BIT(3) + +#define BMI160_REG_INT_LATCH 0x54 + +#define BMI160_REG_INT_MAP_1 0x56 +#define BMI160_INT1_MAP_DRDY BIT(7) +#define BMI160_INT1_MAP_FWM BIT(6) +#define BMI160_INT1_MAP_FFULL BIT(5) +#define BMI160_INT2_MAP_DRDY BIT(3) +#define BMI160_INT2_MAP_FWM BIT(2) +#define BMI160_INT2_MAP_FFULL BIT(1) + #define BMI160_REG_CMD 0x7E #define BMI160_CMD_ACCEL_PM_SUSPEND 0x10 #define BMI160_CMD_ACCEL_PM_NORMAL 0x11 @@ -67,6 +116,8 @@ #define BMI160_REG_DUMMY 0x7F +#define BMI160_FIFO_LENGTH 1024 + #define BMI160_ACCEL_PMU_MIN_USLEEP 3800 #define BMI160_GYRO_PMU_MIN_USLEEP 80000 #define BMI160_SOFTRESET_USLEEP 1000 @@ -109,9 +160,34 @@ enum bmi160_sensor_type { BMI160_NUM_SENSORS /* must be last */ }; +struct bmi160_irq_data { + unsigned int map_fwm; + unsigned int output_en; +}; + +static const struct bmi160_irq_data bmi160_irq1_data = { + .map_fwm = BMI160_INT1_MAP_FWM, + .output_en = BMI160_INT1_OUTPUT_EN, +}; + +static const struct bmi160_irq_data bmi160_irq2_data = { + .map_fwm = BMI160_INT2_MAP_FWM, + .output_en = BMI160_INT2_OUTPUT_EN, +}; + struct bmi160_data { struct regmap *regmap; struct mutex mutex; + const struct bmi160_irq_data *irq_data; + int irq; + bool irq_enabled; + int64_t timestamp; + int64_t fifo_sample_period; + bool fifo_enabled; + unsigned int fifo_config; + unsigned int fifo_sample_size; + u8 *fifo_buffer; + unsigned int watermark; }; const struct regmap_config bmi160_regmap_config = { @@ -374,16 +450,20 @@ int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t, return ret; } -static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, - int *odr, int *uodr) +static int64_t bmi160_frequency_to_period(int odr, int uodr) { - int i, val, ret; + uint64_t period = 1000000000000000; + int64_t frequency = (int64_t) odr * 1000000 + uodr; - mutex_lock(&data->mutex); - ret = regmap_read(data->regmap, bmi160_regs[t].config, &val); - mutex_unlock(&data->mutex); - if (ret < 0) - return ret; + do_div(period, frequency); + + return period; +} + +static const struct bmi160_odr *bmi160_reg_to_odr(enum bmi160_sensor_type t, + unsigned int val) +{ + int i; val &= bmi160_regs[t].config_odr_mask; @@ -392,10 +472,52 @@ static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, break; if (i >= bmi160_odr_table[t].num) - return -EINVAL; + return ERR_PTR(-EINVAL); - *odr = bmi160_odr_table[t].tbl[i].odr; - *uodr = bmi160_odr_table[t].tbl[i].uodr; + return &bmi160_odr_table[t].tbl[i]; +} + +static int __bmi160_get_sample_period(struct bmi160_data *data, + enum bmi160_sensor_type t, + int64_t *sample_period) +{ + const struct bmi160_odr *odr_entry; + int ret; + unsigned int val; + + ret = regmap_read(data->regmap, bmi160_regs[t].config, &val); + if (ret < 0) + return ret; + + odr_entry = bmi160_reg_to_odr(t, val); + if (IS_ERR(odr_entry)) + return PTR_ERR(odr_entry); + + *sample_period = bmi160_frequency_to_period(odr_entry->odr, + odr_entry->uodr); + + return 0; +} + +static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, + int *odr, int *uodr) +{ + const struct bmi160_odr *odr_entry; + int ret; + unsigned int val; + + mutex_lock(&data->mutex); + ret = regmap_read(data->regmap, bmi160_regs[t].config, &val); + mutex_unlock(&data->mutex); + if (ret < 0) + return ret; + + odr_entry = bmi160_reg_to_odr(t, val); + if (IS_ERR(odr_entry)) + return PTR_ERR(odr_entry); + + *odr = odr_entry->odr; + *uodr = odr_entry->uodr; return 0; } @@ -504,6 +626,356 @@ static const struct attribute_group bmi160_attrs_group = { .attrs = bmi160_attrs, }; +static int __bmi160_read_sample_period(struct bmi160_data *data, + enum bmi160_sensor_type sensor_type) +{ + struct device *dev = regmap_get_device(data->regmap); + int64_t uninitialized_var(sample_period); + int ret; + + ret = __bmi160_get_sample_period(data, sensor_type, &sample_period); + if (ret < 0) + return ret; + + if (data->fifo_sample_period) { + if (data->fifo_sample_period != sample_period) { + dev_warn(dev, "Enabled sensors have unequal ODR values\n"); + return -EINVAL; + } + } else { + data->fifo_sample_period = sample_period; + } + + return 0; +} + +static int __bmi160_fifo_enable(struct iio_dev *indio_dev, + struct bmi160_data *data) +{ + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(regmap); + int ret; + int i; + unsigned int val; + unsigned int fifo_config = 0; + + /* Set fifo sample size and period */ + for_each_set_bit(i, indio_dev->active_scan_mask, + indio_dev->masklength) { + if (i <= BMI160_SCAN_GYRO_Z) + fifo_config |= BMI160_FIFO_GYRO_EN; + else if (i <= BMI160_SCAN_ACCEL_Z) + fifo_config |= BMI160_FIFO_ACCEL_EN; + } + + data->fifo_sample_period = 0; + data->fifo_sample_size = 0; + if (fifo_config & BMI160_FIFO_GYRO_EN) { + data->fifo_sample_size += 6; + ret = __bmi160_read_sample_period(data, BMI160_GYRO); + if (ret < 0) + return ret; + } + if (fifo_config & BMI160_FIFO_ACCEL_EN) { + data->fifo_sample_size += 6; + ret = __bmi160_read_sample_period(data, BMI160_ACCEL); + if (ret < 0) + return ret; + } + + /* + * Set watermark level and write real value back, as it will be used + * in timestamp calculation. + */ + val = data->watermark * data->fifo_sample_size; + if (val > BMI160_FIFO_LENGTH - 1) { + val = BMI160_FIFO_LENGTH - 1; + data->watermark = val / data->fifo_sample_size; + } + val = data->watermark * data->fifo_sample_size / 4; + + ret = regmap_write(regmap, BMI160_REG_FIFO_CONFIG_0, val); + if (ret < 0) { + dev_err(dev, "Failed to set watermark\n"); + return ret; + } + + /* Enable FIFO channels */ + ret = regmap_write(regmap, BMI160_REG_FIFO_CONFIG_1, + fifo_config); + if (ret < 0) { + dev_err(dev, "Failed to write FIFO_CONFIG_1\n"); + return ret; + } + + data->fifo_config = fifo_config; + data->fifo_enabled = true; + + return 0; +} + +static int __bmi160_fifo_disable(struct bmi160_data *data) +{ + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(regmap); + int ret; + + /* Disable all FIFO channels */ + ret = regmap_write(regmap, BMI160_REG_FIFO_CONFIG_1, 0); + if (ret < 0) { + dev_err(dev, "Failed to write FIFO_CONFIG_1\n"); + return ret; + } + + data->fifo_enabled = false; + + return 0; +} + +static int bmi160_buffer_postenable(struct iio_dev *indio_dev) +{ + struct bmi160_data *data = iio_priv(indio_dev); + int ret; + + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) + return iio_triggered_buffer_postenable(indio_dev); + + mutex_lock(&data->mutex); + ret = __bmi160_fifo_enable(indio_dev, data); + if (ret < 0) + goto unlock; + + ret = regmap_update_bits(data->regmap, BMI160_REG_INT_MAP_1, + data->irq_data->map_fwm, data->irq_data->map_fwm); + if (ret < 0) + goto unlock; + + ret = regmap_update_bits(data->regmap, BMI160_REG_INT_EN_1, + BMI160_INT_FWM_EN, BMI160_INT_FWM_EN); + +unlock: + mutex_unlock(&data->mutex); + + return ret; +} + +static int bmi160_buffer_predisable(struct iio_dev *indio_dev) +{ + struct bmi160_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + int ret = 0; + + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) + return iio_triggered_buffer_predisable(indio_dev); + + mutex_lock(&data->mutex); + ret = regmap_update_bits(regmap, BMI160_REG_INT_EN_1, + BMI160_INT_FWM_EN, 0); + if (ret < 0) + goto unlock; + + ret = regmap_update_bits(data->regmap, BMI160_REG_INT_MAP_1, + data->irq_data->map_fwm, 0); + if (ret < 0) + goto unlock; + + ret = __bmi160_fifo_disable(data); + +unlock: + mutex_unlock(&data->mutex); + + return ret; +} + +static const struct iio_buffer_setup_ops bmi160_buffer_ops = { + .postenable = bmi160_buffer_postenable, + .predisable = bmi160_buffer_predisable, +}; + +static ssize_t bmi160_get_fifo_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct bmi160_data *data = iio_priv(indio_dev); + bool state; + + mutex_lock(&data->mutex); + state = data->fifo_enabled; + mutex_unlock(&data->mutex); + + return sprintf(buf, "%d\n", (int) state); +} + +static ssize_t bmi160_get_fifo_watermark(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct bmi160_data *data = iio_priv(indio_dev); + int wm; + + mutex_lock(&data->mutex); + wm = data->watermark; + mutex_unlock(&data->mutex); + + return sprintf(buf, "%d\n", wm); +} + +static IIO_CONST_ATTR(hwfifo_watermark_min, "1"); +static IIO_CONST_ATTR(hwfifo_watermark_max, + __stringify(BMI160_FIFO_LENGTH)); +static IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO, + bmi160_get_fifo_state, NULL, 0); +static IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO, + bmi160_get_fifo_watermark, NULL, 0); + +static const struct attribute *bmi160_fifo_attributes[] = { + &iio_const_attr_hwfifo_watermark_min.dev_attr.attr, + &iio_const_attr_hwfifo_watermark_max.dev_attr.attr, + &iio_dev_attr_hwfifo_watermark.dev_attr.attr, + &iio_dev_attr_hwfifo_enabled.dev_attr.attr, + NULL, +}; + +static int bmi160_set_watermark(struct iio_dev *indio_dev, unsigned int val) +{ + struct bmi160_data *data = iio_priv(indio_dev); + + if (val > BMI160_FIFO_LENGTH) + val = BMI160_FIFO_LENGTH; + + mutex_lock(&data->mutex); + data->watermark = val; + mutex_unlock(&data->mutex); + + return 0; +} + +static int __bmi160_fifo_transfer(struct bmi160_data *data, + char *buffer, int num_bytes) +{ + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(regmap); + size_t step = regmap_get_raw_read_max(regmap); + int ret = 0; + int i; + + if (!step || step > num_bytes) + step = num_bytes; + else if (step < num_bytes) + step = data->fifo_sample_size; + + for (i = 0; i < num_bytes; i += step) { + ret = regmap_raw_read(regmap, BMI160_REG_FIFO_DATA, + &buffer[i], step); + + if (ret) + break; + } + + if (ret) + dev_err(dev, + "Error transferring data from fifo in single steps of %zu\n", + step); + + return ret; +} + +static int __bmi160_fifo_flush(struct iio_dev *indio_dev, + unsigned int samples, bool irq) +{ + struct bmi160_data *data = iio_priv(indio_dev); + struct regmap *regmap = data->regmap; + struct device *dev = regmap_get_device(regmap); + int ret; + __le16 fifo_length; + unsigned int fifo_samples; + unsigned int fifo_bytes; + u8 *buffer = data->fifo_buffer; + u8 *buffer_iter; + int64_t last_timestamp, timestamp; + unsigned int last_samples; + unsigned int i; + + /* Get the current FIFO length */ + ret = regmap_bulk_read(regmap, BMI160_REG_FIFO_LENGTH, + &fifo_length, sizeof(__le16)); + if (ret < 0) { + dev_err(dev, "Error reading FIFO_LENGTH\n"); + return ret; + } + + fifo_bytes = le16_to_cpu(fifo_length); + fifo_samples = fifo_bytes / data->fifo_sample_size; + + if (fifo_bytes % data->fifo_sample_size) + dev_warn(dev, "fifo_bytes %u is not dividable by %u\n", + fifo_bytes, data->fifo_sample_size); + + if (!fifo_samples) + return 0; + + if (samples && fifo_samples > samples) { + fifo_samples = samples; + fifo_bytes = fifo_samples * data->fifo_sample_size; + } + + /* + * If we are not called from IRQ, it means that we are flushing data + * on demand. In that case we do not have latest timestamp saved in + * data->timestamp. Get the time now instead. + * + * In case of IRQ flush, saved timestamp shows the time when number + * of samples configured by watermark were ready. Currently there might + * be more samples already. + * If we are not called from IRQ, than we are getting the current fifo + * length, as we are setting timestamp just after getting it. + */ + if (!irq) { + last_timestamp = iio_get_time_ns(indio_dev); + last_samples = fifo_samples; + } else { + last_timestamp = data->timestamp; + last_samples = data->watermark; + } + + /* Get all measurements */ + ret = __bmi160_fifo_transfer(data, buffer, fifo_bytes); + if (ret) + return ret; + + /* Handle demux */ + timestamp = last_timestamp - (last_samples * data->fifo_sample_period); + buffer_iter = buffer; + for (i = 0; i < fifo_samples; i++) { + u8 tmp_buf[32]; + + memcpy(tmp_buf, buffer_iter, data->fifo_sample_size); + + timestamp += data->fifo_sample_period; + iio_push_to_buffers_with_timestamp(indio_dev, + tmp_buf, + timestamp); + + buffer_iter += data->fifo_sample_size; + } + + return fifo_samples; +} + +static int bmi160_fifo_flush(struct iio_dev *indio_dev, unsigned int samples) +{ + struct bmi160_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->mutex); + ret = __bmi160_fifo_flush(indio_dev, samples, false); + mutex_unlock(&data->mutex); + + return ret; +} + static const struct iio_info bmi160_info = { .driver_module = THIS_MODULE, .read_raw = bmi160_read_raw, @@ -511,6 +983,15 @@ static const struct iio_info bmi160_info = { .attrs = &bmi160_attrs_group, }; +static const struct iio_info bmi160_info_fifo = { + .driver_module = THIS_MODULE, + .read_raw = bmi160_read_raw, + .write_raw = bmi160_write_raw, + .attrs = &bmi160_attrs_group, + .hwfifo_set_watermark = bmi160_set_watermark, + .hwfifo_flush_to_buffer = bmi160_fifo_flush, +}; + static const char *bmi160_match_acpi_device(struct device *dev) { const struct acpi_device_id *id; @@ -572,12 +1053,75 @@ static void bmi160_chip_uninit(struct bmi160_data *data) bmi160_set_mode(data, BMI160_ACCEL, false); } +static int bmi160_enable_irq(struct bmi160_data *data) +{ + int ret; + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, BMI160_REG_INT_OUT_CTRL, + data->irq_data->output_en, + data->irq_data->output_en); + mutex_unlock(&data->mutex); + + if (ret == 0) + data->irq_enabled = true; + + return ret; +} + +static int bmi160_disable_irq(struct bmi160_data *data) +{ + int ret; + + if (!data->irq_enabled) + return 0; + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, BMI160_REG_INT_OUT_CTRL, + data->irq_data->output_en, 0); + mutex_unlock(&data->mutex); + + if (ret == 0) + data->irq_enabled = false; + + return ret; +} + +static irqreturn_t bmi160_irq_thread_handler(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct bmi160_data *data = iio_priv(indio_dev); + struct device *dev = regmap_get_device(data->regmap); + + mutex_lock(&data->mutex); + if (data->fifo_enabled) + __bmi160_fifo_flush(indio_dev, BMI160_FIFO_LENGTH, true); + else + dev_warn(dev, + "IRQ has been triggered, but FIFO is not enabled.\n"); + mutex_unlock(&data->mutex); + + return IRQ_HANDLED; +} + +static irqreturn_t bmi160_irq_handler(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct bmi160_data *data = iio_priv(indio_dev); + + data->timestamp = iio_get_time_ns(indio_dev); + + return IRQ_WAKE_THREAD; +} + int bmi160_core_probe(struct device *dev, struct regmap *regmap, - const char *name, bool use_spi) + const char *name, int irq, + bool use_spi, bool block_supported) { struct iio_dev *indio_dev; struct bmi160_data *data; int ret; + int irq2; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) @@ -585,6 +1129,7 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, data = iio_priv(indio_dev); dev_set_drvdata(dev, indio_dev); + data->irq = irq; data->regmap = regmap; mutex_init(&data->mutex); @@ -603,15 +1148,57 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, indio_dev->info = &bmi160_info; ret = iio_triggered_buffer_setup(indio_dev, NULL, - bmi160_trigger_handler, NULL); + bmi160_trigger_handler, + &bmi160_buffer_ops); if (ret < 0) goto uninit; + if (data->irq > 0) { + /* Check which interrupt pin is connected to our board */ + irq2 = of_irq_get_byname(dev->of_node, "INT2"); + if (irq2 == data->irq) { + dev_dbg(dev, "Using interrupt line INT2\n"); + data->irq_data = &bmi160_irq2_data; + } else { + dev_dbg(dev, "Using interrupt line INT1\n"); + data->irq_data = &bmi160_irq1_data; + } + + ret = devm_request_threaded_irq(dev, + data->irq, + bmi160_irq_handler, + bmi160_irq_thread_handler, + IRQF_ONESHOT, + BMI160_IRQ_NAME, + indio_dev); + if (ret) + goto buffer_cleanup; + + ret = bmi160_enable_irq(data); + if (ret < 0) + goto buffer_cleanup; + + if (block_supported) { + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; + indio_dev->info = &bmi160_info_fifo; + indio_dev->buffer->attrs = bmi160_fifo_attributes; + data->fifo_buffer = devm_kmalloc(dev, + BMI160_FIFO_LENGTH, + GFP_KERNEL); + if (!data->fifo_buffer) { + ret = -ENOMEM; + goto disable_irq; + } + } + } + ret = iio_device_register(indio_dev); if (ret < 0) - goto buffer_cleanup; + goto disable_irq; return 0; +disable_irq: + bmi160_disable_irq(data); buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); uninit: @@ -626,6 +1213,7 @@ void bmi160_core_remove(struct device *dev) struct bmi160_data *data = iio_priv(indio_dev); iio_device_unregister(indio_dev); + bmi160_disable_irq(data); iio_triggered_buffer_cleanup(indio_dev); bmi160_chip_uninit(data); } diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 155a31f..1a3f4e1 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -24,6 +24,10 @@ static int bmi160_i2c_probe(struct i2c_client *client, { struct regmap *regmap; const char *name = NULL; + bool block_supported = + i2c_check_functionality(client->adapter, I2C_FUNC_I2C) || + i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK); regmap = devm_regmap_init_i2c(client, &bmi160_regmap_config); if (IS_ERR(regmap)) { @@ -35,7 +39,8 @@ static int bmi160_i2c_probe(struct i2c_client *client, if (id) name = id->name; - return bmi160_core_probe(&client->dev, regmap, name, false); + return bmi160_core_probe(&client->dev, regmap, name, client->irq, + false, block_supported); } static int bmi160_i2c_remove(struct i2c_client *client) diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index d34dfdf..5a53225 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -26,7 +26,8 @@ static int bmi160_spi_probe(struct spi_device *spi) (int)PTR_ERR(regmap)); return PTR_ERR(regmap); } - return bmi160_core_probe(&spi->dev, regmap, id->name, true); + return bmi160_core_probe(&spi->dev, regmap, id->name, spi->irq, + true, true); } static int bmi160_spi_remove(struct spi_device *spi) -- 2.10.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 14+ messages in thread
[parent not found: <20161208142259.26230-7-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org>]
* Re: [PATCH v2 6/6] iio: bmi160: Support hardware fifo [not found] ` <20161208142259.26230-7-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> @ 2016-12-30 11:29 ` Jonathan Cameron 0 siblings, 0 replies; 14+ messages in thread From: Jonathan Cameron @ 2016-12-30 11:29 UTC (permalink / raw) To: Marcin Niestroj Cc: Peter Meerwald-Stadler, Hartmut Knaack, Lars-Peter Clausen, Daniel Baluta, Gregor Boirie, Sanchayan Maity, Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA On 08/12/16 14:22, Marcin Niestroj wrote: > This patch was developed primarily based on bmc150_accel hardware fifo > implementation. > > IRQ handler was added, which for now is responsible only for handling > watermark interrupts. The BMI160 chip has two interrupt outputs. By > default INT is considered to be connected. If INT2 is used instead, the > interrupt-names device-tree property can be used to specify that. > > Signed-off-by: Marcin Niestroj <m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> A few bits and bobs inline but basically looking good to me. Sorry for the delay in getting around to review this! I'd like some input from Daniel ideally as well, but he is rather busy at the moment so I may take the final version of this without hearing from him. thanks, Jonathan > --- > Depends on patch 4 in series > > Changes v1 -> v2: > * add __ prefix to all functions that should be called with mutex held > (suggested by Peter) > * get rid of non-constant array size (suggested by Peter) > * disable irq on init failure and module removal (suggested by Peter) > * make bmi160_buffer_predisable() the reverse order of the > bmi160_buffer_postenable() (suggested by Jonathan) > * remove realignment for iio_info structs (suggested by Jonathan) > > drivers/iio/imu/bmi160/bmi160.h | 3 +- > drivers/iio/imu/bmi160/bmi160_core.c | 618 ++++++++++++++++++++++++++++++++++- > drivers/iio/imu/bmi160/bmi160_i2c.c | 7 +- > drivers/iio/imu/bmi160/bmi160_spi.c | 3 +- > 4 files changed, 613 insertions(+), 18 deletions(-) > > diff --git a/drivers/iio/imu/bmi160/bmi160.h b/drivers/iio/imu/bmi160/bmi160.h > index d2ae6ed..4a7c10e 100644 > --- a/drivers/iio/imu/bmi160/bmi160.h > +++ b/drivers/iio/imu/bmi160/bmi160.h > @@ -4,7 +4,8 @@ > extern const struct regmap_config bmi160_regmap_config; > > int bmi160_core_probe(struct device *dev, struct regmap *regmap, > - const char *name, bool use_spi); > + const char *name, int irq, > + bool use_spi, bool block_supported); > void bmi160_core_remove(struct device *dev); > > #endif /* BMI160_H_ */ > diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c > index 88bcf3f..26404b4 100644 > --- a/drivers/iio/imu/bmi160/bmi160_core.c > +++ b/drivers/iio/imu/bmi160/bmi160_core.c > @@ -10,7 +10,7 @@ > * > * IIO core driver for BMI160, with support for I2C/SPI busses > * > - * TODO: magnetometer, interrupts, hardware FIFO > + * TODO: magnetometer, interrupts > */ > #include <linux/module.h> > #include <linux/regmap.h> > @@ -23,8 +23,12 @@ > #include <linux/iio/buffer.h> > #include <linux/iio/sysfs.h> > > +#include <linux/of_irq.h> > + > #include "bmi160.h" > > +#define BMI160_IRQ_NAME "bmi160_event" Does the device actually support different uses for the two irqs at the same time? If not I'd be tempted ot just call this bmi160 > + > #define BMI160_REG_CHIP_ID 0x00 > #define BMI160_CHIP_ID_VAL 0xD1 > > @@ -35,6 +39,21 @@ > #define BMI160_REG_DATA_GYRO_XOUT_L 0x0C > #define BMI160_REG_DATA_ACCEL_XOUT_L 0x12 > > +#define BMI160_REG_STATUS 0x1B > +#define BMI160_STATUS_MAG_MAN_OP BIT(2) > + > +#define BMI160_REG_INT_STATUS0 0x1C > + > +#define BMI160_REG_INT_STATUS1 0x1D > +#define BMI160_INT_STATUS_FWM BIT(6) > + > +#define BMI160_REG_INT_STATUS2 0x1E > + > +#define BMI160_REG_INT_STATUS3 0x1F > + > +#define BMI160_REG_FIFO_LENGTH 0x22 > +#define BMI160_REG_FIFO_DATA 0x24 > + > #define BMI160_REG_ACCEL_CONFIG 0x40 > #define BMI160_ACCEL_CONFIG_ODR_MASK GENMASK(3, 0) > #define BMI160_ACCEL_CONFIG_BWP_MASK GENMASK(6, 4) > @@ -56,6 +75,36 @@ > #define BMI160_GYRO_RANGE_250DPS 0x03 > #define BMI160_GYRO_RANGE_125DPS 0x04 > > +#define BMI160_REG_FIFO_CONFIG_0 0x46 > + > +#define BMI160_REG_FIFO_CONFIG_1 0x47 > +#define BMI160_FIFO_GYRO_EN BIT(7) > +#define BMI160_FIFO_ACCEL_EN BIT(6) > +#define BMI160_FIFO_MAGN_EN BIT(5) > +#define BMI160_FIFO_HEADER_EN BIT(4) > +#define BMI160_FIFO_TAG_INT1_EN BIT(3) > +#define BMI160_FIFO_TAG_INT2_EN BIT(2) > +#define BMI160_FIFO_TIME_EN BIT(1) > + > +#define BMI160_REG_INT_EN_1 0x51 > +#define BMI160_INT_FWM_EN BIT(6) > +#define BMI160_INT_FFULL_EN BIT(5) > +#define BMI160_INT_DRDY_EN BIT(4) > + > +#define BMI160_REG_INT_OUT_CTRL 0x53 > +#define BMI160_INT2_OUTPUT_EN BIT(7) > +#define BMI160_INT1_OUTPUT_EN BIT(3) > + > +#define BMI160_REG_INT_LATCH 0x54 > + > +#define BMI160_REG_INT_MAP_1 0x56 > +#define BMI160_INT1_MAP_DRDY BIT(7) > +#define BMI160_INT1_MAP_FWM BIT(6) > +#define BMI160_INT1_MAP_FFULL BIT(5) > +#define BMI160_INT2_MAP_DRDY BIT(3) > +#define BMI160_INT2_MAP_FWM BIT(2) > +#define BMI160_INT2_MAP_FFULL BIT(1) > + > #define BMI160_REG_CMD 0x7E > #define BMI160_CMD_ACCEL_PM_SUSPEND 0x10 > #define BMI160_CMD_ACCEL_PM_NORMAL 0x11 > @@ -67,6 +116,8 @@ > > #define BMI160_REG_DUMMY 0x7F > > +#define BMI160_FIFO_LENGTH 1024 > + > #define BMI160_ACCEL_PMU_MIN_USLEEP 3800 > #define BMI160_GYRO_PMU_MIN_USLEEP 80000 > #define BMI160_SOFTRESET_USLEEP 1000 > @@ -109,9 +160,34 @@ enum bmi160_sensor_type { > BMI160_NUM_SENSORS /* must be last */ > }; > > +struct bmi160_irq_data { > + unsigned int map_fwm; > + unsigned int output_en; > +}; > + > +static const struct bmi160_irq_data bmi160_irq1_data = { > + .map_fwm = BMI160_INT1_MAP_FWM, > + .output_en = BMI160_INT1_OUTPUT_EN, > +}; > + > +static const struct bmi160_irq_data bmi160_irq2_data = { > + .map_fwm = BMI160_INT2_MAP_FWM, > + .output_en = BMI160_INT2_OUTPUT_EN, > +}; > + > struct bmi160_data { > struct regmap *regmap; > struct mutex mutex; > + const struct bmi160_irq_data *irq_data; > + int irq; > + bool irq_enabled; > + int64_t timestamp; > + int64_t fifo_sample_period; > + bool fifo_enabled; > + unsigned int fifo_config; > + unsigned int fifo_sample_size; > + u8 *fifo_buffer; > + unsigned int watermark; > }; > > const struct regmap_config bmi160_regmap_config = { > @@ -374,16 +450,20 @@ int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t, > return ret; > } > > -static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, > - int *odr, int *uodr) > +static int64_t bmi160_frequency_to_period(int odr, int uodr) > { > - int i, val, ret; > + uint64_t period = 1000000000000000; > + int64_t frequency = (int64_t) odr * 1000000 + uodr; > > - mutex_lock(&data->mutex); > - ret = regmap_read(data->regmap, bmi160_regs[t].config, &val); > - mutex_unlock(&data->mutex); > - if (ret < 0) > - return ret; > + do_div(period, frequency); > + > + return period; > +} > + > +static const struct bmi160_odr *bmi160_reg_to_odr(enum bmi160_sensor_type t, > + unsigned int val) > +{ > + int i; > > val &= bmi160_regs[t].config_odr_mask; > > @@ -392,10 +472,52 @@ static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, > break; > > if (i >= bmi160_odr_table[t].num) > - return -EINVAL; > + return ERR_PTR(-EINVAL); > > - *odr = bmi160_odr_table[t].tbl[i].odr; > - *uodr = bmi160_odr_table[t].tbl[i].uodr; > + return &bmi160_odr_table[t].tbl[i]; > +} > + > +static int __bmi160_get_sample_period(struct bmi160_data *data, > + enum bmi160_sensor_type t, > + int64_t *sample_period) > +{ > + const struct bmi160_odr *odr_entry; > + int ret; > + unsigned int val; > + > + ret = regmap_read(data->regmap, bmi160_regs[t].config, &val); > + if (ret < 0) > + return ret; > + > + odr_entry = bmi160_reg_to_odr(t, val); > + if (IS_ERR(odr_entry)) > + return PTR_ERR(odr_entry); > + > + *sample_period = bmi160_frequency_to_period(odr_entry->odr, > + odr_entry->uodr); > + > + return 0; > +} > + > +static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, > + int *odr, int *uodr) > +{ > + const struct bmi160_odr *odr_entry; > + int ret; > + unsigned int val; > + > + mutex_lock(&data->mutex); > + ret = regmap_read(data->regmap, bmi160_regs[t].config, &val); > + mutex_unlock(&data->mutex); > + if (ret < 0) > + return ret; > + > + odr_entry = bmi160_reg_to_odr(t, val); > + if (IS_ERR(odr_entry)) > + return PTR_ERR(odr_entry); > + > + *odr = odr_entry->odr; > + *uodr = odr_entry->uodr; > > return 0; > } > @@ -504,6 +626,356 @@ static const struct attribute_group bmi160_attrs_group = { > .attrs = bmi160_attrs, > }; > > +static int __bmi160_read_sample_period(struct bmi160_data *data, > + enum bmi160_sensor_type sensor_type) > +{ > + struct device *dev = regmap_get_device(data->regmap); > + int64_t uninitialized_var(sample_period); > + int ret; > + > + ret = __bmi160_get_sample_period(data, sensor_type, &sample_period); > + if (ret < 0) > + return ret; > + > + if (data->fifo_sample_period) { > + if (data->fifo_sample_period != sample_period) { Ah, I was wondering how you got around this restriction. A bit more limiting than having two separate buffers would have been, but easier to handle and I do wonder how often people actually run these devices with different sampling frequencies... > + dev_warn(dev, "Enabled sensors have unequal ODR values\n"); > + return -EINVAL; > + } > + } else { > + data->fifo_sample_period = sample_period; > + } > + > + return 0; > +} > + > +static int __bmi160_fifo_enable(struct iio_dev *indio_dev, > + struct bmi160_data *data) > +{ > + struct regmap *regmap = data->regmap; > + struct device *dev = regmap_get_device(regmap); > + int ret; > + int i; > + unsigned int val; > + unsigned int fifo_config = 0; > + > + /* Set fifo sample size and period */ > + for_each_set_bit(i, indio_dev->active_scan_mask, > + indio_dev->masklength) { > + if (i <= BMI160_SCAN_GYRO_Z) > + fifo_config |= BMI160_FIFO_GYRO_EN; > + else if (i <= BMI160_SCAN_ACCEL_Z) > + fifo_config |= BMI160_FIFO_ACCEL_EN; > + } > + > + data->fifo_sample_period = 0; > + data->fifo_sample_size = 0; > + if (fifo_config & BMI160_FIFO_GYRO_EN) { > + data->fifo_sample_size += 6; > + ret = __bmi160_read_sample_period(data, BMI160_GYRO); > + if (ret < 0) > + return ret; > + } > + if (fifo_config & BMI160_FIFO_ACCEL_EN) { > + data->fifo_sample_size += 6; > + ret = __bmi160_read_sample_period(data, BMI160_ACCEL); > + if (ret < 0) > + return ret; > + } > + > + /* > + * Set watermark level and write real value back, as it will be used > + * in timestamp calculation. > + */ > + val = data->watermark * data->fifo_sample_size; > + if (val > BMI160_FIFO_LENGTH - 1) { > + val = BMI160_FIFO_LENGTH - 1; > + data->watermark = val / data->fifo_sample_size; > + } > + val = data->watermark * data->fifo_sample_size / 4; > + > + ret = regmap_write(regmap, BMI160_REG_FIFO_CONFIG_0, val); > + if (ret < 0) { > + dev_err(dev, "Failed to set watermark\n"); > + return ret; > + } > + > + /* Enable FIFO channels */ > + ret = regmap_write(regmap, BMI160_REG_FIFO_CONFIG_1, > + fifo_config); > + if (ret < 0) { > + dev_err(dev, "Failed to write FIFO_CONFIG_1\n"); > + return ret; > + } > + > + data->fifo_config = fifo_config; > + data->fifo_enabled = true; > + > + return 0; > +} > + > +static int __bmi160_fifo_disable(struct bmi160_data *data) > +{ > + struct regmap *regmap = data->regmap; > + struct device *dev = regmap_get_device(regmap); > + int ret; > + > + /* Disable all FIFO channels */ > + ret = regmap_write(regmap, BMI160_REG_FIFO_CONFIG_1, 0); > + if (ret < 0) { > + dev_err(dev, "Failed to write FIFO_CONFIG_1\n"); > + return ret; > + } > + > + data->fifo_enabled = false; > + > + return 0; > +} > + > +static int bmi160_buffer_postenable(struct iio_dev *indio_dev) > +{ > + struct bmi160_data *data = iio_priv(indio_dev); > + int ret; > + > + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) > + return iio_triggered_buffer_postenable(indio_dev); > + > + mutex_lock(&data->mutex); > + ret = __bmi160_fifo_enable(indio_dev, data); > + if (ret < 0) > + goto unlock; > + > + ret = regmap_update_bits(data->regmap, BMI160_REG_INT_MAP_1, > + data->irq_data->map_fwm, data->irq_data->map_fwm); > + if (ret < 0) > + goto unlock; > + > + ret = regmap_update_bits(data->regmap, BMI160_REG_INT_EN_1, > + BMI160_INT_FWM_EN, BMI160_INT_FWM_EN); > + > +unlock: > + mutex_unlock(&data->mutex); > + > + return ret; > +} > + > +static int bmi160_buffer_predisable(struct iio_dev *indio_dev) > +{ > + struct bmi160_data *data = iio_priv(indio_dev); > + struct regmap *regmap = data->regmap; > + int ret = 0; > + > + if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) > + return iio_triggered_buffer_predisable(indio_dev); > + > + mutex_lock(&data->mutex); > + ret = regmap_update_bits(regmap, BMI160_REG_INT_EN_1, > + BMI160_INT_FWM_EN, 0); > + if (ret < 0) > + goto unlock; > + > + ret = regmap_update_bits(data->regmap, BMI160_REG_INT_MAP_1, > + data->irq_data->map_fwm, 0); > + if (ret < 0) > + goto unlock; > + > + ret = __bmi160_fifo_disable(data); > + > +unlock: > + mutex_unlock(&data->mutex); > + > + return ret; > +} > + > +static const struct iio_buffer_setup_ops bmi160_buffer_ops = { > + .postenable = bmi160_buffer_postenable, > + .predisable = bmi160_buffer_predisable, > +}; > + > +static ssize_t bmi160_get_fifo_state(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct iio_dev *indio_dev = dev_to_iio_dev(dev); > + struct bmi160_data *data = iio_priv(indio_dev); > + bool state; > + > + mutex_lock(&data->mutex); > + state = data->fifo_enabled; > + mutex_unlock(&data->mutex); > + > + return sprintf(buf, "%d\n", (int) state); > +} > + > +static ssize_t bmi160_get_fifo_watermark(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct iio_dev *indio_dev = dev_to_iio_dev(dev); > + struct bmi160_data *data = iio_priv(indio_dev); > + int wm; > + > + mutex_lock(&data->mutex); > + wm = data->watermark; > + mutex_unlock(&data->mutex); > + > + return sprintf(buf, "%d\n", wm); > +} > + > +static IIO_CONST_ATTR(hwfifo_watermark_min, "1"); > +static IIO_CONST_ATTR(hwfifo_watermark_max, > + __stringify(BMI160_FIFO_LENGTH)); > +static IIO_DEVICE_ATTR(hwfifo_enabled, S_IRUGO, > + bmi160_get_fifo_state, NULL, 0); > +static IIO_DEVICE_ATTR(hwfifo_watermark, S_IRUGO, > + bmi160_get_fifo_watermark, NULL, 0); > + > +static const struct attribute *bmi160_fifo_attributes[] = { > + &iio_const_attr_hwfifo_watermark_min.dev_attr.attr, > + &iio_const_attr_hwfifo_watermark_max.dev_attr.attr, > + &iio_dev_attr_hwfifo_watermark.dev_attr.attr, > + &iio_dev_attr_hwfifo_enabled.dev_attr.attr, > + NULL, > +}; > + > +static int bmi160_set_watermark(struct iio_dev *indio_dev, unsigned int val) > +{ > + struct bmi160_data *data = iio_priv(indio_dev); > + > + if (val > BMI160_FIFO_LENGTH) > + val = BMI160_FIFO_LENGTH; > + > + mutex_lock(&data->mutex); > + data->watermark = val; This is a little interesting, in that mostly people might expect a write to the watermark to be immediately applied if it succeeds. Perhaps protecting with a claim direct mode call (so it faults out if the buffer is enabled) would give a more consistent userspace interface. > + mutex_unlock(&data->mutex); > + > + return 0; > +} > + > +static int __bmi160_fifo_transfer(struct bmi160_data *data, > + char *buffer, int num_bytes) > +{ > + struct regmap *regmap = data->regmap; > + struct device *dev = regmap_get_device(regmap); > + size_t step = regmap_get_raw_read_max(regmap); > + int ret = 0; > + int i; > + > + if (!step || step > num_bytes) > + step = num_bytes; > + else if (step < num_bytes) > + step = data->fifo_sample_size; > + > + for (i = 0; i < num_bytes; i += step) { > + ret = regmap_raw_read(regmap, BMI160_REG_FIFO_DATA, > + &buffer[i], step); When it lands, the new regmap repeated read stuff should simplify this a little. Looks like it missed the recent merge window.. https://patchwork.ozlabs.org/patch/650718/ It's possible the series has died a death as Leonard has move jobs and gone rather quiet. If anyone fancies chasing up what is happening with this and perhaps taking over that work that would be great. > + > + if (ret) > + break; > + } > + > + if (ret) > + dev_err(dev, > + "Error transferring data from fifo in single steps of %zu\n", > + step); > + > + return ret; > +} > + > +static int __bmi160_fifo_flush(struct iio_dev *indio_dev, > + unsigned int samples, bool irq) > +{ > + struct bmi160_data *data = iio_priv(indio_dev); > + struct regmap *regmap = data->regmap; > + struct device *dev = regmap_get_device(regmap); > + int ret; > + __le16 fifo_length; > + unsigned int fifo_samples; > + unsigned int fifo_bytes; > + u8 *buffer = data->fifo_buffer; > + u8 *buffer_iter; > + int64_t last_timestamp, timestamp; > + unsigned int last_samples; > + unsigned int i; > + > + /* Get the current FIFO length */ > + ret = regmap_bulk_read(regmap, BMI160_REG_FIFO_LENGTH, > + &fifo_length, sizeof(__le16)); > + if (ret < 0) { > + dev_err(dev, "Error reading FIFO_LENGTH\n"); > + return ret; > + } > + > + fifo_bytes = le16_to_cpu(fifo_length); > + fifo_samples = fifo_bytes / data->fifo_sample_size; > + > + if (fifo_bytes % data->fifo_sample_size) > + dev_warn(dev, "fifo_bytes %u is not dividable by %u\n", > + fifo_bytes, data->fifo_sample_size); > + > + if (!fifo_samples) > + return 0; > + > + if (samples && fifo_samples > samples) { > + fifo_samples = samples; > + fifo_bytes = fifo_samples * data->fifo_sample_size; > + } > + > + /* > + * If we are not called from IRQ, it means that we are flushing data > + * on demand. In that case we do not have latest timestamp saved in > + * data->timestamp. Get the time now instead. > + * > + * In case of IRQ flush, saved timestamp shows the time when number > + * of samples configured by watermark were ready. Currently there might > + * be more samples already. > + * If we are not called from IRQ, than we are getting the current fifo > + * length, as we are setting timestamp just after getting it. > + */ > + if (!irq) { > + last_timestamp = iio_get_time_ns(indio_dev); > + last_samples = fifo_samples; > + } else { > + last_timestamp = data->timestamp; > + last_samples = data->watermark; > + } > + > + /* Get all measurements */ > + ret = __bmi160_fifo_transfer(data, buffer, fifo_bytes); > + if (ret) > + return ret; > + > + /* Handle demux */ > + timestamp = last_timestamp - (last_samples * data->fifo_sample_period); > + buffer_iter = buffer; > + for (i = 0; i < fifo_samples; i++) { > + u8 tmp_buf[32]; > + > + memcpy(tmp_buf, buffer_iter, data->fifo_sample_size); > + > + timestamp += data->fifo_sample_period; > + iio_push_to_buffers_with_timestamp(indio_dev, > + tmp_buf, > + timestamp); > + > + buffer_iter += data->fifo_sample_size; > + } > + > + return fifo_samples; > +} > + > +static int bmi160_fifo_flush(struct iio_dev *indio_dev, unsigned int samples) > +{ > + struct bmi160_data *data = iio_priv(indio_dev); > + int ret; > + > + mutex_lock(&data->mutex); > + ret = __bmi160_fifo_flush(indio_dev, samples, false); > + mutex_unlock(&data->mutex); > + > + return ret; > +} > + > static const struct iio_info bmi160_info = { > .driver_module = THIS_MODULE, > .read_raw = bmi160_read_raw, > @@ -511,6 +983,15 @@ static const struct iio_info bmi160_info = { > .attrs = &bmi160_attrs_group, > }; > > +static const struct iio_info bmi160_info_fifo = { > + .driver_module = THIS_MODULE, > + .read_raw = bmi160_read_raw, > + .write_raw = bmi160_write_raw, > + .attrs = &bmi160_attrs_group, > + .hwfifo_set_watermark = bmi160_set_watermark, > + .hwfifo_flush_to_buffer = bmi160_fifo_flush, > +}; > + > static const char *bmi160_match_acpi_device(struct device *dev) > { > const struct acpi_device_id *id; > @@ -572,12 +1053,75 @@ static void bmi160_chip_uninit(struct bmi160_data *data) > bmi160_set_mode(data, BMI160_ACCEL, false); > } > > +static int bmi160_enable_irq(struct bmi160_data *data) > +{ > + int ret; > + > + mutex_lock(&data->mutex); > + ret = regmap_update_bits(data->regmap, BMI160_REG_INT_OUT_CTRL, > + data->irq_data->output_en, > + data->irq_data->output_en); > + mutex_unlock(&data->mutex); > + > + if (ret == 0) > + data->irq_enabled = true; > + > + return ret; > +} > + > +static int bmi160_disable_irq(struct bmi160_data *data) > +{ > + int ret; > + > + if (!data->irq_enabled) > + return 0; > + > + mutex_lock(&data->mutex); > + ret = regmap_update_bits(data->regmap, BMI160_REG_INT_OUT_CTRL, > + data->irq_data->output_en, 0); > + mutex_unlock(&data->mutex); > + > + if (ret == 0) > + data->irq_enabled = false; > + > + return ret; > +} > + > +static irqreturn_t bmi160_irq_thread_handler(int irq, void *p) > +{ > + struct iio_dev *indio_dev = p; > + struct bmi160_data *data = iio_priv(indio_dev); > + struct device *dev = regmap_get_device(data->regmap); > + > + mutex_lock(&data->mutex); > + if (data->fifo_enabled) > + __bmi160_fifo_flush(indio_dev, BMI160_FIFO_LENGTH, true); > + else This is not terribly shared interrupt friendly. We should really be verifying that the interrupt seen is ours or returning IRQ_NONE otherwise. Then if we get a load of 'false' interrupts due to hardware issues the unhandled interrupt stuff in the kernel will deal with it for us. > + dev_warn(dev, > + "IRQ has been triggered, but FIFO is not enabled.\n"); > + mutex_unlock(&data->mutex); > + > + return IRQ_HANDLED; > +} > + > +static irqreturn_t bmi160_irq_handler(int irq, void *p) > +{ > + struct iio_dev *indio_dev = p; > + struct bmi160_data *data = iio_priv(indio_dev); > + > + data->timestamp = iio_get_time_ns(indio_dev); > + > + return IRQ_WAKE_THREAD; You could use the utility function: iio_pollfunc_store_timestamp instead of basically replicating it here. > +} > + > int bmi160_core_probe(struct device *dev, struct regmap *regmap, > - const char *name, bool use_spi) > + const char *name, int irq, > + bool use_spi, bool block_supported) > { > struct iio_dev *indio_dev; > struct bmi160_data *data; > int ret; > + int irq2; > > indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); > if (!indio_dev) > @@ -585,6 +1129,7 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, > > data = iio_priv(indio_dev); > dev_set_drvdata(dev, indio_dev); > + data->irq = irq; > data->regmap = regmap; > mutex_init(&data->mutex); > > @@ -603,15 +1148,57 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, > indio_dev->info = &bmi160_info; > > ret = iio_triggered_buffer_setup(indio_dev, NULL, > - bmi160_trigger_handler, NULL); > + bmi160_trigger_handler, > + &bmi160_buffer_ops); > if (ret < 0) > goto uninit; > > + if (data->irq > 0) { > + /* Check which interrupt pin is connected to our board */ > + irq2 = of_irq_get_byname(dev->of_node, "INT2"); > + if (irq2 == data->irq) { > + dev_dbg(dev, "Using interrupt line INT2\n"); > + data->irq_data = &bmi160_irq2_data; > + } else { > + dev_dbg(dev, "Using interrupt line INT1\n"); > + data->irq_data = &bmi160_irq1_data; > + } > + > + ret = devm_request_threaded_irq(dev, > + data->irq, > + bmi160_irq_handler, > + bmi160_irq_thread_handler, > + IRQF_ONESHOT, > + BMI160_IRQ_NAME, > + indio_dev); > + if (ret) > + goto buffer_cleanup; > + > + ret = bmi160_enable_irq(data); > + if (ret < 0) > + goto buffer_cleanup; > + > + if (block_supported) { > + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; > + indio_dev->info = &bmi160_info_fifo; > + indio_dev->buffer->attrs = bmi160_fifo_attributes; > + data->fifo_buffer = devm_kmalloc(dev, > + BMI160_FIFO_LENGTH, > + GFP_KERNEL); > + if (!data->fifo_buffer) { > + ret = -ENOMEM; > + goto disable_irq; > + } > + } > + } > + > ret = iio_device_register(indio_dev); > if (ret < 0) > - goto buffer_cleanup; > + goto disable_irq; > > return 0; > +disable_irq: > + bmi160_disable_irq(data); > buffer_cleanup: > iio_triggered_buffer_cleanup(indio_dev); > uninit: > @@ -626,6 +1213,7 @@ void bmi160_core_remove(struct device *dev) > struct bmi160_data *data = iio_priv(indio_dev); > > iio_device_unregister(indio_dev); > + bmi160_disable_irq(data); > iio_triggered_buffer_cleanup(indio_dev); > bmi160_chip_uninit(data); > } > diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c > index 155a31f..1a3f4e1 100644 > --- a/drivers/iio/imu/bmi160/bmi160_i2c.c > +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c > @@ -24,6 +24,10 @@ static int bmi160_i2c_probe(struct i2c_client *client, > { > struct regmap *regmap; > const char *name = NULL; > + bool block_supported = > + i2c_check_functionality(client->adapter, I2C_FUNC_I2C) || > + i2c_check_functionality(client->adapter, > + I2C_FUNC_SMBUS_READ_I2C_BLOCK); > > regmap = devm_regmap_init_i2c(client, &bmi160_regmap_config); > if (IS_ERR(regmap)) { > @@ -35,7 +39,8 @@ static int bmi160_i2c_probe(struct i2c_client *client, > if (id) > name = id->name; > > - return bmi160_core_probe(&client->dev, regmap, name, false); > + return bmi160_core_probe(&client->dev, regmap, name, client->irq, > + false, block_supported); > } > > static int bmi160_i2c_remove(struct i2c_client *client) > diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c > index d34dfdf..5a53225 100644 > --- a/drivers/iio/imu/bmi160/bmi160_spi.c > +++ b/drivers/iio/imu/bmi160/bmi160_spi.c > @@ -26,7 +26,8 @@ static int bmi160_spi_probe(struct spi_device *spi) > (int)PTR_ERR(regmap)); > return PTR_ERR(regmap); > } > - return bmi160_core_probe(&spi->dev, regmap, id->name, true); > + return bmi160_core_probe(&spi->dev, regmap, id->name, spi->irq, > + true, true); > } > > static int bmi160_spi_remove(struct spi_device *spi) > ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2016-12-30 11:29 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-12-08 14:22 [PATCH v2 0/6] iio: bmi160: cleanups and hardware fifo support Marcin Niestroj [not found] ` <20161208142259.26230-1-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-08 14:22 ` [PATCH v2 1/6] iio: bmi160: Add of device table for i2c Marcin Niestroj [not found] ` <20161208142259.26230-2-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-30 10:47 ` Jonathan Cameron 2016-12-08 14:22 ` [PATCH v2 2/6] iio: bmi160: Add of device table for spi Marcin Niestroj 2016-12-08 14:22 ` [PATCH v2 3/6] Documentation: DT: Add bmi160 imu binding Marcin Niestroj [not found] ` <20161208142259.26230-4-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-12 17:15 ` Rob Herring 2016-12-30 10:40 ` Jonathan Cameron 2016-12-08 14:22 ` [PATCH v2 4/6] iio: bmi160: Protect data transmission with mutex Marcin Niestroj [not found] ` <20161208142259.26230-5-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-30 10:47 ` Jonathan Cameron 2016-12-08 14:22 ` [PATCH v2 5/6] iio: bmi160: Fix time needed to sleep after command execution Marcin Niestroj [not found] ` <20161208142259.26230-6-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-30 10:49 ` Jonathan Cameron [not found] ` <7668f191-dafd-e616-171a-cafc52791292-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> 2016-12-30 10:51 ` Jonathan Cameron 2016-12-08 14:22 ` [PATCH v2 6/6] iio: bmi160: Support hardware fifo Marcin Niestroj [not found] ` <20161208142259.26230-7-m.niestroj-z3quKL4iOrmQ6ZAhV5LmOA@public.gmane.org> 2016-12-30 11:29 ` Jonathan Cameron
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).