linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/8] add magnetometer support for MPU925x
@ 2019-08-29 15:18 Jean-Baptiste Maneyrol
  2019-08-29 15:18 ` [PATCH 1/8] iio: imu: inv_mpu6050: disable i2c mux for 925x under Kconfig Jean-Baptiste Maneyrol
                   ` (8 more replies)
  0 siblings, 9 replies; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-08-29 15:18 UTC (permalink / raw)
  To: jic23; +Cc: linux-iio, Jean-Baptiste Maneyrol

This serie of patches adds support of magnetometer inside MPU925x chips.
It is using the MPU i2c master to drive the integrated magnetometer and
read data into the MPU FIFO.

Beware that this is disabling access to the i2c auxiliary bus. Since this
can break existing setup, it is an optional feature requiring to enable
the corresponding Kconfig option.

Jean-Baptiste Maneyrol (8):
  iio: imu: inv_mpu6050: disable i2c mux for 925x under Kconfig
  iio: imu: inv_mpu6050: add header include protection macro
  iio: imu: inv_mpu6050: add defines for supporting 9-axis chips
  iio: imu: inv_mpu6050: fix objects syntax in Makefile
  iio: imu: inv_mpu6050: helpers for using i2c master on auxiliary bus
  iio: imu: inv_mpu6050: add magnetometer implementation for MPU925x
  iio: imu: inv_mpu6050: add magnetometer support inside mpu driver
  iio: imu: inv_mpu6050: add fifo support for magnetometer data

 drivers/iio/imu/inv_mpu6050/Kconfig           |   9 +
 drivers/iio/imu/inv_mpu6050/Makefile          |   8 +-
 .../iio/imu/inv_mpu6050/inv_mpu9250_magn.c    | 239 ++++++++++++++++++
 .../iio/imu/inv_mpu6050/inv_mpu9250_magn.h    |  27 ++
 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c     | 191 ++++++++++++++
 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h     |  46 ++++
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c    | 141 ++++++++++-
 drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c     |   5 +
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |  79 +++++-
 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c    | 120 +++++++++
 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h    | 107 ++++++++
 drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c    |  14 +-
 drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c |  90 ++++++-
 13 files changed, 1055 insertions(+), 21 deletions(-)
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h

-- 
2.17.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/8] iio: imu: inv_mpu6050: disable i2c mux for 925x under Kconfig
  2019-08-29 15:18 [PATCH 0/8] add magnetometer support for MPU925x Jean-Baptiste Maneyrol
@ 2019-08-29 15:18 ` Jean-Baptiste Maneyrol
  2019-08-29 15:18 ` [PATCH 2/8] iio: imu: inv_mpu6050: add header include protection macro Jean-Baptiste Maneyrol
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-08-29 15:18 UTC (permalink / raw)
  To: jic23; +Cc: linux-iio, Jean-Baptiste Maneyrol

Disable i2c mux for supported 9xxx chips when a Kconfig option
is enabled.
Add the new Kconfig option for enabling control of 9xxx
magnetometer using the i2c master of the chip. Since it has to be
explicitly enabled, we assure retro-compatibility with existing
configuration.

Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
 drivers/iio/imu/inv_mpu6050/Kconfig       | 9 +++++++++
 drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c | 5 +++++
 2 files changed, 14 insertions(+)

diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig
index e4c4c12236a7..a92b723c6b32 100644
--- a/drivers/iio/imu/inv_mpu6050/Kconfig
+++ b/drivers/iio/imu/inv_mpu6050/Kconfig
@@ -31,3 +31,12 @@ config INV_MPU6050_SPI
 	  over SPI.
 	  This driver can be built as a module. The module will be called
 	  inv-mpu6050-spi.
+
+config INV_MPU6050_MAGN
+	bool "Invensense 9-axis magnetometer support"
+	depends on INV_MPU6050_IIO
+	help
+	  For 9xxx chips add support of 9-axis in the driver using chip
+	  i2c master to drive the integrated magnetometer.
+	  Beware that this is disabling access to the i2c auxiliary bus!
+	  Support only MPU925x.
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
index 4b8b5a87398c..4c318304f9c6 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c
@@ -121,6 +121,11 @@ static int inv_mpu_probe(struct i2c_client *client,
 	case INV_ICM20608:
 	case INV_ICM20602:
 		/* no i2c auxiliary bus on the chip */
+#ifdef CONFIG_INV_MPU6050_MAGN
+	case INV_MPU9250:
+	case INV_MPU9255:
+		/* i2c auxiliary bus used for driving magnetometer */
+#endif
 		break;
 	default:
 		/* declare i2c auxiliary bus */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 2/8] iio: imu: inv_mpu6050: add header include protection macro
  2019-08-29 15:18 [PATCH 0/8] add magnetometer support for MPU925x Jean-Baptiste Maneyrol
  2019-08-29 15:18 ` [PATCH 1/8] iio: imu: inv_mpu6050: disable i2c mux for 925x under Kconfig Jean-Baptiste Maneyrol
@ 2019-08-29 15:18 ` Jean-Baptiste Maneyrol
  2019-08-29 15:18 ` [PATCH 3/8] iio: imu: inv_mpu6050: add defines for supporting 9-axis chips Jean-Baptiste Maneyrol
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-08-29 15:18 UTC (permalink / raw)
  To: jic23; +Cc: linux-iio, Jean-Baptiste Maneyrol

Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index db1c6904388b..e64eb978e810 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -2,6 +2,10 @@
 /*
 * Copyright (C) 2012 Invensense, Inc.
 */
+
+#ifndef INV_MPU_IIO_H_
+#define INV_MPU_IIO_H_
+
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
 #include <linux/mutex.h>
@@ -342,3 +346,5 @@ void inv_mpu_acpi_delete_mux_client(struct i2c_client *client);
 int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
 		int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type);
 extern const struct dev_pm_ops inv_mpu_pmops;
+
+#endif
-- 
2.17.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 3/8] iio: imu: inv_mpu6050: add defines for supporting 9-axis chips
  2019-08-29 15:18 [PATCH 0/8] add magnetometer support for MPU925x Jean-Baptiste Maneyrol
  2019-08-29 15:18 ` [PATCH 1/8] iio: imu: inv_mpu6050: disable i2c mux for 925x under Kconfig Jean-Baptiste Maneyrol
  2019-08-29 15:18 ` [PATCH 2/8] iio: imu: inv_mpu6050: add header include protection macro Jean-Baptiste Maneyrol
@ 2019-08-29 15:18 ` Jean-Baptiste Maneyrol
  2019-08-29 15:18 ` [PATCH 4/8] iio: imu: inv_mpu6050: fix objects syntax in Makefile Jean-Baptiste Maneyrol
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-08-29 15:18 UTC (permalink / raw)
  To: jic23; +Cc: linux-iio, Jean-Baptiste Maneyrol

Add registers defines required for driving chip i2c master ip.
Add MPU9xxx magnetometer scan elements and update data bytes size.

Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 65 ++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 2 deletions(-)

diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index e64eb978e810..82669ecb4735 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -162,9 +162,41 @@ struct inv_mpu6050_state {
 #define INV_MPU6050_REG_ACCEL_CONFIG        0x1C
 
 #define INV_MPU6050_REG_FIFO_EN             0x23
+#define INV_MPU6050_BIT_SLAVE_0             0x01
+#define INV_MPU6050_BIT_SLAVE_1             0x02
+#define INV_MPU6050_BIT_SLAVE_2             0x04
 #define INV_MPU6050_BIT_ACCEL_OUT           0x08
 #define INV_MPU6050_BITS_GYRO_OUT           0x70
 
+#define INV_MPU6050_REG_I2C_MST_CTRL        0x24
+#define INV_MPU6050_BITS_I2C_MST_CLK_400KHZ 0x0D
+#define INV_MPU6050_BIT_I2C_MST_P_NSR       0x10
+#define INV_MPU6050_BIT_SLV3_FIFO_EN        0x20
+#define INV_MPU6050_BIT_WAIT_FOR_ES         0x40
+#define INV_MPU6050_BIT_MULT_MST_EN         0x80
+
+/* control I2C slaves from 0 to 3 */
+#define INV_MPU6050_REG_I2C_SLV_ADDR(_x)    (0x25 + 3 * (_x))
+#define INV_MPU6050_BIT_I2C_SLV_RNW         0x80
+
+#define INV_MPU6050_REG_I2C_SLV_REG(_x)     (0x26 + 3 * (_x))
+
+#define INV_MPU6050_REG_I2C_SLV_CTRL(_x)    (0x27 + 3 * (_x))
+#define INV_MPU6050_BIT_SLV_GRP             0x10
+#define INV_MPU6050_BIT_SLV_REG_DIS         0x20
+#define INV_MPU6050_BIT_SLV_BYTE_SW         0x40
+#define INV_MPU6050_BIT_SLV_EN              0x80
+
+/* I2C master delay register */
+#define INV_MPU6050_REG_I2C_SLV4_CTRL       0x34
+#define INV_MPU6050_BITS_I2C_MST_DLY(_x)    ((_x) & 0x1F)
+
+#define INV_MPU6050_REG_I2C_MST_STATUS      0x36
+#define INV_MPU6050_BIT_I2C_SLV0_NACK       0x01
+#define INV_MPU6050_BIT_I2C_SLV1_NACK       0x02
+#define INV_MPU6050_BIT_I2C_SLV2_NACK       0x04
+#define INV_MPU6050_BIT_I2C_SLV3_NACK       0x08
+
 #define INV_MPU6050_REG_INT_ENABLE          0x38
 #define INV_MPU6050_BIT_DATA_RDY_EN         0x01
 #define INV_MPU6050_BIT_DMP_INT_EN          0x02
@@ -177,6 +209,18 @@ struct inv_mpu6050_state {
 #define INV_MPU6050_BIT_FIFO_OVERFLOW_INT   0x10
 #define INV_MPU6050_BIT_RAW_DATA_RDY_INT    0x01
 
+#define INV_MPU6050_REG_EXT_SENS_DATA       0x49
+
+/* I2C slaves data output from 0 to 3 */
+#define INV_MPU6050_REG_I2C_SLV_DO(_x)      (0x63 + (_x))
+
+#define INV_MPU6050_REG_I2C_MST_DELAY_CTRL  0x67
+#define INV_MPU6050_BIT_I2C_SLV0_DLY_EN     0x01
+#define INV_MPU6050_BIT_I2C_SLV1_DLY_EN     0x02
+#define INV_MPU6050_BIT_I2C_SLV2_DLY_EN     0x04
+#define INV_MPU6050_BIT_I2C_SLV3_DLY_EN     0x08
+#define INV_MPU6050_BIT_DELAY_ES_SHADOW     0x80
+
 #define INV_MPU6050_REG_USER_CTRL           0x6A
 #define INV_MPU6050_BIT_FIFO_RST            0x04
 #define INV_MPU6050_BIT_DMP_RST             0x08
@@ -204,6 +248,9 @@ struct inv_mpu6050_state {
 #define INV_MPU6050_BYTES_PER_3AXIS_SENSOR   6
 #define INV_MPU6050_FIFO_COUNT_BYTE          2
 
+/* MPU9X50 9-axis magnetometer */
+#define INV_MPU9X50_BYTES_MAGN               7
+
 /* ICM20602 FIFO samples include temperature readings */
 #define INV_ICM20602_BYTES_PER_TEMP_SENSOR   2
 
@@ -231,8 +278,8 @@ struct inv_mpu6050_state {
 #define INV_ICM20602_TEMP_OFFSET	     8170
 #define INV_ICM20602_TEMP_SCALE		     3060
 
-/* 6 + 6 round up and plus 8 */
-#define INV_MPU6050_OUTPUT_DATA_SIZE         24
+/* 6 + 6 + 7 (for MPU9x50) round up and plus 8 */
+#define INV_MPU6050_OUTPUT_DATA_SIZE         32
 
 #define INV_MPU6050_REG_INT_PIN_CFG	0x37
 #define INV_MPU6050_ACTIVE_HIGH		0x00
@@ -283,6 +330,20 @@ enum inv_mpu6050_scan {
 	INV_MPU6050_SCAN_TIMESTAMP,
 };
 
+/* scan element definition for MPU9x50 devices */
+enum inv_mpu9x50_scan {
+	INV_MPU9X50_SCAN_ACCL_X,
+	INV_MPU9X50_SCAN_ACCL_Y,
+	INV_MPU9X50_SCAN_ACCL_Z,
+	INV_MPU9X50_SCAN_GYRO_X,
+	INV_MPU9X50_SCAN_GYRO_Y,
+	INV_MPU9X50_SCAN_GYRO_Z,
+	INV_MPU9X50_SCAN_MAGN_X,
+	INV_MPU9X50_SCAN_MAGN_Y,
+	INV_MPU9X50_SCAN_MAGN_Z,
+	INV_MPU9X50_SCAN_TIMESTAMP,
+};
+
 /* scan element definition for ICM20602, which includes temperature */
 enum inv_icm20602_scan {
 	INV_ICM20602_SCAN_ACCL_X,
-- 
2.17.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 4/8] iio: imu: inv_mpu6050: fix objects syntax in Makefile
  2019-08-29 15:18 [PATCH 0/8] add magnetometer support for MPU925x Jean-Baptiste Maneyrol
                   ` (2 preceding siblings ...)
  2019-08-29 15:18 ` [PATCH 3/8] iio: imu: inv_mpu6050: add defines for supporting 9-axis chips Jean-Baptiste Maneyrol
@ 2019-08-29 15:18 ` Jean-Baptiste Maneyrol
  2019-08-29 15:18 ` [PATCH 5/8] iio: imu: inv_mpu6050: helpers for using i2c master on auxiliary bus Jean-Baptiste Maneyrol
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-08-29 15:18 UTC (permalink / raw)
  To: jic23; +Cc: linux-iio, Jean-Baptiste Maneyrol

Use the correct syntax *-y for declaring object files.

Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
 drivers/iio/imu/inv_mpu6050/Makefile | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile
index 70ffe0d13d8c..33bec09fee9b 100644
--- a/drivers/iio/imu/inv_mpu6050/Makefile
+++ b/drivers/iio/imu/inv_mpu6050/Makefile
@@ -4,10 +4,10 @@
 #
 
 obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
-inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
+inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
 
 obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o
-inv-mpu6050-i2c-objs := inv_mpu_i2c.o inv_mpu_acpi.o
+inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o
 
 obj-$(CONFIG_INV_MPU6050_SPI) += inv-mpu6050-spi.o
-inv-mpu6050-spi-objs := inv_mpu_spi.o
+inv-mpu6050-spi-y := inv_mpu_spi.o
-- 
2.17.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 5/8] iio: imu: inv_mpu6050: helpers for using i2c master on auxiliary bus
  2019-08-29 15:18 [PATCH 0/8] add magnetometer support for MPU925x Jean-Baptiste Maneyrol
                   ` (3 preceding siblings ...)
  2019-08-29 15:18 ` [PATCH 4/8] iio: imu: inv_mpu6050: fix objects syntax in Makefile Jean-Baptiste Maneyrol
@ 2019-08-29 15:18 ` Jean-Baptiste Maneyrol
  2019-09-08 11:57   ` Jonathan Cameron
  2019-08-29 15:18 ` [PATCH 6/8] iio: imu: inv_mpu6050: add magnetometer implementation for MPU925x Jean-Baptiste Maneyrol
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-08-29 15:18 UTC (permalink / raw)
  To: jic23; +Cc: linux-iio, Jean-Baptiste Maneyrol

Add helper functions to use the i2c auxiliary bus with the MPU i2c
master block.

Support only register based chip, reading and 1 byte writing. These
will be useful for initializing magnetometers inside MPU9x50 chips.

Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
 drivers/iio/imu/inv_mpu6050/Makefile      |   1 +
 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c | 191 ++++++++++++++++++++++
 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h |  46 ++++++
 3 files changed, 238 insertions(+)
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h

diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile
index 33bec09fee9b..187f003c81f2 100644
--- a/drivers/iio/imu/inv_mpu6050/Makefile
+++ b/drivers/iio/imu/inv_mpu6050/Makefile
@@ -5,6 +5,7 @@
 
 obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
 inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
+inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o
 
 obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o
 inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
new file mode 100644
index 000000000000..afb957567c12
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
@@ -0,0 +1,191 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 TDK-InvenSense, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+
+#include "inv_mpu_iio.h"
+
+/*
+ * i2c master auxiliary bus transfer function.
+ * Requires the i2c operations to be correctly setup before.
+ */
+static int inv_mpu_i2c_master_xfer(const struct inv_mpu6050_state *st)
+{
+	/* use 50hz frequency for xfer */
+	const unsigned int freq = 50;
+	const unsigned int period_ms = 1000 / freq;
+	uint8_t d;
+	unsigned int user_ctrl;
+	int ret;
+
+	/* set sample rate */
+	d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(freq);
+	ret = regmap_write(st->map, st->reg->sample_rate_div, d);
+	if (ret)
+		return ret;
+
+	/* start i2c master */
+	user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN;
+	ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
+	if (ret)
+		goto error_restore_rate;
+
+	/* wait for xfer: 1 period + half-period margin */
+	msleep(period_ms + period_ms / 2);
+
+	/* stop i2c master */
+	user_ctrl = st->chip_config.user_ctrl;
+	ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
+	if (ret)
+		goto error_stop_i2c;
+
+	/* restore sample rate */
+	d = st->chip_config.divider;
+	ret = regmap_write(st->map, st->reg->sample_rate_div, d);
+	if (ret)
+		goto error_restore_rate;
+
+	return 0;
+
+error_stop_i2c:
+	regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl);
+error_restore_rate:
+	regmap_write(st->map, st->reg->sample_rate_div, st->chip_config.divider);
+	return ret;
+}
+
+int inv_mpu_aux_init(const struct inv_mpu6050_state *st)
+{
+	unsigned int val;
+	int ret;
+
+	/* configure i2c master */
+	val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ |
+			INV_MPU6050_BIT_WAIT_FOR_ES;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_MST_CTRL, val);
+	if (ret)
+		return ret;
+
+	/* configure i2c master delay */
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, 0);
+	if (ret)
+		return ret;
+	val = INV_MPU6050_BIT_I2C_SLV0_DLY_EN |
+			INV_MPU6050_BIT_I2C_SLV1_DLY_EN |
+			INV_MPU6050_BIT_I2C_SLV2_DLY_EN |
+			INV_MPU6050_BIT_I2C_SLV3_DLY_EN |
+			INV_MPU6050_BIT_DELAY_ES_SHADOW;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_MST_DELAY_CTRL, val);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * i2c slave reading using SLV0
+ */
+int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr,
+		     uint8_t reg, uint8_t *val, size_t size)
+{
+	unsigned int status;
+	int ret;
+
+	if (size > 0x0F)
+		return -EINVAL;
+
+	/* setup i2c SLV0 control: i2c addr, register, enable + size */
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0),
+			   INV_MPU6050_BIT_I2C_SLV_RNW | addr);
+	if (ret)
+		return ret;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg);
+	if (ret)
+		return ret;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
+			   INV_MPU6050_BIT_SLV_EN | size);
+	if (ret)
+		return ret;
+
+	/* do i2c xfer */
+	ret = inv_mpu_i2c_master_xfer(st);
+	if (ret)
+		goto error_disable_i2c;
+
+	/* disable i2c slave */
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
+	if (ret)
+		goto error_disable_i2c;
+
+	/* check i2c status */
+	ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
+	if (ret)
+		return ret;
+	if (status & INV_MPU6050_BIT_I2C_SLV0_NACK)
+		return -EIO;
+
+	/* read data in registers */
+	ret = regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
+			       val, size);
+	if (ret)
+		return ret;
+
+	return 0;
+
+error_disable_i2c:
+	regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
+	return ret;
+}
+
+/*
+ * i2c slave writing 1 byte using SLV0
+ */
+int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr,
+		      uint8_t reg, uint8_t val)
+{
+	unsigned int status;
+	int ret;
+
+	/* setup i2c SLV0 control: i2c addr, register, value, enable + size */
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0), addr);
+	if (ret)
+		return ret;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg);
+	if (ret)
+		return ret;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(0), val);
+	if (ret)
+		return ret;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
+			   INV_MPU6050_BIT_SLV_EN | 1);
+	if (ret)
+		return ret;
+
+	/* do i2c xfer */
+	ret = inv_mpu_i2c_master_xfer(st);
+	if (ret)
+		goto error_disable_i2c;
+
+	/* disable i2c slave */
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
+	if (ret)
+		goto error_disable_i2c;
+
+	/* check i2c status */
+	ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
+	if (ret)
+		return ret;
+	if (status & INV_MPU6050_BIT_I2C_SLV0_NACK)
+		return -EIO;
+
+	return 0;
+
+error_disable_i2c:
+	regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
+	return ret;
+}
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h
new file mode 100644
index 000000000000..bae4eab58e6c
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 TDK-InvenSense, Inc.
+ */
+
+#ifndef INV_MPU_AUX_H_
+#define INV_MPU_AUX_H_
+
+#include <linux/kernel.h>
+
+#include "inv_mpu_iio.h"
+
+/**
+ * inv_mpu_aux_init() - init i2c auxiliary bus
+ * @st: driver internal state
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int inv_mpu_aux_init(const struct inv_mpu6050_state *st);
+
+/**
+ * inv_mpu_aux_read() - read register function for i2c auxiliary bus
+ * @st: driver internal state.
+ * @addr: chip i2c Address
+ * @reg: chip register address
+ * @val: buffer for storing read bytes
+ * @size: number of bytes to read
+ *
+ *  Returns 0 on success, a negative error code otherwise.
+ */
+int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr,
+		     uint8_t reg, uint8_t *val, size_t size);
+
+/**
+ * inv_mpu_aux_write() - write register function for i2c auxiliary bus
+ * @st: driver internal state.
+ * @addr: chip i2c Address
+ * @reg: chip register address
+ * @val: 1 byte value to write
+ *
+ *  Returns 0 on success, a negative error code otherwise.
+ */
+int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr,
+		      uint8_t reg, uint8_t val);
+
+#endif		/* INV_MPU_AUX_H_ */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 6/8] iio: imu: inv_mpu6050: add magnetometer implementation for MPU925x
  2019-08-29 15:18 [PATCH 0/8] add magnetometer support for MPU925x Jean-Baptiste Maneyrol
                   ` (4 preceding siblings ...)
  2019-08-29 15:18 ` [PATCH 5/8] iio: imu: inv_mpu6050: helpers for using i2c master on auxiliary bus Jean-Baptiste Maneyrol
@ 2019-08-29 15:18 ` Jean-Baptiste Maneyrol
  2019-09-08 11:57   ` Jonathan Cameron
  2019-08-29 15:18 ` [PATCH 7/8] iio: imu: inv_mpu6050: add magnetometer support inside mpu driver Jean-Baptiste Maneyrol
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-08-29 15:18 UTC (permalink / raw)
  To: jic23; +Cc: linux-iio, Jean-Baptiste Maneyrol

Add implementation for driving MPU9250 magnetometer connected on
i2c auxiliary bus using the MPU i2c master. This is currently not
wired inside the main mpu driver.

Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
 drivers/iio/imu/inv_mpu6050/Makefile          |   2 +-
 .../iio/imu/inv_mpu6050/inv_mpu9250_magn.c    | 239 ++++++++++++++++++
 .../iio/imu/inv_mpu6050/inv_mpu9250_magn.h    |  27 ++
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |   4 +
 4 files changed, 271 insertions(+), 1 deletion(-)
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h

diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile
index 187f003c81f2..fee41415ebdb 100644
--- a/drivers/iio/imu/inv_mpu6050/Makefile
+++ b/drivers/iio/imu/inv_mpu6050/Makefile
@@ -5,7 +5,7 @@
 
 obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
 inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
-inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o
+inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o inv_mpu9250_magn.o
 
 obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o
 inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c
new file mode 100644
index 000000000000..0c2230247557
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 TDK-InvenSense, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <asm/unaligned.h>
+
+#include "inv_mpu_iio.h"
+#include "inv_mpu_aux.h"
+#include "inv_mpu9250_magn.h"
+
+/*
+ * MPU9250 magnetometer is an AKM AK8963 chip on I2C aux bus
+ */
+#define INV_MPU9250_MAGN_I2C_ADDR		0x0C
+
+#define INV_MPU9250_MAGN_REG_WIA		0x00
+#define INV_MPU9250_MAGN_BITS_WIA		0x48
+
+#define INV_MPU9250_MAGN_REG_ST1		0x02
+#define INV_MPU9250_MAGN_BIT_DRDY		0x01
+#define INV_MPU9250_MAGN_BIT_DOR		0x02
+
+#define INV_MPU9250_MAGN_REG_DATA		0x03
+
+#define INV_MPU9250_MAGN_REG_ST2		0x09
+#define INV_MPU9250_MAGN_BIT_HOFL		0x08
+#define INV_MPU9250_MAGN_BIT_BITM		0x10
+
+#define INV_MPU9250_MAGN_REG_CNTL1		0x0A
+#define INV_MPU9250_MAGN_BITS_MODE_PWDN		0x00
+#define INV_MPU9250_MAGN_BITS_MODE_SINGLE	0x01
+#define INV_MPU9250_MAGN_BITS_MODE_FUSE		0x0F
+#define INV_MPU9250_MAGN_BIT_OUTPUT_BIT		0x10
+
+#define INV_MPU9250_MAGN_REG_CNTL2		0x0B
+#define INV_MPU9250_MAGN_BIT_SRST		0x01
+
+#define INV_MPU9250_MAGN_REG_ASAX		0x10
+#define INV_MPU9250_MAGN_REG_ASAY		0x11
+#define INV_MPU9250_MAGN_REG_ASAZ		0x12
+
+/* init magnetometer chip */
+static int inv_magn_init(struct inv_mpu6050_state *st)
+{
+	uint8_t val;
+	uint8_t asa[3];
+	int ret;
+
+	/* check whoami */
+	ret = inv_mpu_aux_read(st, INV_MPU9250_MAGN_I2C_ADDR,
+			       INV_MPU9250_MAGN_REG_WIA, &val, sizeof(val));
+	if (ret)
+		return ret;
+	if (val != INV_MPU9250_MAGN_BITS_WIA)
+		return -ENODEV;
+
+	/* reset chip */
+	ret = inv_mpu_aux_write(st, INV_MPU9250_MAGN_I2C_ADDR,
+				INV_MPU9250_MAGN_REG_CNTL2,
+				INV_MPU9250_MAGN_BIT_SRST);
+	if (ret)
+		return ret;
+
+	/* read fuse ROM data */
+	ret = inv_mpu_aux_write(st, INV_MPU9250_MAGN_I2C_ADDR,
+				INV_MPU9250_MAGN_REG_CNTL1,
+				INV_MPU9250_MAGN_BITS_MODE_FUSE);
+	if (ret)
+		return ret;
+	ret = inv_mpu_aux_read(st, INV_MPU9250_MAGN_I2C_ADDR,
+			       INV_MPU9250_MAGN_REG_ASAX, asa, sizeof(asa));
+	if (ret)
+		return ret;
+
+	/* switch back to power-down */
+	ret = inv_mpu_aux_write(st, INV_MPU9250_MAGN_I2C_ADDR,
+				INV_MPU9250_MAGN_REG_CNTL1,
+				INV_MPU9250_MAGN_BITS_MODE_PWDN);
+	if (ret)
+		return ret;
+
+	/*
+	 * Sensitivity adjustement and scale to Gauss
+	 *
+	 * Hadj = H * (((ASA - 128) * 0.5 / 128) + 1)
+	 * Factor simplification:
+	 * Hadj = H * ((ASA + 128) / 256)
+	 *
+	 * sensor sensitivity: 0.15 uT (16 bits)
+	 * 1 uT = 0.01 G and value is in micron (1e6)
+	 *
+	 * Hadj = H * ((ASA + 128) / 256) * 0.15 * 0.01 * 1e6
+	 * Hadj = H * ((ASA + 128) / 256) * 1500
+	 */
+	st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * 1500) / 256;
+	st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * 1500) / 256;
+	st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * 1500) / 256;
+
+	return 0;
+}
+
+/**
+ * Probe magnetometer chip and setup all i2c transfers.
+ * SLV0: read sensor data
+ * SLV1: launch sensor single measurement
+ *
+ * Sampling data requires 2 cycles to read after measurement.
+ * A measurement can take up to ~10ms.
+ */
+int inv_mpu9250_magn_probe(struct inv_mpu6050_state *st)
+{
+	int ret;
+
+	/* check and init mag chip */
+	ret = inv_magn_init(st);
+	if (ret)
+		return ret;
+
+	/*
+	 * configure mpu i2c master accesses
+	 * i2c SLV0: read sensor data, 7 bytes data(6)-ST2
+	 * Byte swap data to store them in big-endian in impair address groups
+	 */
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0),
+			   INV_MPU6050_BIT_I2C_SLV_RNW |
+			   INV_MPU9250_MAGN_I2C_ADDR);
+	if (ret)
+		return ret;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0),
+			   INV_MPU9250_MAGN_REG_DATA);
+	if (ret)
+		return ret;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
+			   INV_MPU6050_BIT_SLV_EN |
+			   INV_MPU6050_BIT_SLV_BYTE_SW |
+			   INV_MPU6050_BIT_SLV_GRP |
+			   INV_MPU9X50_BYTES_MAGN);
+	if (ret)
+		return ret;
+
+	/* i2c SLV1: launch single measurement */
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(1),
+			   INV_MPU9250_MAGN_I2C_ADDR);
+	if (ret)
+		return ret;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(1),
+			   INV_MPU9250_MAGN_REG_CNTL1);
+	if (ret)
+		return ret;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1),
+			   INV_MPU9250_MAGN_BITS_MODE_SINGLE |
+			   INV_MPU9250_MAGN_BIT_OUTPUT_BIT);
+	if (ret)
+		return ret;
+	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(1),
+			   INV_MPU6050_BIT_SLV_EN | 1);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/**
+ * Read magnetometer data from MPU fifo.
+ * Sampling data requires running the i2c master for 2 cycles.
+ * Use magnetometer maximal supported frequency.
+ */
+int inv_mpu9250_magn_read(const struct inv_mpu6050_state *st, int axis,
+			  int *val)
+{
+	unsigned int user_ctrl, status;
+	__be16 data[3];
+	uint8_t addr;
+	uint8_t d;
+	unsigned int period_ms;
+	int ret;
+
+	/* Mag data: X - Y - Z */
+	switch (axis) {
+	case IIO_MOD_X:
+		addr = 0;
+		break;
+	case IIO_MOD_Y:
+		addr = 1;
+		break;
+	case IIO_MOD_Z:
+		addr = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* set sample rate to max mag freq */
+	d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU9250_MAGN_FREQ_HZ_MAX);
+	ret = regmap_write(st->map, st->reg->sample_rate_div, d);
+	if (ret)
+		return ret;
+
+	/* start i2c master, wait for xfer, stop */
+	user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN;
+	ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
+	if (ret)
+		return ret;
+	/* need to wait 2 periods + half-period margin */
+	period_ms = 1000 / INV_MPU9250_MAGN_FREQ_HZ_MAX;
+	msleep(period_ms * 2 + period_ms / 2);
+	user_ctrl = st->chip_config.user_ctrl;
+	ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
+	if (ret)
+		return ret;
+
+	/* restore sample rate */
+	d = st->chip_config.divider;
+	ret = regmap_write(st->map, st->reg->sample_rate_div, d);
+	if (ret)
+		return ret;
+
+	/* check i2c status and read raw data */
+	ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
+	if (ret)
+		return ret;
+	if (status & INV_MPU6050_BIT_I2C_SLV0_NACK ||
+			status & INV_MPU6050_BIT_I2C_SLV1_NACK)
+		return -EIO;
+	ret = regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
+			       data, sizeof(data));
+	if (ret)
+		return ret;
+
+	*val = (int16_t)be16_to_cpu(data[addr]);
+
+	return IIO_VAL_INT;
+}
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h b/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h
new file mode 100644
index 000000000000..9899dd6c560c
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 TDK-InvenSense, Inc.
+ */
+
+#ifndef INV_MPU9250_MAGN_H_
+#define INV_MPU9250_MAGN_H_
+
+#include <linux/kernel.h>
+
+#include "inv_mpu_iio.h"
+
+/* Magnetometer maximum frequency */
+#define INV_MPU9250_MAGN_FREQ_HZ_MAX		50
+
+/**
+ * inv_mpu9250_magn_probe() - MPU9250 implementation
+ */
+int inv_mpu9250_magn_probe(struct inv_mpu6050_state *st);
+
+/**
+ * inv_mpu9250_magn_read() - MPU9250 implementation
+ */
+int inv_mpu9250_magn_read(const struct inv_mpu6050_state *st, int axis,
+			  int *val);
+
+#endif
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index 82669ecb4735..5b462672bbcb 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -129,6 +129,7 @@ struct inv_mpu6050_hw {
  *  @it_timestamp:	timestamp from previous interrupt.
  *  @data_timestamp:	timestamp for next data sample.
  *  @vddio_supply	voltage regulator for the chip.
+ *  @magn_raw_to_gauss:	coefficient to convert mag raw value to Gauss.
  */
 struct inv_mpu6050_state {
 	struct mutex lock;
@@ -150,6 +151,9 @@ struct inv_mpu6050_state {
 	s64 it_timestamp;
 	s64 data_timestamp;
 	struct regulator *vddio_supply;
+#ifdef CONFIG_INV_MPU6050_MAGN
+	s32 magn_raw_to_gauss[3];
+#endif
 };
 
 /*register and associated bit definition*/
-- 
2.17.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 7/8] iio: imu: inv_mpu6050: add magnetometer support inside mpu driver
  2019-08-29 15:18 [PATCH 0/8] add magnetometer support for MPU925x Jean-Baptiste Maneyrol
                   ` (5 preceding siblings ...)
  2019-08-29 15:18 ` [PATCH 6/8] iio: imu: inv_mpu6050: add magnetometer implementation for MPU925x Jean-Baptiste Maneyrol
@ 2019-08-29 15:18 ` Jean-Baptiste Maneyrol
  2019-09-08 12:05   ` Jonathan Cameron
  2019-08-29 15:18 ` [PATCH 8/8] iio: imu: inv_mpu6050: add fifo support for magnetometer data Jean-Baptiste Maneyrol
  2019-09-08 11:42 ` [PATCH 0/8] add magnetometer support for MPU925x Jonathan Cameron
  8 siblings, 1 reply; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-08-29 15:18 UTC (permalink / raw)
  To: jic23; +Cc: linux-iio, Jean-Baptiste Maneyrol

Add inv_mpu_magn layer to manage several chip specific
implementations and be noop when Kconfig option is not set.

Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
 drivers/iio/imu/inv_mpu6050/Makefile       |   3 +-
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 140 ++++++++++++++++++++-
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h  |   2 +
 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c | 120 ++++++++++++++++++
 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h | 107 ++++++++++++++++
 5 files changed, 368 insertions(+), 4 deletions(-)
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
 create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h

diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile
index fee41415ebdb..6f5baac29f81 100644
--- a/drivers/iio/imu/inv_mpu6050/Makefile
+++ b/drivers/iio/imu/inv_mpu6050/Makefile
@@ -5,7 +5,8 @@
 
 obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
 inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
-inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o inv_mpu9250_magn.o
+inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o inv_mpu_magn.o \
+	inv_mpu9250_magn.o
 
 obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o
 inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index b17f060b52fc..d08cec6a8a7a 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -16,7 +16,9 @@
 #include <linux/acpi.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+
 #include "inv_mpu_iio.h"
+#include "inv_mpu_magn.h"
 
 /*
  * this is the gyro scale translated from dynamic range plus/minus
@@ -332,6 +334,11 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
 	 */
 	st->chip_period = NSEC_PER_MSEC;
 
+	/* magn chip init, noop if not present in the chip */
+	result = inv_mpu_magn_probe(st);
+	if (result)
+		goto error_power_off;
+
 	return inv_mpu6050_set_power_itg(st, false);
 
 error_power_off:
@@ -411,6 +418,9 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
 		ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
 					      IIO_MOD_X, val);
 		break;
+	case IIO_MAGN:
+		ret = inv_mpu_magn_read(st, chan->channel2, val);
+		break;
 	default:
 		ret = -EINVAL;
 		break;
@@ -469,6 +479,8 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
 				*val2 = INV_MPU6050_TEMP_SCALE;
 
 			return IIO_VAL_INT_PLUS_MICRO;
+		case IIO_MAGN:
+			return inv_mpu_magn_get_scale(st, chan, val, val2);
 		default:
 			return -EINVAL;
 		}
@@ -710,6 +722,11 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
 	if (result)
 		goto fifo_rate_fail_power_off;
 
+	/* update rate for magn, noop if not present in chip */
+	result = inv_mpu_magn_set_rate(st, fifo_rate);
+	if (result)
+		goto fifo_rate_fail_power_off;
+
 fifo_rate_fail_power_off:
 	result |= inv_mpu6050_set_power_itg(st, false);
 fifo_rate_fail_unlock:
@@ -795,8 +812,13 @@ inv_get_mount_matrix(const struct iio_dev *indio_dev,
 		     const struct iio_chan_spec *chan)
 {
 	struct inv_mpu6050_state *data = iio_priv(indio_dev);
+	const struct iio_mount_matrix *matrix = &data->orientation;
 
-	return &data->orientation;
+#ifdef CONFIG_INV_MPU6050_MAGN
+	if (chan->type == IIO_MAGN)
+		matrix = &data->magn_orient;
+#endif
+	return matrix;
 }
 
 static const struct iio_chan_spec_ext_info inv_ext_info[] = {
@@ -864,6 +886,102 @@ static const unsigned long inv_mpu_scan_masks[] = {
 	0,
 };
 
+#ifdef CONFIG_INV_MPU6050_MAGN
+
+#define INV_MPU9X50_MAGN_CHAN(_chan2, _bits, _index)			\
+	{								\
+		.type = IIO_MAGN,					\
+		.modified = 1,						\
+		.channel2 = _chan2,					\
+		.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) |	\
+				      BIT(IIO_CHAN_INFO_RAW),		\
+		.scan_index = _index,					\
+		.scan_type = {						\
+			.sign = 's',					\
+			.realbits = _bits,				\
+			.storagebits = 16,				\
+			.shift = 0,					\
+			.endianness = IIO_BE,				\
+		},							\
+		.ext_info = inv_ext_info,				\
+	}
+
+static const struct iio_chan_spec inv_mpu9250_channels[] = {
+	IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP),
+	/*
+	 * Note that temperature should only be via polled reading only,
+	 * not the final scan elements output.
+	 */
+	{
+		.type = IIO_TEMP,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
+				| BIT(IIO_CHAN_INFO_OFFSET)
+				| BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = -1,
+	},
+	INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU9X50_SCAN_GYRO_X),
+	INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU9X50_SCAN_GYRO_Y),
+	INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU9X50_SCAN_GYRO_Z),
+
+	INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU9X50_SCAN_ACCL_X),
+	INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU9X50_SCAN_ACCL_Y),
+	INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU9X50_SCAN_ACCL_Z),
+
+	/* Magnetometer resolution is 16 bits */
+	INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 16, INV_MPU9X50_SCAN_MAGN_X),
+	INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 16, INV_MPU9X50_SCAN_MAGN_Y),
+	INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 16, INV_MPU9X50_SCAN_MAGN_Z),
+};
+
+static const unsigned long inv_mpu9x50_scan_masks[] = {
+	/* 3-axis accel */
+	BIT(INV_MPU9X50_SCAN_ACCL_X)
+		| BIT(INV_MPU9X50_SCAN_ACCL_Y)
+		| BIT(INV_MPU9X50_SCAN_ACCL_Z),
+	/* 3-axis gyro */
+	BIT(INV_MPU9X50_SCAN_GYRO_X)
+		| BIT(INV_MPU9X50_SCAN_GYRO_Y)
+		| BIT(INV_MPU9X50_SCAN_GYRO_Z),
+	/* 3-axis magn */
+	BIT(INV_MPU9X50_SCAN_MAGN_X)
+		| BIT(INV_MPU9X50_SCAN_MAGN_Y)
+		| BIT(INV_MPU9X50_SCAN_MAGN_Z),
+	/* 6-axis accel + gyro */
+	BIT(INV_MPU9X50_SCAN_ACCL_X)
+		| BIT(INV_MPU9X50_SCAN_ACCL_Y)
+		| BIT(INV_MPU9X50_SCAN_ACCL_Z)
+		| BIT(INV_MPU9X50_SCAN_GYRO_X)
+		| BIT(INV_MPU9X50_SCAN_GYRO_Y)
+		| BIT(INV_MPU9X50_SCAN_GYRO_Z),
+	/* 6-axis accel + magn */
+	BIT(INV_MPU9X50_SCAN_ACCL_X)
+		| BIT(INV_MPU9X50_SCAN_ACCL_Y)
+		| BIT(INV_MPU9X50_SCAN_ACCL_Z)
+		| BIT(INV_MPU9X50_SCAN_MAGN_X)
+		| BIT(INV_MPU9X50_SCAN_MAGN_Y)
+		| BIT(INV_MPU9X50_SCAN_MAGN_Z),
+	/* 6-axis gyro + magn */
+	BIT(INV_MPU9X50_SCAN_GYRO_X)
+		| BIT(INV_MPU9X50_SCAN_GYRO_Y)
+		| BIT(INV_MPU9X50_SCAN_GYRO_Z)
+		| BIT(INV_MPU9X50_SCAN_MAGN_X)
+		| BIT(INV_MPU9X50_SCAN_MAGN_Y)
+		| BIT(INV_MPU9X50_SCAN_MAGN_Z),
+	/* 9-axis accel + gyro + magn */
+	BIT(INV_MPU9X50_SCAN_ACCL_X)
+		| BIT(INV_MPU9X50_SCAN_ACCL_Y)
+		| BIT(INV_MPU9X50_SCAN_ACCL_Z)
+		| BIT(INV_MPU9X50_SCAN_GYRO_X)
+		| BIT(INV_MPU9X50_SCAN_GYRO_Y)
+		| BIT(INV_MPU9X50_SCAN_GYRO_Z)
+		| BIT(INV_MPU9X50_SCAN_MAGN_X)
+		| BIT(INV_MPU9X50_SCAN_MAGN_Y)
+		| BIT(INV_MPU9X50_SCAN_MAGN_Z),
+	0,
+};
+
+#endif
+
 static const struct iio_chan_spec inv_icm20602_channels[] = {
 	IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP),
 	{
@@ -1145,6 +1263,11 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
 		return result;
 	}
 
+	/* fill magnetometer orientation */
+	result = inv_mpu_magn_set_orient(st);
+	if (result)
+		return result;
+
 	/* power is turned on inside check chip type*/
 	result = inv_check_and_setup_chip(st);
 	if (result)
@@ -1167,14 +1290,25 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
 	else
 		indio_dev->name = dev_name(dev);
 
-	if (chip_type == INV_ICM20602) {
+	switch (chip_type) {
+#ifdef CONFIG_INV_MPU6050_MAGN
+	case INV_MPU9250:
+	case INV_MPU9255:
+		indio_dev->channels = inv_mpu9250_channels;
+		indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
+		indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
+		break;
+#endif
+	case INV_ICM20602:
 		indio_dev->channels = inv_icm20602_channels;
 		indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels);
 		indio_dev->available_scan_masks = inv_icm20602_scan_masks;
-	} else {
+		break;
+	default:
 		indio_dev->channels = inv_mpu_channels;
 		indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
 		indio_dev->available_scan_masks = inv_mpu_scan_masks;
+		break;
 	}
 
 	indio_dev->info = &mpu_info;
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index 5b462672bbcb..cfc11cb0a36c 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -130,6 +130,7 @@ struct inv_mpu6050_hw {
  *  @data_timestamp:	timestamp for next data sample.
  *  @vddio_supply	voltage regulator for the chip.
  *  @magn_raw_to_gauss:	coefficient to convert mag raw value to Gauss.
+ *  @magn_orient:	magnetometer sensor chip orientation if available.
  */
 struct inv_mpu6050_state {
 	struct mutex lock;
@@ -153,6 +154,7 @@ struct inv_mpu6050_state {
 	struct regulator *vddio_supply;
 #ifdef CONFIG_INV_MPU6050_MAGN
 	s32 magn_raw_to_gauss[3];
+	struct iio_mount_matrix magn_orient;
 #endif
 };
 
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
new file mode 100644
index 000000000000..2bb40dae0429
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 TDK-InvenSense, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/string.h>
+
+#include "inv_mpu_iio.h"
+#include "inv_mpu_aux.h"
+#include "inv_mpu9250_magn.h"
+
+int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
+{
+	int ret;
+
+	/* probe and init mag chip */
+	switch (st->chip_type) {
+	case INV_MPU9250:
+	case INV_MPU9255:
+		/* configure i2c master aux port */
+		ret = inv_mpu_aux_init(st);
+		if (ret)
+			return ret;
+		return inv_mpu9250_magn_probe(st);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate)
+{
+	int max_freq;
+	uint8_t d;
+
+	switch (st->chip_type) {
+	case INV_MPU9250:
+	case INV_MPU9255:
+		max_freq = INV_MPU9250_MAGN_FREQ_HZ_MAX;
+		break;
+	default:
+		return 0;
+	}
+
+	/*
+	 * update i2c master delay to limit mag sampling to max frequency
+	 * compute fifo_rate divider d: rate = fifo_rate / (d + 1)
+	 */
+	if (fifo_rate > max_freq)
+		d = fifo_rate / max_freq - 1;
+	else
+		d = 0;
+
+	return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, d);
+}
+
+int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
+{
+	const char *orient;
+	char *str;
+	int i;
+
+	/* fill magnetometer orientation */
+	switch (st->chip_type) {
+	case INV_MPU9250:
+	case INV_MPU9255:
+		/* x <- y */
+		st->magn_orient.rotation[0] = st->orientation.rotation[3];
+		st->magn_orient.rotation[1] = st->orientation.rotation[4];
+		st->magn_orient.rotation[2] = st->orientation.rotation[5];
+		/* y <- x */
+		st->magn_orient.rotation[3] = st->orientation.rotation[0];
+		st->magn_orient.rotation[4] = st->orientation.rotation[1];
+		st->magn_orient.rotation[5] = st->orientation.rotation[2];
+		/* z <- -z */
+		for (i = 0; i < 3; ++i) {
+			orient = st->orientation.rotation[6 + i];
+			/* use length + 2 for adding minus sign if needed */
+			str = devm_kzalloc(regmap_get_device(st->map),
+					   strlen(orient) + 2, GFP_KERNEL);
+			if (str == NULL)
+				return -ENOMEM;
+			if (strcmp(orient, "0") == 0) {
+				strcpy(str, orient);
+			} else if (orient[0] == '-') {
+				strcpy(str, &orient[1]);
+			} else {
+				str[0] = '-';
+				strcpy(&str[1], orient);
+			}
+			st->magn_orient.rotation[6 + i] = str;
+		}
+		break;
+	default:
+		st->magn_orient = st->orientation;
+		break;
+	}
+
+	return 0;
+}
+
+int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val)
+{
+	int ret;
+
+	switch (st->chip_type) {
+	case INV_MPU9250:
+	case INV_MPU9255:
+		ret = inv_mpu9250_magn_read(st, axis, val);
+		break;
+	default:
+		ret = -ENODEV;
+		break;
+	}
+
+	return ret;
+}
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h
new file mode 100644
index 000000000000..efa2ec1b3b2f
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 TDK-InvenSense, Inc.
+ */
+
+#ifndef INV_MPU_MAGN_H_
+#define INV_MPU_MAGN_H_
+
+#include <linux/kernel.h>
+
+#include "inv_mpu_iio.h"
+
+#ifdef CONFIG_INV_MPU6050_MAGN
+
+/**
+ * inv_mpu_magn_probe() - probe and setup magnetometer chip
+ * @st: driver internal state
+ *
+ * Returns 0 on success, a negative error code otherwise
+ *
+ * It is probing the chip and setting up all needed i2c transfers.
+ * Noop if there is no magnetometer in the chip.
+ */
+int inv_mpu_magn_probe(struct inv_mpu6050_state *st);
+
+/**
+ * inv_mpu_magn_get_scale() - get magnetometer scale value
+ * @st: driver internal state
+ *
+ * Returns IIO data format.
+ */
+static inline int inv_mpu_magn_get_scale(const struct inv_mpu6050_state *st,
+					 const struct iio_chan_spec *chan,
+					 int *val, int *val2)
+{
+	*val = 0;
+	*val2 = st->magn_raw_to_gauss[chan->address];
+	return IIO_VAL_INT_PLUS_MICRO;
+}
+
+/**
+ * inv_mpu_magn_set_rate() - set magnetometer sampling rate
+ * @st: driver internal state
+ * @fifo_rate: mpu set fifo rate
+ *
+ * Returns 0 on success, a negative error code otherwise
+ *
+ * Limit sampling frequency to the maximum value supported by the
+ * magnetometer chip. Resulting in duplicated data for higher frequencies.
+ * Noop if there is no magnetometer in the chip.
+ */
+int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate);
+
+/**
+ * inv_mpu_magn_set_orient() - fill magnetometer mounting matrix
+ * @st: driver internal state
+ *
+ * Returns 0 on success, a negative error code otherwise
+ *
+ * Fill magnetometer mounting matrix using the provided chip matrix.
+ */
+int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st);
+
+/**
+ * inv_mpu_magn_read() - read magnetometer data
+ * @st: driver internal state
+ * @axis: IIO modifier axis value
+ * @val: store corresponding axis value
+ *
+ * Returns 0 on success, a negative error code otherwise
+ */
+int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val);
+
+#else		/* CONFIG_INV_MPU6050_MAGN */
+
+static inline int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
+{
+	return 0;
+}
+
+static inline int inv_mpu_magn_get_scale(const struct inv_mpu6050_state *st,
+					 const struct iio_chan_spec *chan,
+					 int *val, int *val2)
+{
+	return -EINVAL;
+}
+
+static inline int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st,
+					int fifo_rate)
+{
+	return 0;
+}
+
+static inline int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
+{
+	return 0;
+}
+
+static inline int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis,
+				    int *val)
+{
+	return 0;
+}
+
+#endif		/* CONFIG_INV_MPU6050_MAGN */
+
+#endif		/* INV_MPU_MAGN_H_ */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 8/8] iio: imu: inv_mpu6050: add fifo support for magnetometer data
  2019-08-29 15:18 [PATCH 0/8] add magnetometer support for MPU925x Jean-Baptiste Maneyrol
                   ` (6 preceding siblings ...)
  2019-08-29 15:18 ` [PATCH 7/8] iio: imu: inv_mpu6050: add magnetometer support inside mpu driver Jean-Baptiste Maneyrol
@ 2019-08-29 15:18 ` Jean-Baptiste Maneyrol
  2019-09-08 12:07   ` Jonathan Cameron
  2019-09-08 11:42 ` [PATCH 0/8] add magnetometer support for MPU925x Jonathan Cameron
  8 siblings, 1 reply; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-08-29 15:18 UTC (permalink / raw)
  To: jic23; +Cc: linux-iio, Jean-Baptiste Maneyrol

Put read magnetometer data by mpu inside the fifo.

Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
 drivers/iio/imu/inv_mpu6050/inv_mpu_core.c    |  1 +
 drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |  2 +
 drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c    | 14 ++-
 drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 90 +++++++++++++++++--
 4 files changed, 94 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index d08cec6a8a7a..d4a321fd03a9 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -105,6 +105,7 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = {
 	.divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE),
 	.gyro_fifo_enable = false,
 	.accl_fifo_enable = false,
+	.magn_fifo_enable = false,
 	.accl_fs = INV_MPU6050_FS_02G,
 	.user_ctrl = 0,
 };
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index cfc11cb0a36c..48ed66e39cda 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -86,6 +86,7 @@ enum inv_devices {
  *  @accl_fs:		accel full scale range.
  *  @accl_fifo_enable:	enable accel data output
  *  @gyro_fifo_enable:	enable gyro data output
+ *  @magn_fifo_enable:	enable magn data output
  *  @divider:		chip sample rate divider (sample rate divider - 1)
  */
 struct inv_mpu6050_chip_config {
@@ -94,6 +95,7 @@ struct inv_mpu6050_chip_config {
 	unsigned int accl_fs:2;
 	unsigned int accl_fifo_enable:1;
 	unsigned int gyro_fifo_enable:1;
+	unsigned int magn_fifo_enable:1;
 	u8 divider;
 	u8 user_ctrl;
 };
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
index 5f9a5de0bab4..f0a5350c1848 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
@@ -14,6 +14,7 @@
 #include <linux/poll.h>
 #include <linux/math64.h>
 #include <asm/unaligned.h>
+
 #include "inv_mpu_iio.h"
 
 /**
@@ -124,7 +125,8 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
 
 	/* enable interrupt */
 	if (st->chip_config.accl_fifo_enable ||
-	    st->chip_config.gyro_fifo_enable) {
+	    st->chip_config.gyro_fifo_enable ||
+	    st->chip_config.magn_fifo_enable) {
 		result = regmap_write(st->map, st->reg->int_enable,
 				      INV_MPU6050_BIT_DATA_RDY_EN);
 		if (result)
@@ -141,6 +143,8 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
 		d |= INV_MPU6050_BITS_GYRO_OUT;
 	if (st->chip_config.accl_fifo_enable)
 		d |= INV_MPU6050_BIT_ACCEL_OUT;
+	if (st->chip_config.magn_fifo_enable)
+		d |= INV_MPU6050_BIT_SLAVE_0;
 	result = regmap_write(st->map, st->reg->fifo_en, d);
 	if (result)
 		goto reset_fifo_fail;
@@ -190,17 +194,19 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
 	}
 
 	if (!(st->chip_config.accl_fifo_enable |
-		st->chip_config.gyro_fifo_enable))
+		st->chip_config.gyro_fifo_enable |
+		st->chip_config.magn_fifo_enable))
 		goto end_session;
+
 	bytes_per_datum = 0;
 	if (st->chip_config.accl_fifo_enable)
 		bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
-
 	if (st->chip_config.gyro_fifo_enable)
 		bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
-
 	if (st->chip_type == INV_ICM20602)
 		bytes_per_datum += INV_ICM20602_BYTES_PER_TEMP_SENSOR;
+	if (st->chip_config.magn_fifo_enable)
+		bytes_per_datum += INV_MPU9X50_BYTES_MAGN;
 
 	/*
 	 * read fifo_count register to know how many bytes are inside the FIFO
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
index dd55e70b6f77..fa4928e589b9 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -5,7 +5,7 @@
 
 #include "inv_mpu_iio.h"
 
-static void inv_scan_query(struct iio_dev *indio_dev)
+static void inv_scan_query_mpu6050(struct iio_dev *indio_dev)
 {
 	struct inv_mpu6050_state  *st = iio_priv(indio_dev);
 
@@ -26,6 +26,52 @@ static void inv_scan_query(struct iio_dev *indio_dev)
 			 indio_dev->active_scan_mask);
 }
 
+#ifdef CONFIG_INV_MPU6050_MAGN
+static void inv_scan_query_mpu9x50(struct iio_dev *indio_dev)
+{
+	struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+	st->chip_config.gyro_fifo_enable =
+		test_bit(INV_MPU9X50_SCAN_GYRO_X,
+			 indio_dev->active_scan_mask) ||
+		test_bit(INV_MPU9X50_SCAN_GYRO_Y,
+			 indio_dev->active_scan_mask) ||
+		test_bit(INV_MPU9X50_SCAN_GYRO_Z,
+			 indio_dev->active_scan_mask);
+
+	st->chip_config.accl_fifo_enable =
+		test_bit(INV_MPU9X50_SCAN_ACCL_X,
+			 indio_dev->active_scan_mask) ||
+		test_bit(INV_MPU9X50_SCAN_ACCL_Y,
+			 indio_dev->active_scan_mask) ||
+		test_bit(INV_MPU9X50_SCAN_ACCL_Z,
+			 indio_dev->active_scan_mask);
+
+	st->chip_config.magn_fifo_enable =
+		test_bit(INV_MPU9X50_SCAN_MAGN_X,
+			 indio_dev->active_scan_mask) ||
+		test_bit(INV_MPU9X50_SCAN_MAGN_Y,
+			 indio_dev->active_scan_mask) ||
+		test_bit(INV_MPU9X50_SCAN_MAGN_Z,
+			 indio_dev->active_scan_mask);
+}
+#endif
+
+static void inv_scan_query(struct iio_dev *indio_dev)
+{
+	struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+	switch (st->chip_type) {
+#ifdef CONFIG_INV_MPU6050_MAGN
+	case INV_MPU9250:
+	case INV_MPU9255:
+		return inv_scan_query_mpu9x50(indio_dev);
+#endif
+	default:
+		return inv_scan_query_mpu6050(indio_dev);
+	}
+}
+
 /**
  *  inv_mpu6050_set_enable() - enable chip functions.
  *  @indio_dev:	Device driver instance.
@@ -34,6 +80,11 @@ static void inv_scan_query(struct iio_dev *indio_dev)
 static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
 {
 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
+	uint8_t d;
+	unsigned int gyro_skip = 0;
+	unsigned int accl_skip = 0;
+	unsigned int magn_skip = 0;
+	unsigned int skip_samples;
 	int result;
 
 	if (enable) {
@@ -41,14 +92,13 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
 		if (result)
 			return result;
 		inv_scan_query(indio_dev);
-		st->skip_samples = 0;
 		if (st->chip_config.gyro_fifo_enable) {
 			result = inv_mpu6050_switch_engine(st, true,
 					INV_MPU6050_BIT_PWR_GYRO_STBY);
 			if (result)
 				goto error_power_off;
 			/* gyro first sample is out of specs, skip it */
-			st->skip_samples = 1;
+			gyro_skip = 1;
 		}
 		if (st->chip_config.accl_fifo_enable) {
 			result = inv_mpu6050_switch_engine(st, true,
@@ -56,22 +106,40 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
 			if (result)
 				goto error_gyro_off;
 		}
+		if (st->chip_config.magn_fifo_enable) {
+			d = st->chip_config.user_ctrl |
+					INV_MPU6050_BIT_I2C_MST_EN;
+			result = regmap_write(st->map, st->reg->user_ctrl, d);
+			if (result)
+				goto error_accl_off;
+			st->chip_config.user_ctrl = d;
+			/* mag first sample is always not ready, skip it */
+			magn_skip = 1;
+		}
+		/* compute first samples to skip */
+		skip_samples = gyro_skip;
+		if (accl_skip > skip_samples)
+			skip_samples = accl_skip;
+		if (magn_skip > skip_samples)
+			skip_samples = magn_skip;
+		st->skip_samples = skip_samples;
 		result = inv_reset_fifo(indio_dev);
 		if (result)
-			goto error_accl_off;
+			goto error_magn_off;
 	} else {
 		result = regmap_write(st->map, st->reg->fifo_en, 0);
 		if (result)
-			goto error_accl_off;
+			goto error_magn_off;
 
 		result = regmap_write(st->map, st->reg->int_enable, 0);
 		if (result)
-			goto error_accl_off;
+			goto error_magn_off;
 
-		result = regmap_write(st->map, st->reg->user_ctrl,
-				      st->chip_config.user_ctrl);
+		d = st->chip_config.user_ctrl & ~INV_MPU6050_BIT_I2C_MST_EN;
+		result = regmap_write(st->map, st->reg->user_ctrl, d);
 		if (result)
-			goto error_accl_off;
+			goto error_magn_off;
+		st->chip_config.user_ctrl = d;
 
 		result = inv_mpu6050_switch_engine(st, false,
 					INV_MPU6050_BIT_PWR_ACCL_STBY);
@@ -90,6 +158,10 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
 
 	return 0;
 
+error_magn_off:
+	/* always restore user_ctrl to disable fifo properly */
+	st->chip_config.user_ctrl &= ~INV_MPU6050_BIT_I2C_MST_EN;
+	regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl);
 error_accl_off:
 	if (st->chip_config.accl_fifo_enable)
 		inv_mpu6050_switch_engine(st, false,
-- 
2.17.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/8] add magnetometer support for MPU925x
  2019-08-29 15:18 [PATCH 0/8] add magnetometer support for MPU925x Jean-Baptiste Maneyrol
                   ` (7 preceding siblings ...)
  2019-08-29 15:18 ` [PATCH 8/8] iio: imu: inv_mpu6050: add fifo support for magnetometer data Jean-Baptiste Maneyrol
@ 2019-09-08 11:42 ` Jonathan Cameron
  2019-09-09  9:55   ` Jean-Baptiste Maneyrol
  8 siblings, 1 reply; 17+ messages in thread
From: Jonathan Cameron @ 2019-09-08 11:42 UTC (permalink / raw)
  To: Jean-Baptiste Maneyrol; +Cc: linux-iio

On Thu, 29 Aug 2019 15:18:33 +0000
Jean-Baptiste Maneyrol <JManeyrol@invensense.com> wrote:

> This serie of patches adds support of magnetometer inside MPU925x chips.
> It is using the MPU i2c master to drive the integrated magnetometer and
> read data into the MPU FIFO.
> 
> Beware that this is disabling access to the i2c auxiliary bus. Since this
> can break existing setup, it is an optional feature requiring to enable
> the corresponding Kconfig option.

That's not great... People will fail to set that correctly for their
setup even if there is a 'correct' setting.

So we need more information to risk that breakage + discussions of
ways to avoid it.  Can we for example check if the auxiliary bus is
in use? (DT binding for example - check for the i2c-gate node?)

Jonathan

> 
> Jean-Baptiste Maneyrol (8):
>   iio: imu: inv_mpu6050: disable i2c mux for 925x under Kconfig
>   iio: imu: inv_mpu6050: add header include protection macro
>   iio: imu: inv_mpu6050: add defines for supporting 9-axis chips
>   iio: imu: inv_mpu6050: fix objects syntax in Makefile
>   iio: imu: inv_mpu6050: helpers for using i2c master on auxiliary bus
>   iio: imu: inv_mpu6050: add magnetometer implementation for MPU925x
>   iio: imu: inv_mpu6050: add magnetometer support inside mpu driver
>   iio: imu: inv_mpu6050: add fifo support for magnetometer data
> 
>  drivers/iio/imu/inv_mpu6050/Kconfig           |   9 +
>  drivers/iio/imu/inv_mpu6050/Makefile          |   8 +-
>  .../iio/imu/inv_mpu6050/inv_mpu9250_magn.c    | 239 ++++++++++++++++++
>  .../iio/imu/inv_mpu6050/inv_mpu9250_magn.h    |  27 ++
>  drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c     | 191 ++++++++++++++
>  drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h     |  46 ++++
>  drivers/iio/imu/inv_mpu6050/inv_mpu_core.c    | 141 ++++++++++-
>  drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c     |   5 +
>  drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |  79 +++++-
>  drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c    | 120 +++++++++
>  drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h    | 107 ++++++++
>  drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c    |  14 +-
>  drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c |  90 ++++++-
>  13 files changed, 1055 insertions(+), 21 deletions(-)
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h
> 


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 6/8] iio: imu: inv_mpu6050: add magnetometer implementation for MPU925x
  2019-08-29 15:18 ` [PATCH 6/8] iio: imu: inv_mpu6050: add magnetometer implementation for MPU925x Jean-Baptiste Maneyrol
@ 2019-09-08 11:57   ` Jonathan Cameron
  0 siblings, 0 replies; 17+ messages in thread
From: Jonathan Cameron @ 2019-09-08 11:57 UTC (permalink / raw)
  To: Jean-Baptiste Maneyrol; +Cc: linux-iio

On Thu, 29 Aug 2019 15:18:43 +0000
Jean-Baptiste Maneyrol <JManeyrol@invensense.com> wrote:

> Add implementation for driving MPU9250 magnetometer connected on
> i2c auxiliary bus using the MPU i2c master. This is currently not
> wired inside the main mpu driver.
> 
> Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>

A few comments inline. 

Thanks,

Jonathan

> ---
>  drivers/iio/imu/inv_mpu6050/Makefile          |   2 +-
>  .../iio/imu/inv_mpu6050/inv_mpu9250_magn.c    | 239 ++++++++++++++++++
>  .../iio/imu/inv_mpu6050/inv_mpu9250_magn.h    |  27 ++
>  drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |   4 +
>  4 files changed, 271 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h
> 
> diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile
> index 187f003c81f2..fee41415ebdb 100644
> --- a/drivers/iio/imu/inv_mpu6050/Makefile
> +++ b/drivers/iio/imu/inv_mpu6050/Makefile
> @@ -5,7 +5,7 @@
>  
>  obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
>  inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
> -inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o
> +inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o inv_mpu9250_magn.o
>  
>  obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o
>  inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c
> new file mode 100644
> index 000000000000..0c2230247557
> --- /dev/null
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c
> @@ -0,0 +1,239 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2019 TDK-InvenSense, Inc.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/regmap.h>
> +#include <linux/delay.h>
> +#include <linux/string.h>
> +#include <asm/unaligned.h>
> +
> +#include "inv_mpu_iio.h"
> +#include "inv_mpu_aux.h"
> +#include "inv_mpu9250_magn.h"
> +
> +/*
> + * MPU9250 magnetometer is an AKM AK8963 chip on I2C aux bus
> + */
> +#define INV_MPU9250_MAGN_I2C_ADDR		0x0C
> +
> +#define INV_MPU9250_MAGN_REG_WIA		0x00
> +#define INV_MPU9250_MAGN_BITS_WIA		0x48
> +
> +#define INV_MPU9250_MAGN_REG_ST1		0x02
> +#define INV_MPU9250_MAGN_BIT_DRDY		0x01
> +#define INV_MPU9250_MAGN_BIT_DOR		0x02
> +
> +#define INV_MPU9250_MAGN_REG_DATA		0x03
> +
> +#define INV_MPU9250_MAGN_REG_ST2		0x09
> +#define INV_MPU9250_MAGN_BIT_HOFL		0x08
> +#define INV_MPU9250_MAGN_BIT_BITM		0x10
> +
> +#define INV_MPU9250_MAGN_REG_CNTL1		0x0A
> +#define INV_MPU9250_MAGN_BITS_MODE_PWDN		0x00
> +#define INV_MPU9250_MAGN_BITS_MODE_SINGLE	0x01
> +#define INV_MPU9250_MAGN_BITS_MODE_FUSE		0x0F
> +#define INV_MPU9250_MAGN_BIT_OUTPUT_BIT		0x10
> +
> +#define INV_MPU9250_MAGN_REG_CNTL2		0x0B
> +#define INV_MPU9250_MAGN_BIT_SRST		0x01
> +
> +#define INV_MPU9250_MAGN_REG_ASAX		0x10
> +#define INV_MPU9250_MAGN_REG_ASAY		0x11
> +#define INV_MPU9250_MAGN_REG_ASAZ		0x12
> +
> +/* init magnetometer chip */
> +static int inv_magn_init(struct inv_mpu6050_state *st)
> +{
> +	uint8_t val;
> +	uint8_t asa[3];
> +	int ret;
> +
> +	/* check whoami */
> +	ret = inv_mpu_aux_read(st, INV_MPU9250_MAGN_I2C_ADDR,
> +			       INV_MPU9250_MAGN_REG_WIA, &val, sizeof(val));
> +	if (ret)
> +		return ret;
> +	if (val != INV_MPU9250_MAGN_BITS_WIA)
> +		return -ENODEV;
> +
> +	/* reset chip */
> +	ret = inv_mpu_aux_write(st, INV_MPU9250_MAGN_I2C_ADDR,
> +				INV_MPU9250_MAGN_REG_CNTL2,
> +				INV_MPU9250_MAGN_BIT_SRST);
> +	if (ret)
> +		return ret;
> +
> +	/* read fuse ROM data */
> +	ret = inv_mpu_aux_write(st, INV_MPU9250_MAGN_I2C_ADDR,
> +				INV_MPU9250_MAGN_REG_CNTL1,
> +				INV_MPU9250_MAGN_BITS_MODE_FUSE);
> +	if (ret)
> +		return ret;
> +	ret = inv_mpu_aux_read(st, INV_MPU9250_MAGN_I2C_ADDR,
> +			       INV_MPU9250_MAGN_REG_ASAX, asa, sizeof(asa));
> +	if (ret)
> +		return ret;
> +
> +	/* switch back to power-down */
> +	ret = inv_mpu_aux_write(st, INV_MPU9250_MAGN_I2C_ADDR,
> +				INV_MPU9250_MAGN_REG_CNTL1,
> +				INV_MPU9250_MAGN_BITS_MODE_PWDN);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * Sensitivity adjustement and scale to Gauss
> +	 *
> +	 * Hadj = H * (((ASA - 128) * 0.5 / 128) + 1)
> +	 * Factor simplification:
> +	 * Hadj = H * ((ASA + 128) / 256)
> +	 *
> +	 * sensor sensitivity: 0.15 uT (16 bits)
> +	 * 1 uT = 0.01 G and value is in micron (1e6)
> +	 *
> +	 * Hadj = H * ((ASA + 128) / 256) * 0.15 * 0.01 * 1e6
> +	 * Hadj = H * ((ASA + 128) / 256) * 1500
> +	 */
> +	st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * 1500) / 256;
> +	st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * 1500) / 256;
> +	st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * 1500) / 256;
> +
> +	return 0;
> +}
> +
> +/**
> + * Probe magnetometer chip and setup all i2c transfers.
> + * SLV0: read sensor data
> + * SLV1: launch sensor single measurement
> + *
> + * Sampling data requires 2 cycles to read after measurement.
> + * A measurement can take up to ~10ms.
> + */
> +int inv_mpu9250_magn_probe(struct inv_mpu6050_state *st)
> +{
> +	int ret;
> +
> +	/* check and init mag chip */
> +	ret = inv_magn_init(st);
> +	if (ret)
> +		return ret;
> +
> +	/*
> +	 * configure mpu i2c master accesses
> +	 * i2c SLV0: read sensor data, 7 bytes data(6)-ST2
> +	 * Byte swap data to store them in big-endian in impair address groups
> +	 */
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0),
> +			   INV_MPU6050_BIT_I2C_SLV_RNW |
> +			   INV_MPU9250_MAGN_I2C_ADDR);
> +	if (ret)
> +		return ret;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0),
> +			   INV_MPU9250_MAGN_REG_DATA);
> +	if (ret)
> +		return ret;

blank lines in all these locations ideally.  See below.

> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
> +			   INV_MPU6050_BIT_SLV_EN |
> +			   INV_MPU6050_BIT_SLV_BYTE_SW |
> +			   INV_MPU6050_BIT_SLV_GRP |
> +			   INV_MPU9X50_BYTES_MAGN);
> +	if (ret)
> +		return ret;
> +
> +	/* i2c SLV1: launch single measurement */
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(1),
> +			   INV_MPU9250_MAGN_I2C_ADDR);
> +	if (ret)
> +		return ret;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(1),
> +			   INV_MPU9250_MAGN_REG_CNTL1);
> +	if (ret)
> +		return ret;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1),
> +			   INV_MPU9250_MAGN_BITS_MODE_SINGLE |
> +			   INV_MPU9250_MAGN_BIT_OUTPUT_BIT);
> +	if (ret)
> +		return ret;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(1),
> +			   INV_MPU6050_BIT_SLV_EN | 1);
> +	if (ret)
> +		return ret;
> +
return regmap_write....

Check for others of these in the rest of the patches.

> +	return 0;
> +}
> +
> +/**
> + * Read magnetometer data from MPU fifo.
> + * Sampling data requires running the i2c master for 2 cycles.
> + * Use magnetometer maximal supported frequency.
> + */
> +int inv_mpu9250_magn_read(const struct inv_mpu6050_state *st, int axis,
> +			  int *val)
> +{
> +	unsigned int user_ctrl, status;
> +	__be16 data[3];
> +	uint8_t addr;
> +	uint8_t d;
> +	unsigned int period_ms;
> +	int ret;
> +
> +	/* Mag data: X - Y - Z */
> +	switch (axis) {
> +	case IIO_MOD_X:
> +		addr = 0;
> +		break;
> +	case IIO_MOD_Y:
> +		addr = 1;
> +		break;
> +	case IIO_MOD_Z:
> +		addr = 2;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	/* set sample rate to max mag freq */
> +	d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU9250_MAGN_FREQ_HZ_MAX);
> +	ret = regmap_write(st->map, st->reg->sample_rate_div, d);
> +	if (ret)
> +		return ret;
> +
> +	/* start i2c master, wait for xfer, stop */
> +	user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN;
> +	ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
> +	if (ret)
> +		return ret;
blank line.

> +	/* need to wait 2 periods + half-period margin */
> +	period_ms = 1000 / INV_MPU9250_MAGN_FREQ_HZ_MAX;
> +	msleep(period_ms * 2 + period_ms / 2);
> +	user_ctrl = st->chip_config.user_ctrl;
> +	ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
> +	if (ret)
> +		return ret;
> +
> +	/* restore sample rate */
> +	d = st->chip_config.divider;
> +	ret = regmap_write(st->map, st->reg->sample_rate_div, d);
> +	if (ret)
> +		return ret;
> +
> +	/* check i2c status and read raw data */
> +	ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
> +	if (ret)
> +		return ret;

Blank line.

> +	if (status & INV_MPU6050_BIT_I2C_SLV0_NACK ||
> +			status & INV_MPU6050_BIT_I2C_SLV1_NACK)
> +		return -EIO;

Blank lines after error checks like this make the code a little
easier to read.

> +	ret = regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
> +			       data, sizeof(data));
> +	if (ret)
> +		return ret;
> +
> +	*val = (int16_t)be16_to_cpu(data[addr]);
> +
> +	return IIO_VAL_INT;
> +}
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h b/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h
> new file mode 100644
> index 000000000000..9899dd6c560c
> --- /dev/null
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h
> @@ -0,0 +1,27 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2019 TDK-InvenSense, Inc.
> + */
> +
> +#ifndef INV_MPU9250_MAGN_H_
> +#define INV_MPU9250_MAGN_H_
> +
> +#include <linux/kernel.h>
> +
> +#include "inv_mpu_iio.h"
> +
> +/* Magnetometer maximum frequency */
> +#define INV_MPU9250_MAGN_FREQ_HZ_MAX		50
> +
> +/**
> + * inv_mpu9250_magn_probe() - MPU9250 implementation
> + */
> +int inv_mpu9250_magn_probe(struct inv_mpu6050_state *st);
> +
> +/**
> + * inv_mpu9250_magn_read() - MPU9250 implementation

Documentation by implementation not in the header.  Also full documentation
of all parameters needed if you are going to use kernel-doc style

> + */
> +int inv_mpu9250_magn_read(const struct inv_mpu6050_state *st, int axis,
> +			  int *val);
> +
> +#endif
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> index 82669ecb4735..5b462672bbcb 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> @@ -129,6 +129,7 @@ struct inv_mpu6050_hw {
>   *  @it_timestamp:	timestamp from previous interrupt.
>   *  @data_timestamp:	timestamp for next data sample.
>   *  @vddio_supply	voltage regulator for the chip.
> + *  @magn_raw_to_gauss:	coefficient to convert mag raw value to Gauss.
>   */
>  struct inv_mpu6050_state {
>  	struct mutex lock;
> @@ -150,6 +151,9 @@ struct inv_mpu6050_state {
>  	s64 it_timestamp;
>  	s64 data_timestamp;
>  	struct regulator *vddio_supply;
> +#ifdef CONFIG_INV_MPU6050_MAGN
> +	s32 magn_raw_to_gauss[3];
> +#endif
>  };
>  
>  /*register and associated bit definition*/


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 5/8] iio: imu: inv_mpu6050: helpers for using i2c master on auxiliary bus
  2019-08-29 15:18 ` [PATCH 5/8] iio: imu: inv_mpu6050: helpers for using i2c master on auxiliary bus Jean-Baptiste Maneyrol
@ 2019-09-08 11:57   ` Jonathan Cameron
  0 siblings, 0 replies; 17+ messages in thread
From: Jonathan Cameron @ 2019-09-08 11:57 UTC (permalink / raw)
  To: Jean-Baptiste Maneyrol; +Cc: linux-iio

On Thu, 29 Aug 2019 15:18:42 +0000
Jean-Baptiste Maneyrol <JManeyrol@invensense.com> wrote:

> Add helper functions to use the i2c auxiliary bus with the MPU i2c
> master block.
> 
> Support only register based chip, reading and 1 byte writing. These
> will be useful for initializing magnetometers inside MPU9x50 chips.
> 
> Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>

A few minor comments inline.

Always the fun question on whether we should support these sorts of
aux buses as true masters and register them as such, or whether it's
just not worth the effort as they are limited...

> ---
>  drivers/iio/imu/inv_mpu6050/Makefile      |   1 +
>  drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c | 191 ++++++++++++++++++++++
>  drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h |  46 ++++++
>  3 files changed, 238 insertions(+)
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h
> 
> diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile
> index 33bec09fee9b..187f003c81f2 100644
> --- a/drivers/iio/imu/inv_mpu6050/Makefile
> +++ b/drivers/iio/imu/inv_mpu6050/Makefile
> @@ -5,6 +5,7 @@
>  
>  obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
>  inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
> +inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o
>  
>  obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o
>  inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
> new file mode 100644
> index 000000000000..afb957567c12
> --- /dev/null
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c
> @@ -0,0 +1,191 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2019 TDK-InvenSense, Inc.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/regmap.h>
> +#include <linux/delay.h>
> +
> +#include "inv_mpu_iio.h"
> +
> +/*
> + * i2c master auxiliary bus transfer function.
> + * Requires the i2c operations to be correctly setup before.
> + */
> +static int inv_mpu_i2c_master_xfer(const struct inv_mpu6050_state *st)
> +{
> +	/* use 50hz frequency for xfer */
> +	const unsigned int freq = 50;
> +	const unsigned int period_ms = 1000 / freq;
> +	uint8_t d;
> +	unsigned int user_ctrl;
> +	int ret;
> +
> +	/* set sample rate */
> +	d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(freq);
> +	ret = regmap_write(st->map, st->reg->sample_rate_div, d);
> +	if (ret)
> +		return ret;
> +
> +	/* start i2c master */
> +	user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN;
> +	ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
> +	if (ret)
> +		goto error_restore_rate;
> +
> +	/* wait for xfer: 1 period + half-period margin */
> +	msleep(period_ms + period_ms / 2);
> +
> +	/* stop i2c master */
> +	user_ctrl = st->chip_config.user_ctrl;
> +	ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl);
> +	if (ret)
> +		goto error_stop_i2c;
> +
> +	/* restore sample rate */
> +	d = st->chip_config.divider;
> +	ret = regmap_write(st->map, st->reg->sample_rate_div, d);
> +	if (ret)
> +		goto error_restore_rate;
> +
> +	return 0;
> +
> +error_stop_i2c:
> +	regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl);
> +error_restore_rate:
> +	regmap_write(st->map, st->reg->sample_rate_div, st->chip_config.divider);
> +	return ret;
> +}
> +
> +int inv_mpu_aux_init(const struct inv_mpu6050_state *st)
> +{
> +	unsigned int val;
> +	int ret;
> +
> +	/* configure i2c master */
> +	val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ |
> +			INV_MPU6050_BIT_WAIT_FOR_ES;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_MST_CTRL, val);
> +	if (ret)
> +		return ret;
> +
> +	/* configure i2c master delay */
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, 0);
> +	if (ret)
> +		return ret;
> +	val = INV_MPU6050_BIT_I2C_SLV0_DLY_EN |
> +			INV_MPU6050_BIT_I2C_SLV1_DLY_EN |
> +			INV_MPU6050_BIT_I2C_SLV2_DLY_EN |
> +			INV_MPU6050_BIT_I2C_SLV3_DLY_EN |
> +			INV_MPU6050_BIT_DELAY_ES_SHADOW;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_MST_DELAY_CTRL, val);

return regmap_write...

> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +/*
> + * i2c slave reading using SLV0
> + */
> +int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr,
> +		     uint8_t reg, uint8_t *val, size_t size)
> +{
> +	unsigned int status;
> +	int ret;
> +
> +	if (size > 0x0F)
> +		return -EINVAL;
> +
> +	/* setup i2c SLV0 control: i2c addr, register, enable + size */
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0),
> +			   INV_MPU6050_BIT_I2C_SLV_RNW | addr);
> +	if (ret)
> +		return ret;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg);
> +	if (ret)
> +		return ret;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
> +			   INV_MPU6050_BIT_SLV_EN | size);
> +	if (ret)
> +		return ret;
> +
> +	/* do i2c xfer */
> +	ret = inv_mpu_i2c_master_xfer(st);
> +	if (ret)
> +		goto error_disable_i2c;
> +
> +	/* disable i2c slave */
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
> +	if (ret)
> +		goto error_disable_i2c;
> +
> +	/* check i2c status */
> +	ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
> +	if (ret)
> +		return ret;
> +	if (status & INV_MPU6050_BIT_I2C_SLV0_NACK)
> +		return -EIO;
> +
> +	/* read data in registers */
> +	ret = regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA,
> +			       val, size);

return regmap_...

> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +
> +error_disable_i2c:
> +	regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
> +	return ret;
> +}
> +
> +/*
> + * i2c slave writing 1 byte using SLV0
> + */
> +int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr,
> +		      uint8_t reg, uint8_t val)
> +{
> +	unsigned int status;
> +	int ret;
> +
> +	/* setup i2c SLV0 control: i2c addr, register, value, enable + size */
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0), addr);
> +	if (ret)
> +		return ret;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg);
> +	if (ret)
> +		return ret;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(0), val);
> +	if (ret)
> +		return ret;
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0),
> +			   INV_MPU6050_BIT_SLV_EN | 1);
> +	if (ret)
> +		return ret;
> +
> +	/* do i2c xfer */
> +	ret = inv_mpu_i2c_master_xfer(st);
> +	if (ret)
> +		goto error_disable_i2c;
> +
> +	/* disable i2c slave */
> +	ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
> +	if (ret)
> +		goto error_disable_i2c;
> +
> +	/* check i2c status */
> +	ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status);
> +	if (ret)
> +		return ret;
> +	if (status & INV_MPU6050_BIT_I2C_SLV0_NACK)
> +		return -EIO;
> +
> +	return 0;
> +
> +error_disable_i2c:
> +	regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0);
> +	return ret;
> +}
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h
> new file mode 100644
> index 000000000000..bae4eab58e6c
> --- /dev/null
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h
> @@ -0,0 +1,46 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2019 TDK-InvenSense, Inc.
> + */
> +
> +#ifndef INV_MPU_AUX_H_
> +#define INV_MPU_AUX_H_
> +
> +#include <linux/kernel.h>
> +
> +#include "inv_mpu_iio.h"
> +
> +/**
> + * inv_mpu_aux_init() - init i2c auxiliary bus
> + * @st: driver internal state
> + *
> + * Returns 0 on success, a negative error code otherwise.
> + */
> +int inv_mpu_aux_init(const struct inv_mpu6050_state *st);
> +
> +/**
> + * inv_mpu_aux_read() - read register function for i2c auxiliary bus
> + * @st: driver internal state.
> + * @addr: chip i2c Address
> + * @reg: chip register address
> + * @val: buffer for storing read bytes
> + * @size: number of bytes to read
> + *
> + *  Returns 0 on success, a negative error code otherwise.
> + */
> +int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr,
> +		     uint8_t reg, uint8_t *val, size_t size);
> +
> +/**
> + * inv_mpu_aux_write() - write register function for i2c auxiliary bus
> + * @st: driver internal state.
> + * @addr: chip i2c Address
> + * @reg: chip register address
> + * @val: 1 byte value to write
> + *
> + *  Returns 0 on success, a negative error code otherwise.
> + */
> +int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr,
> +		      uint8_t reg, uint8_t val);
> +
> +#endif		/* INV_MPU_AUX_H_ */


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 7/8] iio: imu: inv_mpu6050: add magnetometer support inside mpu driver
  2019-08-29 15:18 ` [PATCH 7/8] iio: imu: inv_mpu6050: add magnetometer support inside mpu driver Jean-Baptiste Maneyrol
@ 2019-09-08 12:05   ` Jonathan Cameron
  2019-09-09 16:18     ` Jean-Baptiste Maneyrol
  0 siblings, 1 reply; 17+ messages in thread
From: Jonathan Cameron @ 2019-09-08 12:05 UTC (permalink / raw)
  To: Jean-Baptiste Maneyrol; +Cc: linux-iio

On Thu, 29 Aug 2019 15:18:45 +0000
Jean-Baptiste Maneyrol <JManeyrol@invensense.com> wrote:

> Add inv_mpu_magn layer to manage several chip specific
> implementations and be noop when Kconfig option is not set.
> 
> Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>

A few minor bits inline.

Thanks,

Jonathan

> ---
>  drivers/iio/imu/inv_mpu6050/Makefile       |   3 +-
>  drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 140 ++++++++++++++++++++-
>  drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h  |   2 +
>  drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c | 120 ++++++++++++++++++
>  drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h | 107 ++++++++++++++++
>  5 files changed, 368 insertions(+), 4 deletions(-)
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h
> 
> diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile
> index fee41415ebdb..6f5baac29f81 100644
> --- a/drivers/iio/imu/inv_mpu6050/Makefile
> +++ b/drivers/iio/imu/inv_mpu6050/Makefile
> @@ -5,7 +5,8 @@
>  
>  obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
>  inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
> -inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o inv_mpu9250_magn.o
> +inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o inv_mpu_magn.o \
> +	inv_mpu9250_magn.o
>  
>  obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o
>  inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> index b17f060b52fc..d08cec6a8a7a 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> @@ -16,7 +16,9 @@
>  #include <linux/acpi.h>
>  #include <linux/platform_device.h>
>  #include <linux/regulator/consumer.h>
> +
>  #include "inv_mpu_iio.h"
> +#include "inv_mpu_magn.h"
>  
>  /*
>   * this is the gyro scale translated from dynamic range plus/minus
> @@ -332,6 +334,11 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
>  	 */
>  	st->chip_period = NSEC_PER_MSEC;
>  
> +	/* magn chip init, noop if not present in the chip */
> +	result = inv_mpu_magn_probe(st);
> +	if (result)
> +		goto error_power_off;
> +
>  	return inv_mpu6050_set_power_itg(st, false);
>  
>  error_power_off:
> @@ -411,6 +418,9 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
>  		ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
>  					      IIO_MOD_X, val);
>  		break;
> +	case IIO_MAGN:
> +		ret = inv_mpu_magn_read(st, chan->channel2, val);
> +		break;
>  	default:
>  		ret = -EINVAL;
>  		break;
> @@ -469,6 +479,8 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
>  				*val2 = INV_MPU6050_TEMP_SCALE;
>  
>  			return IIO_VAL_INT_PLUS_MICRO;
> +		case IIO_MAGN:
> +			return inv_mpu_magn_get_scale(st, chan, val, val2);
>  		default:
>  			return -EINVAL;
>  		}
> @@ -710,6 +722,11 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
>  	if (result)
>  		goto fifo_rate_fail_power_off;
>  
> +	/* update rate for magn, noop if not present in chip */
> +	result = inv_mpu_magn_set_rate(st, fifo_rate);
> +	if (result)
> +		goto fifo_rate_fail_power_off;
> +
>  fifo_rate_fail_power_off:
>  	result |= inv_mpu6050_set_power_itg(st, false);
>  fifo_rate_fail_unlock:
> @@ -795,8 +812,13 @@ inv_get_mount_matrix(const struct iio_dev *indio_dev,
>  		     const struct iio_chan_spec *chan)
>  {
>  	struct inv_mpu6050_state *data = iio_priv(indio_dev);
> +	const struct iio_mount_matrix *matrix = &data->orientation;
>  
> -	return &data->orientation;
> +#ifdef CONFIG_INV_MPU6050_MAGN
> +	if (chan->type == IIO_MAGN)
> +		matrix = &data->magn_orient;
> +#endif
> +	return matrix;
>  }
>  
>  static const struct iio_chan_spec_ext_info inv_ext_info[] = {
> @@ -864,6 +886,102 @@ static const unsigned long inv_mpu_scan_masks[] = {
>  	0,
>  };
>  
> +#ifdef CONFIG_INV_MPU6050_MAGN
> +
> +#define INV_MPU9X50_MAGN_CHAN(_chan2, _bits, _index)			\
> +	{								\
> +		.type = IIO_MAGN,					\
> +		.modified = 1,						\
> +		.channel2 = _chan2,					\
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) |	\
> +				      BIT(IIO_CHAN_INFO_RAW),		\
> +		.scan_index = _index,					\
> +		.scan_type = {						\
> +			.sign = 's',					\
> +			.realbits = _bits,				\
> +			.storagebits = 16,				\
> +			.shift = 0,					\
> +			.endianness = IIO_BE,				\
> +		},							\
> +		.ext_info = inv_ext_info,				\
> +	}
> +
> +static const struct iio_chan_spec inv_mpu9250_channels[] = {
> +	IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP),
> +	/*
> +	 * Note that temperature should only be via polled reading only,
> +	 * not the final scan elements output.
> +	 */
> +	{
> +		.type = IIO_TEMP,
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
> +				| BIT(IIO_CHAN_INFO_OFFSET)
> +				| BIT(IIO_CHAN_INFO_SCALE),
> +		.scan_index = -1,
> +	},
> +	INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU9X50_SCAN_GYRO_X),
> +	INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU9X50_SCAN_GYRO_Y),
> +	INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU9X50_SCAN_GYRO_Z),
> +
> +	INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU9X50_SCAN_ACCL_X),
> +	INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU9X50_SCAN_ACCL_Y),
> +	INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU9X50_SCAN_ACCL_Z),
> +
> +	/* Magnetometer resolution is 16 bits */
> +	INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 16, INV_MPU9X50_SCAN_MAGN_X),
> +	INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 16, INV_MPU9X50_SCAN_MAGN_Y),
> +	INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 16, INV_MPU9X50_SCAN_MAGN_Z),
> +};
> +
> +static const unsigned long inv_mpu9x50_scan_masks[] = {
> +	/* 3-axis accel */
> +	BIT(INV_MPU9X50_SCAN_ACCL_X)
> +		| BIT(INV_MPU9X50_SCAN_ACCL_Y)
> +		| BIT(INV_MPU9X50_SCAN_ACCL_Z),
> +	/* 3-axis gyro */
> +	BIT(INV_MPU9X50_SCAN_GYRO_X)
> +		| BIT(INV_MPU9X50_SCAN_GYRO_Y)
> +		| BIT(INV_MPU9X50_SCAN_GYRO_Z),
> +	/* 3-axis magn */
> +	BIT(INV_MPU9X50_SCAN_MAGN_X)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_Y)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_Z),
> +	/* 6-axis accel + gyro */
> +	BIT(INV_MPU9X50_SCAN_ACCL_X)
> +		| BIT(INV_MPU9X50_SCAN_ACCL_Y)
> +		| BIT(INV_MPU9X50_SCAN_ACCL_Z)
> +		| BIT(INV_MPU9X50_SCAN_GYRO_X)
> +		| BIT(INV_MPU9X50_SCAN_GYRO_Y)
> +		| BIT(INV_MPU9X50_SCAN_GYRO_Z),
> +	/* 6-axis accel + magn */
> +	BIT(INV_MPU9X50_SCAN_ACCL_X)
> +		| BIT(INV_MPU9X50_SCAN_ACCL_Y)
> +		| BIT(INV_MPU9X50_SCAN_ACCL_Z)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_X)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_Y)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_Z),
> +	/* 6-axis gyro + magn */
> +	BIT(INV_MPU9X50_SCAN_GYRO_X)
> +		| BIT(INV_MPU9X50_SCAN_GYRO_Y)
> +		| BIT(INV_MPU9X50_SCAN_GYRO_Z)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_X)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_Y)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_Z),
> +	/* 9-axis accel + gyro + magn */
> +	BIT(INV_MPU9X50_SCAN_ACCL_X)
> +		| BIT(INV_MPU9X50_SCAN_ACCL_Y)
> +		| BIT(INV_MPU9X50_SCAN_ACCL_Z)
> +		| BIT(INV_MPU9X50_SCAN_GYRO_X)
> +		| BIT(INV_MPU9X50_SCAN_GYRO_Y)
> +		| BIT(INV_MPU9X50_SCAN_GYRO_Z)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_X)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_Y)
> +		| BIT(INV_MPU9X50_SCAN_MAGN_Z),
> +	0,
> +};
> +
> +#endif
> +
>  static const struct iio_chan_spec inv_icm20602_channels[] = {
>  	IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP),
>  	{
> @@ -1145,6 +1263,11 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
>  		return result;
>  	}
>  
> +	/* fill magnetometer orientation */
> +	result = inv_mpu_magn_set_orient(st);
> +	if (result)
> +		return result;
> +
>  	/* power is turned on inside check chip type*/
>  	result = inv_check_and_setup_chip(st);
>  	if (result)
> @@ -1167,14 +1290,25 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
>  	else
>  		indio_dev->name = dev_name(dev);
>  
> -	if (chip_type == INV_ICM20602) {
> +	switch (chip_type) {
> +#ifdef CONFIG_INV_MPU6050_MAGN
> +	case INV_MPU9250:
> +	case INV_MPU9255:
> +		indio_dev->channels = inv_mpu9250_channels;
> +		indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
> +		indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
> +		break;
> +#endif
> +	case INV_ICM20602:
>  		indio_dev->channels = inv_icm20602_channels;
>  		indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels);
>  		indio_dev->available_scan_masks = inv_icm20602_scan_masks;
> -	} else {
> +		break;
> +	default:
>  		indio_dev->channels = inv_mpu_channels;
>  		indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
>  		indio_dev->available_scan_masks = inv_mpu_scan_masks;
> +		break;
>  	}
>  
>  	indio_dev->info = &mpu_info;
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> index 5b462672bbcb..cfc11cb0a36c 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> @@ -130,6 +130,7 @@ struct inv_mpu6050_hw {
>   *  @data_timestamp:	timestamp for next data sample.
>   *  @vddio_supply	voltage regulator for the chip.
>   *  @magn_raw_to_gauss:	coefficient to convert mag raw value to Gauss.
> + *  @magn_orient:	magnetometer sensor chip orientation if available.
>   */
>  struct inv_mpu6050_state {
>  	struct mutex lock;
> @@ -153,6 +154,7 @@ struct inv_mpu6050_state {
>  	struct regulator *vddio_supply;
>  #ifdef CONFIG_INV_MPU6050_MAGN
>  	s32 magn_raw_to_gauss[3];
> +	struct iio_mount_matrix magn_orient;
>  #endif
>  };
>  
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
> new file mode 100644
> index 000000000000..2bb40dae0429
> --- /dev/null
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c
> @@ -0,0 +1,120 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2019 TDK-InvenSense, Inc.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/string.h>
> +
> +#include "inv_mpu_iio.h"
> +#include "inv_mpu_aux.h"
> +#include "inv_mpu9250_magn.h"
> +
> +int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
> +{
> +	int ret;
> +
> +	/* probe and init mag chip */
> +	switch (st->chip_type) {
> +	case INV_MPU9250:
> +	case INV_MPU9255:
> +		/* configure i2c master aux port */
> +		ret = inv_mpu_aux_init(st);
> +		if (ret)
> +			return ret;
> +		return inv_mpu9250_magn_probe(st);
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate)
> +{
> +	int max_freq;
> +	uint8_t d;
> +
> +	switch (st->chip_type) {
> +	case INV_MPU9250:
> +	case INV_MPU9255:
> +		max_freq = INV_MPU9250_MAGN_FREQ_HZ_MAX;
> +		break;
> +	default:
> +		return 0;
> +	}
> +
> +	/*
> +	 * update i2c master delay to limit mag sampling to max frequency
> +	 * compute fifo_rate divider d: rate = fifo_rate / (d + 1)
> +	 */
> +	if (fifo_rate > max_freq)
> +		d = fifo_rate / max_freq - 1;
> +	else
> +		d = 0;
> +
> +	return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, d);
> +}
> +
> +int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
> +{
> +	const char *orient;
> +	char *str;
> +	int i;
> +
> +	/* fill magnetometer orientation */
> +	switch (st->chip_type) {
> +	case INV_MPU9250:
> +	case INV_MPU9255:
> +		/* x <- y */
> +		st->magn_orient.rotation[0] = st->orientation.rotation[3];
> +		st->magn_orient.rotation[1] = st->orientation.rotation[4];
> +		st->magn_orient.rotation[2] = st->orientation.rotation[5];
> +		/* y <- x */
> +		st->magn_orient.rotation[3] = st->orientation.rotation[0];
> +		st->magn_orient.rotation[4] = st->orientation.rotation[1];
> +		st->magn_orient.rotation[5] = st->orientation.rotation[2];
> +		/* z <- -z */
> +		for (i = 0; i < 3; ++i) {
> +			orient = st->orientation.rotation[6 + i];
> +			/* use length + 2 for adding minus sign if needed */
> +			str = devm_kzalloc(regmap_get_device(st->map),
> +					   strlen(orient) + 2, GFP_KERNEL);
> +			if (str == NULL)
> +				return -ENOMEM;
> +			if (strcmp(orient, "0") == 0) {
> +				strcpy(str, orient);
> +			} else if (orient[0] == '-') {
> +				strcpy(str, &orient[1]);
> +			} else {
> +				str[0] = '-';
> +				strcpy(&str[1], orient);
> +			}
> +			st->magn_orient.rotation[6 + i] = str;
> +		}
> +		break;
> +	default:
> +		st->magn_orient = st->orientation;
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val)
> +{
> +	int ret;
> +
> +	switch (st->chip_type) {
> +	case INV_MPU9250:
> +	case INV_MPU9255:

This is a bit paranoid given we can't get anywhere near here if it isn't one of
these devices.  I suppose you might have other magn containing devices to be
supported in the near future?

> +		ret = inv_mpu9250_magn_read(st, axis, val);
> +		break;
> +	default:
> +		ret = -ENODEV;
> +		break;
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h
> new file mode 100644
> index 000000000000..efa2ec1b3b2f
> --- /dev/null
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h
> @@ -0,0 +1,107 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2019 TDK-InvenSense, Inc.
> + */
> +
> +#ifndef INV_MPU_MAGN_H_
> +#define INV_MPU_MAGN_H_
> +
> +#include <linux/kernel.h>
> +
> +#include "inv_mpu_iio.h"
> +
> +#ifdef CONFIG_INV_MPU6050_MAGN
> +
> +/**
> + * inv_mpu_magn_probe() - probe and setup magnetometer chip
> + * @st: driver internal state
> + *
> + * Returns 0 on success, a negative error code otherwise
> + *
> + * It is probing the chip and setting up all needed i2c transfers.
> + * Noop if there is no magnetometer in the chip.
> + */

Comments generally next to implementations rather than definitions...
We got this wrong a fair bit in early IIO but let us move forward
correctly!

> +int inv_mpu_magn_probe(struct inv_mpu6050_state *st);
> +
> +/**
> + * inv_mpu_magn_get_scale() - get magnetometer scale value
> + * @st: driver internal state
> + *
> + * Returns IIO data format.
> + */
> +static inline int inv_mpu_magn_get_scale(const struct inv_mpu6050_state *st,
> +					 const struct iio_chan_spec *chan,
> +					 int *val, int *val2)
> +{
> +	*val = 0;
> +	*val2 = st->magn_raw_to_gauss[chan->address];
> +	return IIO_VAL_INT_PLUS_MICRO;
> +}
> +
> +/**
> + * inv_mpu_magn_set_rate() - set magnetometer sampling rate
> + * @st: driver internal state
> + * @fifo_rate: mpu set fifo rate
> + *
> + * Returns 0 on success, a negative error code otherwise
> + *
> + * Limit sampling frequency to the maximum value supported by the
> + * magnetometer chip. Resulting in duplicated data for higher frequencies.
> + * Noop if there is no magnetometer in the chip.
> + */
> +int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate);
> +
> +/**
> + * inv_mpu_magn_set_orient() - fill magnetometer mounting matrix
> + * @st: driver internal state
> + *
> + * Returns 0 on success, a negative error code otherwise
> + *
> + * Fill magnetometer mounting matrix using the provided chip matrix.
> + */
> +int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st);
> +
> +/**
> + * inv_mpu_magn_read() - read magnetometer data
> + * @st: driver internal state
> + * @axis: IIO modifier axis value
> + * @val: store corresponding axis value
> + *
> + * Returns 0 on success, a negative error code otherwise
> + */
> +int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val);
> +
> +#else		/* CONFIG_INV_MPU6050_MAGN */
> +
> +static inline int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
> +{
> +	return 0;
> +}
> +
> +static inline int inv_mpu_magn_get_scale(const struct inv_mpu6050_state *st,
> +					 const struct iio_chan_spec *chan,
> +					 int *val, int *val2)
> +{
> +	return -EINVAL;
> +}
> +
> +static inline int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st,
> +					int fifo_rate)
> +{
> +	return 0;
> +}
> +
> +static inline int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
> +{
> +	return 0;
> +}
> +
> +static inline int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis,
> +				    int *val)
> +{
> +	return 0;
> +}
> +
> +#endif		/* CONFIG_INV_MPU6050_MAGN */
> +
> +#endif		/* INV_MPU_MAGN_H_ */


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 8/8] iio: imu: inv_mpu6050: add fifo support for magnetometer data
  2019-08-29 15:18 ` [PATCH 8/8] iio: imu: inv_mpu6050: add fifo support for magnetometer data Jean-Baptiste Maneyrol
@ 2019-09-08 12:07   ` Jonathan Cameron
  0 siblings, 0 replies; 17+ messages in thread
From: Jonathan Cameron @ 2019-09-08 12:07 UTC (permalink / raw)
  To: Jean-Baptiste Maneyrol; +Cc: linux-iio

On Thu, 29 Aug 2019 15:18:46 +0000
Jean-Baptiste Maneyrol <JManeyrol@invensense.com> wrote:

> Put read magnetometer data by mpu inside the fifo.
> 
> Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>

Inline...

> ---
>  drivers/iio/imu/inv_mpu6050/inv_mpu_core.c    |  1 +
>  drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |  2 +
>  drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c    | 14 ++-
>  drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c | 90 +++++++++++++++++--
>  4 files changed, 94 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> index d08cec6a8a7a..d4a321fd03a9 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
> @@ -105,6 +105,7 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = {
>  	.divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE),
>  	.gyro_fifo_enable = false,
>  	.accl_fifo_enable = false,
> +	.magn_fifo_enable = false,
>  	.accl_fs = INV_MPU6050_FS_02G,
>  	.user_ctrl = 0,
>  };
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> index cfc11cb0a36c..48ed66e39cda 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
> @@ -86,6 +86,7 @@ enum inv_devices {
>   *  @accl_fs:		accel full scale range.
>   *  @accl_fifo_enable:	enable accel data output
>   *  @gyro_fifo_enable:	enable gyro data output
> + *  @magn_fifo_enable:	enable magn data output
>   *  @divider:		chip sample rate divider (sample rate divider - 1)
>   */
>  struct inv_mpu6050_chip_config {
> @@ -94,6 +95,7 @@ struct inv_mpu6050_chip_config {
>  	unsigned int accl_fs:2;
>  	unsigned int accl_fifo_enable:1;
>  	unsigned int gyro_fifo_enable:1;
> +	unsigned int magn_fifo_enable:1;
>  	u8 divider;
>  	u8 user_ctrl;
>  };
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
> index 5f9a5de0bab4..f0a5350c1848 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
> @@ -14,6 +14,7 @@
>  #include <linux/poll.h>
>  #include <linux/math64.h>
>  #include <asm/unaligned.h>
> +

Clean this stuff up - should not be in this patch.


>  #include "inv_mpu_iio.h"
>  
>  /**
> @@ -124,7 +125,8 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
>  
>  	/* enable interrupt */
>  	if (st->chip_config.accl_fifo_enable ||
> -	    st->chip_config.gyro_fifo_enable) {
> +	    st->chip_config.gyro_fifo_enable ||
> +	    st->chip_config.magn_fifo_enable) {
>  		result = regmap_write(st->map, st->reg->int_enable,
>  				      INV_MPU6050_BIT_DATA_RDY_EN);
>  		if (result)
> @@ -141,6 +143,8 @@ int inv_reset_fifo(struct iio_dev *indio_dev)
>  		d |= INV_MPU6050_BITS_GYRO_OUT;
>  	if (st->chip_config.accl_fifo_enable)
>  		d |= INV_MPU6050_BIT_ACCEL_OUT;
> +	if (st->chip_config.magn_fifo_enable)
> +		d |= INV_MPU6050_BIT_SLAVE_0;
>  	result = regmap_write(st->map, st->reg->fifo_en, d);
>  	if (result)
>  		goto reset_fifo_fail;
> @@ -190,17 +194,19 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
>  	}
>  
>  	if (!(st->chip_config.accl_fifo_enable |
> -		st->chip_config.gyro_fifo_enable))
> +		st->chip_config.gyro_fifo_enable |
> +		st->chip_config.magn_fifo_enable))
>  		goto end_session;
> +
>  	bytes_per_datum = 0;
>  	if (st->chip_config.accl_fifo_enable)
>  		bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
> -
I don't want to see white space changes in a patch doing something else.
Better to just be consistent and carry on with the blank line for your new
case.

>  	if (st->chip_config.gyro_fifo_enable)
>  		bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
> -
>  	if (st->chip_type == INV_ICM20602)
>  		bytes_per_datum += INV_ICM20602_BYTES_PER_TEMP_SENSOR;
> +	if (st->chip_config.magn_fifo_enable)
> +		bytes_per_datum += INV_MPU9X50_BYTES_MAGN;
>  
>  	/*
>  	 * read fifo_count register to know how many bytes are inside the FIFO
> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
> index dd55e70b6f77..fa4928e589b9 100644
> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
> @@ -5,7 +5,7 @@
>  
>  #include "inv_mpu_iio.h"
>  
> -static void inv_scan_query(struct iio_dev *indio_dev)
> +static void inv_scan_query_mpu6050(struct iio_dev *indio_dev)
>  {
>  	struct inv_mpu6050_state  *st = iio_priv(indio_dev);
>  
> @@ -26,6 +26,52 @@ static void inv_scan_query(struct iio_dev *indio_dev)
>  			 indio_dev->active_scan_mask);
>  }
>  
> +#ifdef CONFIG_INV_MPU6050_MAGN
> +static void inv_scan_query_mpu9x50(struct iio_dev *indio_dev)
> +{
> +	struct inv_mpu6050_state *st = iio_priv(indio_dev);
> +
> +	st->chip_config.gyro_fifo_enable =
> +		test_bit(INV_MPU9X50_SCAN_GYRO_X,
> +			 indio_dev->active_scan_mask) ||
> +		test_bit(INV_MPU9X50_SCAN_GYRO_Y,
> +			 indio_dev->active_scan_mask) ||
> +		test_bit(INV_MPU9X50_SCAN_GYRO_Z,
> +			 indio_dev->active_scan_mask);
> +
> +	st->chip_config.accl_fifo_enable =
> +		test_bit(INV_MPU9X50_SCAN_ACCL_X,
> +			 indio_dev->active_scan_mask) ||
> +		test_bit(INV_MPU9X50_SCAN_ACCL_Y,
> +			 indio_dev->active_scan_mask) ||
> +		test_bit(INV_MPU9X50_SCAN_ACCL_Z,
> +			 indio_dev->active_scan_mask);
> +
> +	st->chip_config.magn_fifo_enable =
> +		test_bit(INV_MPU9X50_SCAN_MAGN_X,
> +			 indio_dev->active_scan_mask) ||
> +		test_bit(INV_MPU9X50_SCAN_MAGN_Y,
> +			 indio_dev->active_scan_mask) ||
> +		test_bit(INV_MPU9X50_SCAN_MAGN_Z,
> +			 indio_dev->active_scan_mask);
> +}
> +#endif
> +
> +static void inv_scan_query(struct iio_dev *indio_dev)
> +{
> +	struct inv_mpu6050_state *st = iio_priv(indio_dev);
> +
> +	switch (st->chip_type) {
> +#ifdef CONFIG_INV_MPU6050_MAGN
> +	case INV_MPU9250:
> +	case INV_MPU9255:
> +		return inv_scan_query_mpu9x50(indio_dev);
> +#endif
> +	default:
> +		return inv_scan_query_mpu6050(indio_dev);
> +	}
> +}
> +
>  /**
>   *  inv_mpu6050_set_enable() - enable chip functions.
>   *  @indio_dev:	Device driver instance.
> @@ -34,6 +80,11 @@ static void inv_scan_query(struct iio_dev *indio_dev)
>  static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
>  {
>  	struct inv_mpu6050_state *st = iio_priv(indio_dev);
> +	uint8_t d;
> +	unsigned int gyro_skip = 0;
> +	unsigned int accl_skip = 0;
> +	unsigned int magn_skip = 0;
> +	unsigned int skip_samples;
>  	int result;
>  
>  	if (enable) {
> @@ -41,14 +92,13 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
>  		if (result)
>  			return result;
>  		inv_scan_query(indio_dev);
> -		st->skip_samples = 0;
>  		if (st->chip_config.gyro_fifo_enable) {
>  			result = inv_mpu6050_switch_engine(st, true,
>  					INV_MPU6050_BIT_PWR_GYRO_STBY);
>  			if (result)
>  				goto error_power_off;
>  			/* gyro first sample is out of specs, skip it */
> -			st->skip_samples = 1;
> +			gyro_skip = 1;
>  		}
>  		if (st->chip_config.accl_fifo_enable) {
>  			result = inv_mpu6050_switch_engine(st, true,
> @@ -56,22 +106,40 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
>  			if (result)
>  				goto error_gyro_off;
>  		}
> +		if (st->chip_config.magn_fifo_enable) {
> +			d = st->chip_config.user_ctrl |
> +					INV_MPU6050_BIT_I2C_MST_EN;
> +			result = regmap_write(st->map, st->reg->user_ctrl, d);
> +			if (result)
> +				goto error_accl_off;
> +			st->chip_config.user_ctrl = d;
> +			/* mag first sample is always not ready, skip it */
> +			magn_skip = 1;
> +		}
> +		/* compute first samples to skip */
> +		skip_samples = gyro_skip;
> +		if (accl_skip > skip_samples)
> +			skip_samples = accl_skip;
> +		if (magn_skip > skip_samples)
> +			skip_samples = magn_skip;
> +		st->skip_samples = skip_samples;
>  		result = inv_reset_fifo(indio_dev);
>  		if (result)
> -			goto error_accl_off;
> +			goto error_magn_off;
>  	} else {
>  		result = regmap_write(st->map, st->reg->fifo_en, 0);
>  		if (result)
> -			goto error_accl_off;
> +			goto error_magn_off;
>  
>  		result = regmap_write(st->map, st->reg->int_enable, 0);
>  		if (result)
> -			goto error_accl_off;
> +			goto error_magn_off;
>  
> -		result = regmap_write(st->map, st->reg->user_ctrl,
> -				      st->chip_config.user_ctrl);
> +		d = st->chip_config.user_ctrl & ~INV_MPU6050_BIT_I2C_MST_EN;
> +		result = regmap_write(st->map, st->reg->user_ctrl, d);
>  		if (result)
> -			goto error_accl_off;
> +			goto error_magn_off;
> +		st->chip_config.user_ctrl = d;
>  
>  		result = inv_mpu6050_switch_engine(st, false,
>  					INV_MPU6050_BIT_PWR_ACCL_STBY);
> @@ -90,6 +158,10 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
>  
>  	return 0;
>  
> +error_magn_off:
> +	/* always restore user_ctrl to disable fifo properly */
> +	st->chip_config.user_ctrl &= ~INV_MPU6050_BIT_I2C_MST_EN;
> +	regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl);
>  error_accl_off:
>  	if (st->chip_config.accl_fifo_enable)
>  		inv_mpu6050_switch_engine(st, false,


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/8] add magnetometer support for MPU925x
  2019-09-08 11:42 ` [PATCH 0/8] add magnetometer support for MPU925x Jonathan Cameron
@ 2019-09-09  9:55   ` Jean-Baptiste Maneyrol
  2019-09-10 13:39     ` Jonathan Cameron
  0 siblings, 1 reply; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-09-09  9:55 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

Hi Jonathan,

we could add a check on the DT for i2c-gate node.
We also need to add a check on the ACPI configuration used by the ASUS T100TA device.

In this case, do you think it is still valuable to have a Kconfig option? (this can still help to reduce driver footprint)

Thanks.
JB


From: Jonathan Cameron <jic23@kernel.org>

Sent: Sunday, September 8, 2019 13:42

To: Jean-Baptiste Maneyrol <JManeyrol@invensense.com>

Cc: linux-iio@vger.kernel.org <linux-iio@vger.kernel.org>

Subject: Re: [PATCH 0/8] add magnetometer support for MPU925x

 


 CAUTION: This email originated from outside of the organization. Please make sure the sender is who they say they are and do not click links or open attachments unless you recognize the sender and know the content is safe.



On Thu, 29 Aug 2019 15:18:33 +0000

Jean-Baptiste Maneyrol <JManeyrol@invensense.com> wrote:



> This serie of patches adds support of magnetometer inside MPU925x chips.

> It is using the MPU i2c master to drive the integrated magnetometer and

> read data into the MPU FIFO.

> 

> Beware that this is disabling access to the i2c auxiliary bus. Since this

> can break existing setup, it is an optional feature requiring to enable

> the corresponding Kconfig option.



That's not great... People will fail to set that correctly for their

setup even if there is a 'correct' setting.



So we need more information to risk that breakage + discussions of

ways to avoid it.  Can we for example check if the auxiliary bus is

in use? (DT binding for example - check for the i2c-gate node?)



Jonathan



> 

> Jean-Baptiste Maneyrol (8):

>   iio: imu: inv_mpu6050: disable i2c mux for 925x under Kconfig

>   iio: imu: inv_mpu6050: add header include protection macro

>   iio: imu: inv_mpu6050: add defines for supporting 9-axis chips

>   iio: imu: inv_mpu6050: fix objects syntax in Makefile

>   iio: imu: inv_mpu6050: helpers for using i2c master on auxiliary bus

>   iio: imu: inv_mpu6050: add magnetometer implementation for MPU925x

>   iio: imu: inv_mpu6050: add magnetometer support inside mpu driver

>   iio: imu: inv_mpu6050: add fifo support for magnetometer data

> 

>  drivers/iio/imu/inv_mpu6050/Kconfig           |   9 +

>  drivers/iio/imu/inv_mpu6050/Makefile          |   8 +-

>  .../iio/imu/inv_mpu6050/inv_mpu9250_magn.c    | 239 ++++++++++++++++++

>  .../iio/imu/inv_mpu6050/inv_mpu9250_magn.h    |  27 ++

>  drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c     | 191 ++++++++++++++

>  drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h     |  46 ++++

>  drivers/iio/imu/inv_mpu6050/inv_mpu_core.c    | 141 ++++++++++-

>  drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c     |   5 +

>  drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |  79 +++++-

>  drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c    | 120 +++++++++

>  drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h    | 107 ++++++++

>  drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c    |  14 +-

>  drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c |  90 ++++++-

>  13 files changed, 1055 insertions(+), 21 deletions(-)

>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c

>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h

>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c

>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h

>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c

>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h

> 




^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 7/8] iio: imu: inv_mpu6050: add magnetometer support inside mpu driver
  2019-09-08 12:05   ` Jonathan Cameron
@ 2019-09-09 16:18     ` Jean-Baptiste Maneyrol
  0 siblings, 0 replies; 17+ messages in thread
From: Jean-Baptiste Maneyrol @ 2019-09-09 16:18 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio

Hi Jonathan,

I think this one is effectively a little overdoing it. The idea is to add in the future support of other 9-axis chips

But let's try to be simple first. I will merge the inv_mpu9250_magn and inv_mpu_magn together in the v2 series.

Thanks for the feedback.
JB


From: Jonathan Cameron <jic23@kernel.org>

Sent: Sunday, September 8, 2019 14:05

To: Jean-Baptiste Maneyrol <JManeyrol@invensense.com>

Cc: linux-iio@vger.kernel.org <linux-iio@vger.kernel.org>

Subject: Re: [PATCH 7/8] iio: imu: inv_mpu6050: add magnetometer support inside mpu driver

 


 CAUTION: This email originated from outside of the organization. Please make sure the sender is who they say they are and do not click links or open attachments unless you recognize the sender and know the content is safe.



On Thu, 29 Aug 2019 15:18:45 +0000

Jean-Baptiste Maneyrol <JManeyrol@invensense.com> wrote:



> Add inv_mpu_magn layer to manage several chip specific

> implementations and be noop when Kconfig option is not set.

> 

> Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>



A few minor bits inline.



Thanks,



Jonathan



> ---

>  drivers/iio/imu/inv_mpu6050/Makefile       |   3 +-

>  drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 140 ++++++++++++++++++++-

>  drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h  |   2 +

>  drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c | 120 ++++++++++++++++++

>  drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h | 107 ++++++++++++++++

>  5 files changed, 368 insertions(+), 4 deletions(-)

>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c

>  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h

> 

> diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile

> index fee41415ebdb..6f5baac29f81 100644

> --- a/drivers/iio/imu/inv_mpu6050/Makefile

> +++ b/drivers/iio/imu/inv_mpu6050/Makefile

> @@ -5,7 +5,8 @@


>  obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o

>  inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o

> -inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o inv_mpu9250_magn.o

> +inv-mpu6050-$(CONFIG_INV_MPU6050_MAGN) += inv_mpu_aux.o inv_mpu_magn.o \

> +     inv_mpu9250_magn.o


>  obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o

>  inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o

> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c

> index b17f060b52fc..d08cec6a8a7a 100644

> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c

> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c

> @@ -16,7 +16,9 @@

>  #include <linux/acpi.h>

>  #include <linux/platform_device.h>

>  #include <linux/regulator/consumer.h>

> +

>  #include "inv_mpu_iio.h"

> +#include "inv_mpu_magn.h"


>  /*

>   * this is the gyro scale translated from dynamic range plus/minus

> @@ -332,6 +334,11 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev)

>         */

>        st->chip_period = NSEC_PER_MSEC;


> +     /* magn chip init, noop if not present in the chip */

> +     result = inv_mpu_magn_probe(st);

> +     if (result)

> +             goto error_power_off;

> +

>        return inv_mpu6050_set_power_itg(st, false);


>  error_power_off:

> @@ -411,6 +418,9 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,

>                ret = inv_mpu6050_sensor_show(st, st->reg->temperature,

>                                              IIO_MOD_X, val);

>                break;

> +     case IIO_MAGN:

> +             ret = inv_mpu_magn_read(st, chan->channel2, val);

> +             break;

>        default:

>                ret = -EINVAL;

>                break;

> @@ -469,6 +479,8 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,

>                                *val2 = INV_MPU6050_TEMP_SCALE;


>                        return IIO_VAL_INT_PLUS_MICRO;

> +             case IIO_MAGN:

> +                     return inv_mpu_magn_get_scale(st, chan, val, val2);

>                default:

>                        return -EINVAL;

>                }

> @@ -710,6 +722,11 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,

>        if (result)

>                goto fifo_rate_fail_power_off;


> +     /* update rate for magn, noop if not present in chip */

> +     result = inv_mpu_magn_set_rate(st, fifo_rate);

> +     if (result)

> +             goto fifo_rate_fail_power_off;

> +

>  fifo_rate_fail_power_off:

>        result |= inv_mpu6050_set_power_itg(st, false);

>  fifo_rate_fail_unlock:

> @@ -795,8 +812,13 @@ inv_get_mount_matrix(const struct iio_dev *indio_dev,

>                     const struct iio_chan_spec *chan)

>  {

>        struct inv_mpu6050_state *data = iio_priv(indio_dev);

> +     const struct iio_mount_matrix *matrix = &data->orientation;


> -     return &data->orientation;

> +#ifdef CONFIG_INV_MPU6050_MAGN

> +     if (chan->type == IIO_MAGN)

> +             matrix = &data->magn_orient;

> +#endif

> +     return matrix;

>  }


>  static const struct iio_chan_spec_ext_info inv_ext_info[] = {

> @@ -864,6 +886,102 @@ static const unsigned long inv_mpu_scan_masks[] = {

>        0,

>  };


> +#ifdef CONFIG_INV_MPU6050_MAGN

> +

> +#define INV_MPU9X50_MAGN_CHAN(_chan2, _bits, _index)                 \

> +     {                                                               \

> +             .type = IIO_MAGN,                                       \

> +             .modified = 1,                                          \

> +             .channel2 = _chan2,                                     \

> +             .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) |        \

> +                                   BIT(IIO_CHAN_INFO_RAW),            \

> +             .scan_index = _index,                                   \

> +             .scan_type = {                                          \

> +                     .sign = 's',                                    \

> +                     .realbits = _bits,                              \

> +                     .storagebits = 16,                              \

> +                     .shift = 0,                                     \

> +                     .endianness = IIO_BE,                           \

> +             },                                                      \

> +             .ext_info = inv_ext_info,                               \

> +     }

> +

> +static const struct iio_chan_spec inv_mpu9250_channels[] = {

> +     IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP),

> +     /*

> +      * Note that temperature should only be via polled reading only,

> +      * not the final scan elements output.

> +      */

> +     {

> +             .type = IIO_TEMP,

> +             .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)

> +                             | BIT(IIO_CHAN_INFO_OFFSET)

> +                             | BIT(IIO_CHAN_INFO_SCALE),

> +             .scan_index = -1,

> +     },

> +     INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU9X50_SCAN_GYRO_X),

> +     INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU9X50_SCAN_GYRO_Y),

> +     INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU9X50_SCAN_GYRO_Z),

> +

> +     INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU9X50_SCAN_ACCL_X),

> +     INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU9X50_SCAN_ACCL_Y),

> +     INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU9X50_SCAN_ACCL_Z),

> +

> +     /* Magnetometer resolution is 16 bits */

> +     INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 16, INV_MPU9X50_SCAN_MAGN_X),

> +     INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 16, INV_MPU9X50_SCAN_MAGN_Y),

> +     INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 16, INV_MPU9X50_SCAN_MAGN_Z),

> +};

> +

> +static const unsigned long inv_mpu9x50_scan_masks[] = {

> +     /* 3-axis accel */

> +     BIT(INV_MPU9X50_SCAN_ACCL_X)

> +             | BIT(INV_MPU9X50_SCAN_ACCL_Y)

> +             | BIT(INV_MPU9X50_SCAN_ACCL_Z),

> +     /* 3-axis gyro */

> +     BIT(INV_MPU9X50_SCAN_GYRO_X)

> +             | BIT(INV_MPU9X50_SCAN_GYRO_Y)

> +             | BIT(INV_MPU9X50_SCAN_GYRO_Z),

> +     /* 3-axis magn */

> +     BIT(INV_MPU9X50_SCAN_MAGN_X)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_Y)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_Z),

> +     /* 6-axis accel + gyro */

> +     BIT(INV_MPU9X50_SCAN_ACCL_X)

> +             | BIT(INV_MPU9X50_SCAN_ACCL_Y)

> +             | BIT(INV_MPU9X50_SCAN_ACCL_Z)

> +             | BIT(INV_MPU9X50_SCAN_GYRO_X)

> +             | BIT(INV_MPU9X50_SCAN_GYRO_Y)

> +             | BIT(INV_MPU9X50_SCAN_GYRO_Z),

> +     /* 6-axis accel + magn */

> +     BIT(INV_MPU9X50_SCAN_ACCL_X)

> +             | BIT(INV_MPU9X50_SCAN_ACCL_Y)

> +             | BIT(INV_MPU9X50_SCAN_ACCL_Z)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_X)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_Y)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_Z),

> +     /* 6-axis gyro + magn */

> +     BIT(INV_MPU9X50_SCAN_GYRO_X)

> +             | BIT(INV_MPU9X50_SCAN_GYRO_Y)

> +             | BIT(INV_MPU9X50_SCAN_GYRO_Z)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_X)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_Y)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_Z),

> +     /* 9-axis accel + gyro + magn */

> +     BIT(INV_MPU9X50_SCAN_ACCL_X)

> +             | BIT(INV_MPU9X50_SCAN_ACCL_Y)

> +             | BIT(INV_MPU9X50_SCAN_ACCL_Z)

> +             | BIT(INV_MPU9X50_SCAN_GYRO_X)

> +             | BIT(INV_MPU9X50_SCAN_GYRO_Y)

> +             | BIT(INV_MPU9X50_SCAN_GYRO_Z)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_X)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_Y)

> +             | BIT(INV_MPU9X50_SCAN_MAGN_Z),

> +     0,

> +};

> +

> +#endif

> +

>  static const struct iio_chan_spec inv_icm20602_channels[] = {

>        IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP),

>        {

> @@ -1145,6 +1263,11 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,

>                return result;

>        }


> +     /* fill magnetometer orientation */

> +     result = inv_mpu_magn_set_orient(st);

> +     if (result)

> +             return result;

> +

>        /* power is turned on inside check chip type*/

>        result = inv_check_and_setup_chip(st);

>        if (result)

> @@ -1167,14 +1290,25 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,

>        else

>                indio_dev->name = dev_name(dev);


> -     if (chip_type == INV_ICM20602) {

> +     switch (chip_type) {

> +#ifdef CONFIG_INV_MPU6050_MAGN

> +     case INV_MPU9250:

> +     case INV_MPU9255:

> +             indio_dev->channels = inv_mpu9250_channels;

> +             indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);

> +             indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;

> +             break;

> +#endif

> +     case INV_ICM20602:

>                indio_dev->channels = inv_icm20602_channels;

>                indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels);

>                indio_dev->available_scan_masks = inv_icm20602_scan_masks;

> -     } else {

> +             break;

> +     default:

>                indio_dev->channels = inv_mpu_channels;

>                indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);

>                indio_dev->available_scan_masks = inv_mpu_scan_masks;

> +             break;

>        }


>        indio_dev->info = &mpu_info;

> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h

> index 5b462672bbcb..cfc11cb0a36c 100644

> --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h

> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h

> @@ -130,6 +130,7 @@ struct inv_mpu6050_hw {

>   *  @data_timestamp: timestamp for next data sample.

>   *  @vddio_supply    voltage regulator for the chip.

>   *  @magn_raw_to_gauss:      coefficient to convert mag raw value to Gauss.

> + *  @magn_orient:    magnetometer sensor chip orientation if available.

>   */

>  struct inv_mpu6050_state {

>        struct mutex lock;

> @@ -153,6 +154,7 @@ struct inv_mpu6050_state {

>        struct regulator *vddio_supply;

>  #ifdef CONFIG_INV_MPU6050_MAGN

>        s32 magn_raw_to_gauss[3];

> +     struct iio_mount_matrix magn_orient;

>  #endif

>  };


> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c

> new file mode 100644

> index 000000000000..2bb40dae0429

> --- /dev/null

> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c

> @@ -0,0 +1,120 @@

> +// SPDX-License-Identifier: GPL-2.0

> +/*

> + * Copyright (C) 2019 TDK-InvenSense, Inc.

> + */

> +

> +#include <linux/kernel.h>

> +#include <linux/device.h>

> +#include <linux/string.h>

> +

> +#include "inv_mpu_iio.h"

> +#include "inv_mpu_aux.h"

> +#include "inv_mpu9250_magn.h"

> +

> +int inv_mpu_magn_probe(struct inv_mpu6050_state *st)

> +{

> +     int ret;

> +

> +     /* probe and init mag chip */

> +     switch (st->chip_type) {

> +     case INV_MPU9250:

> +     case INV_MPU9255:

> +             /* configure i2c master aux port */

> +             ret = inv_mpu_aux_init(st);

> +             if (ret)

> +                     return ret;

> +             return inv_mpu9250_magn_probe(st);

> +     default:

> +             break;

> +     }

> +

> +     return 0;

> +}

> +

> +int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate)

> +{

> +     int max_freq;

> +     uint8_t d;

> +

> +     switch (st->chip_type) {

> +     case INV_MPU9250:

> +     case INV_MPU9255:

> +             max_freq = INV_MPU9250_MAGN_FREQ_HZ_MAX;

> +             break;

> +     default:

> +             return 0;

> +     }

> +

> +     /*

> +      * update i2c master delay to limit mag sampling to max frequency

> +      * compute fifo_rate divider d: rate = fifo_rate / (d + 1)

> +      */

> +     if (fifo_rate > max_freq)

> +             d = fifo_rate / max_freq - 1;

> +     else

> +             d = 0;

> +

> +     return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, d);

> +}

> +

> +int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)

> +{

> +     const char *orient;

> +     char *str;

> +     int i;

> +

> +     /* fill magnetometer orientation */

> +     switch (st->chip_type) {

> +     case INV_MPU9250:

> +     case INV_MPU9255:

> +             /* x <- y */

> +             st->magn_orient.rotation[0] = st->orientation.rotation[3];

> +             st->magn_orient.rotation[1] = st->orientation.rotation[4];

> +             st->magn_orient.rotation[2] = st->orientation.rotation[5];

> +             /* y <- x */

> +             st->magn_orient.rotation[3] = st->orientation.rotation[0];

> +             st->magn_orient.rotation[4] = st->orientation.rotation[1];

> +             st->magn_orient.rotation[5] = st->orientation.rotation[2];

> +             /* z <- -z */

> +             for (i = 0; i < 3; ++i) {

> +                     orient = st->orientation.rotation[6 + i];

> +                     /* use length + 2 for adding minus sign if needed */

> +                     str = devm_kzalloc(regmap_get_device(st->map),

> +                                        strlen(orient) + 2, GFP_KERNEL);

> +                     if (str == NULL)

> +                             return -ENOMEM;

> +                     if (strcmp(orient, "0") == 0) {

> +                             strcpy(str, orient);

> +                     } else if (orient[0] == '-') {

> +                             strcpy(str, &orient[1]);

> +                     } else {

> +                             str[0] = '-';

> +                             strcpy(&str[1], orient);

> +                     }

> +                     st->magn_orient.rotation[6 + i] = str;

> +             }

> +             break;

> +     default:

> +             st->magn_orient = st->orientation;

> +             break;

> +     }

> +

> +     return 0;

> +}

> +

> +int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val)

> +{

> +     int ret;

> +

> +     switch (st->chip_type) {

> +     case INV_MPU9250:

> +     case INV_MPU9255:



This is a bit paranoid given we can't get anywhere near here if it isn't one of

these devices.  I suppose you might have other magn containing devices to be

supported in the near future?



> +             ret = inv_mpu9250_magn_read(st, axis, val);

> +             break;

> +     default:

> +             ret = -ENODEV;

> +             break;

> +     }

> +

> +     return ret;

> +}

> diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h

> new file mode 100644

> index 000000000000..efa2ec1b3b2f

> --- /dev/null

> +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h

> @@ -0,0 +1,107 @@

> +/* SPDX-License-Identifier: GPL-2.0 */

> +/*

> + * Copyright (C) 2019 TDK-InvenSense, Inc.

> + */

> +

> +#ifndef INV_MPU_MAGN_H_

> +#define INV_MPU_MAGN_H_

> +

> +#include <linux/kernel.h>

> +

> +#include "inv_mpu_iio.h"

> +

> +#ifdef CONFIG_INV_MPU6050_MAGN

> +

> +/**

> + * inv_mpu_magn_probe() - probe and setup magnetometer chip

> + * @st: driver internal state

> + *

> + * Returns 0 on success, a negative error code otherwise

> + *

> + * It is probing the chip and setting up all needed i2c transfers.

> + * Noop if there is no magnetometer in the chip.

> + */



Comments generally next to implementations rather than definitions...

We got this wrong a fair bit in early IIO but let us move forward

correctly!



> +int inv_mpu_magn_probe(struct inv_mpu6050_state *st);

> +

> +/**

> + * inv_mpu_magn_get_scale() - get magnetometer scale value

> + * @st: driver internal state

> + *

> + * Returns IIO data format.

> + */

> +static inline int inv_mpu_magn_get_scale(const struct inv_mpu6050_state *st,

> +                                      const struct iio_chan_spec *chan,

> +                                      int *val, int *val2)

> +{

> +     *val = 0;

> +     *val2 = st->magn_raw_to_gauss[chan->address];

> +     return IIO_VAL_INT_PLUS_MICRO;

> +}

> +

> +/**

> + * inv_mpu_magn_set_rate() - set magnetometer sampling rate

> + * @st: driver internal state

> + * @fifo_rate: mpu set fifo rate

> + *

> + * Returns 0 on success, a negative error code otherwise

> + *

> + * Limit sampling frequency to the maximum value supported by the

> + * magnetometer chip. Resulting in duplicated data for higher frequencies.

> + * Noop if there is no magnetometer in the chip.

> + */

> +int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate);

> +

> +/**

> + * inv_mpu_magn_set_orient() - fill magnetometer mounting matrix

> + * @st: driver internal state

> + *

> + * Returns 0 on success, a negative error code otherwise

> + *

> + * Fill magnetometer mounting matrix using the provided chip matrix.

> + */

> +int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st);

> +

> +/**

> + * inv_mpu_magn_read() - read magnetometer data

> + * @st: driver internal state

> + * @axis: IIO modifier axis value

> + * @val: store corresponding axis value

> + *

> + * Returns 0 on success, a negative error code otherwise

> + */

> +int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val);

> +

> +#else                /* CONFIG_INV_MPU6050_MAGN */

> +

> +static inline int inv_mpu_magn_probe(struct inv_mpu6050_state *st)

> +{

> +     return 0;

> +}

> +

> +static inline int inv_mpu_magn_get_scale(const struct inv_mpu6050_state *st,

> +                                      const struct iio_chan_spec *chan,

> +                                      int *val, int *val2)

> +{

> +     return -EINVAL;

> +}

> +

> +static inline int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st,

> +                                     int fifo_rate)

> +{

> +     return 0;

> +}

> +

> +static inline int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)

> +{

> +     return 0;

> +}

> +

> +static inline int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis,

> +                                 int *val)

> +{

> +     return 0;

> +}

> +

> +#endif               /* CONFIG_INV_MPU6050_MAGN */

> +

> +#endif               /* INV_MPU_MAGN_H_ */




^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 0/8] add magnetometer support for MPU925x
  2019-09-09  9:55   ` Jean-Baptiste Maneyrol
@ 2019-09-10 13:39     ` Jonathan Cameron
  0 siblings, 0 replies; 17+ messages in thread
From: Jonathan Cameron @ 2019-09-10 13:39 UTC (permalink / raw)
  To: Jean-Baptiste Maneyrol; +Cc: Jonathan Cameron, linux-iio

On Mon, 9 Sep 2019 09:55:59 +0000
Jean-Baptiste Maneyrol <JManeyrol@invensense.com> wrote:

> Hi Jonathan,
> 
> we could add a check on the DT for i2c-gate node.
> We also need to add a check on the ACPI configuration used by the ASUS T100TA device.

Great.

> 
> In this case, do you think it is still valuable to have a Kconfig option? (this can still help to reduce driver footprint)

It's less painful if the only reason is tinyfication, but then I want
numbers in the patch to show it makes a significant difference.

Kconfig options are just more things to test so generally prefer
to avoid them for little additions like this.

Thanks,

Jonathan
> 
> Thanks.
> JB
> 
> 
> From: Jonathan Cameron <jic23@kernel.org>
> 
> Sent: Sunday, September 8, 2019 13:42
> 
> To: Jean-Baptiste Maneyrol <JManeyrol@invensense.com>
> 
> Cc: linux-iio@vger.kernel.org <linux-iio@vger.kernel.org>
> 
> Subject: Re: [PATCH 0/8] add magnetometer support for MPU925x
> 
>  
> 
> 
>  CAUTION: This email originated from outside of the organization. Please make sure the sender is who they say they are and do not click links or open attachments unless you recognize the sender and know the content is safe.
> 
> 
> 
> On Thu, 29 Aug 2019 15:18:33 +0000
> 
> Jean-Baptiste Maneyrol <JManeyrol@invensense.com> wrote:
> 
> 
> 
> > This serie of patches adds support of magnetometer inside MPU925x chips.  
> 
> > It is using the MPU i2c master to drive the integrated magnetometer and  
> 
> > read data into the MPU FIFO.  
> 
> >   
> 
> > Beware that this is disabling access to the i2c auxiliary bus. Since this  
> 
> > can break existing setup, it is an optional feature requiring to enable  
> 
> > the corresponding Kconfig option.  
> 
> 
> 
> That's not great... People will fail to set that correctly for their
> 
> setup even if there is a 'correct' setting.
> 
> 
> 
> So we need more information to risk that breakage + discussions of
> 
> ways to avoid it.  Can we for example check if the auxiliary bus is
> 
> in use? (DT binding for example - check for the i2c-gate node?)
> 
> 
> 
> Jonathan
> 
> 
> 
> >   
> 
> > Jean-Baptiste Maneyrol (8):  
> 
> >   iio: imu: inv_mpu6050: disable i2c mux for 925x under Kconfig  
> 
> >   iio: imu: inv_mpu6050: add header include protection macro  
> 
> >   iio: imu: inv_mpu6050: add defines for supporting 9-axis chips  
> 
> >   iio: imu: inv_mpu6050: fix objects syntax in Makefile  
> 
> >   iio: imu: inv_mpu6050: helpers for using i2c master on auxiliary bus  
> 
> >   iio: imu: inv_mpu6050: add magnetometer implementation for MPU925x  
> 
> >   iio: imu: inv_mpu6050: add magnetometer support inside mpu driver  
> 
> >   iio: imu: inv_mpu6050: add fifo support for magnetometer data  
> 
> >   
> 
> >  drivers/iio/imu/inv_mpu6050/Kconfig           |   9 +  
> 
> >  drivers/iio/imu/inv_mpu6050/Makefile          |   8 +-  
> 
> >  .../iio/imu/inv_mpu6050/inv_mpu9250_magn.c    | 239 ++++++++++++++++++  
> 
> >  .../iio/imu/inv_mpu6050/inv_mpu9250_magn.h    |  27 ++  
> 
> >  drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c     | 191 ++++++++++++++  
> 
> >  drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h     |  46 ++++  
> 
> >  drivers/iio/imu/inv_mpu6050/inv_mpu_core.c    | 141 ++++++++++-  
> 
> >  drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c     |   5 +  
> 
> >  drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h     |  79 +++++-  
> 
> >  drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c    | 120 +++++++++  
> 
> >  drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h    | 107 ++++++++  
> 
> >  drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c    |  14 +-  
> 
> >  drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c |  90 ++++++-  
> 
> >  13 files changed, 1055 insertions(+), 21 deletions(-)  
> 
> >  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.c  
> 
> >  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu9250_magn.h  
> 
> >  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c  
> 
> >  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h  
> 
> >  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c  
> 
> >  create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h  
> 
> >   
> 
> 
> 



^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2019-09-10 13:40 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-29 15:18 [PATCH 0/8] add magnetometer support for MPU925x Jean-Baptiste Maneyrol
2019-08-29 15:18 ` [PATCH 1/8] iio: imu: inv_mpu6050: disable i2c mux for 925x under Kconfig Jean-Baptiste Maneyrol
2019-08-29 15:18 ` [PATCH 2/8] iio: imu: inv_mpu6050: add header include protection macro Jean-Baptiste Maneyrol
2019-08-29 15:18 ` [PATCH 3/8] iio: imu: inv_mpu6050: add defines for supporting 9-axis chips Jean-Baptiste Maneyrol
2019-08-29 15:18 ` [PATCH 4/8] iio: imu: inv_mpu6050: fix objects syntax in Makefile Jean-Baptiste Maneyrol
2019-08-29 15:18 ` [PATCH 5/8] iio: imu: inv_mpu6050: helpers for using i2c master on auxiliary bus Jean-Baptiste Maneyrol
2019-09-08 11:57   ` Jonathan Cameron
2019-08-29 15:18 ` [PATCH 6/8] iio: imu: inv_mpu6050: add magnetometer implementation for MPU925x Jean-Baptiste Maneyrol
2019-09-08 11:57   ` Jonathan Cameron
2019-08-29 15:18 ` [PATCH 7/8] iio: imu: inv_mpu6050: add magnetometer support inside mpu driver Jean-Baptiste Maneyrol
2019-09-08 12:05   ` Jonathan Cameron
2019-09-09 16:18     ` Jean-Baptiste Maneyrol
2019-08-29 15:18 ` [PATCH 8/8] iio: imu: inv_mpu6050: add fifo support for magnetometer data Jean-Baptiste Maneyrol
2019-09-08 12:07   ` Jonathan Cameron
2019-09-08 11:42 ` [PATCH 0/8] add magnetometer support for MPU925x Jonathan Cameron
2019-09-09  9:55   ` Jean-Baptiste Maneyrol
2019-09-10 13:39     ` 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).