* [PATCH v2 08/12] iio: imu: inv_icm42600: add device interrupt
From: Jean-Baptiste Maneyrol @ 2020-05-27 18:57 UTC (permalink / raw)
To: jic23, robh+dt, robh, mchehab+huawei, davem, gregkh
Cc: linux-iio, devicetree, linux-kernel, Jean-Baptiste Maneyrol
In-Reply-To: <20200527185711.21331-1-jmaneyrol@invensense.com>
Add INT1 interrupt support. Support interrupt edge and level,
active high or low. Push-pull or open-drain configurations.
Interrupt will be used to read data from the FIFO.
Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
drivers/iio/imu/inv_icm42600/inv_icm42600.h | 2 +-
.../iio/imu/inv_icm42600/inv_icm42600_core.c | 96 ++++++++++++++++++-
.../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 3 +-
.../iio/imu/inv_icm42600/inv_icm42600_spi.c | 3 +-
4 files changed, 100 insertions(+), 4 deletions(-)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index c534acae0308..43749f56426c 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -372,7 +372,7 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval);
-int inv_icm42600_core_probe(struct regmap *regmap, int chip,
+int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
inv_icm42600_bus_setup bus_setup);
int inv_icm42600_gyro_init(struct inv_icm42600_state *st);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index e7f7835aca9b..246c1eb52231 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -9,8 +9,11 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
@@ -409,6 +412,79 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st,
return inv_icm42600_set_conf(st, hw->conf);
}
+static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data)
+{
+ struct inv_icm42600_state *st = _data;
+ struct device *dev = regmap_get_device(st->map);
+ unsigned int status;
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &status);
+ if (ret)
+ goto out_unlock;
+
+ /* FIFO full */
+ if (status & INV_ICM42600_INT_STATUS_FIFO_FULL)
+ dev_warn(dev, "FIFO full data lost!\n");
+
+out_unlock:
+ mutex_unlock(&st->lock);
+ return IRQ_HANDLED;
+}
+
+/**
+ * inv_icm42600_irq_init() - initialize int pin and interrupt handler
+ * @st: driver internal state
+ * @irq: irq number
+ * @irq_type: irq trigger type
+ * @open_drain: true if irq is open drain, false for push-pull
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq,
+ int irq_type, bool open_drain)
+{
+ struct device *dev = regmap_get_device(st->map);
+ unsigned int val;
+ int ret;
+
+ /* configure INT1 interrupt: default is active low on edge */
+ switch (irq_type) {
+ case IRQF_TRIGGER_RISING:
+ case IRQF_TRIGGER_HIGH:
+ val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH;
+ break;
+ default:
+ val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW;
+ break;
+ }
+ switch (irq_type) {
+ case IRQF_TRIGGER_LOW:
+ case IRQF_TRIGGER_HIGH:
+ val |= INV_ICM42600_INT_CONFIG_INT1_LATCHED;
+ break;
+ default:
+ break;
+ }
+ if (!open_drain)
+ val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL;
+ ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val);
+ if (ret)
+ return ret;
+
+ /* Deassert async reset for proper INT pin operation (cf datasheet) */
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
+ INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0);
+ if (ret)
+ return ret;
+
+ return devm_request_threaded_irq(dev, irq, NULL,
+ inv_icm42600_irq_handler, irq_type,
+ "inv_icm42600", st);
+}
+
static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st)
{
int ret;
@@ -453,11 +529,14 @@ static void inv_icm42600_disable_pm(void *_data)
pm_runtime_disable(dev);
}
-int inv_icm42600_core_probe(struct regmap *regmap, int chip,
+int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
inv_icm42600_bus_setup bus_setup)
{
struct device *dev = regmap_get_device(regmap);
struct inv_icm42600_state *st;
+ struct irq_data *irq_desc;
+ int irq_type;
+ bool open_drain;
int ret;
if (chip < 0 || chip >= INV_CHIP_NB) {
@@ -465,6 +544,17 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip,
return -ENODEV;
}
+ /* get irq properties, set trigger falling by default */
+ irq_desc = irq_get_irq_data(irq);
+ if (!irq_desc) {
+ dev_err(dev, "could not find IRQ %d\n", irq);
+ return -EINVAL;
+ }
+ irq_type = irqd_get_trigger_type(irq_desc);
+ if (!irq_type)
+ irq_type = IRQF_TRIGGER_FALLING;
+ open_drain = device_property_read_bool(dev, "drive-open-drain");
+
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
if (!st)
return -ENOMEM;
@@ -518,6 +608,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip,
if (ret)
return ret;
+ ret = inv_icm42600_irq_init(st, irq, irq_type, open_drain);
+ if (ret)
+ return ret;
+
/* setup runtime power management */
ret = pm_runtime_set_active(dev);
if (ret)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
index 4789cead23b3..85b1934cec60 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
@@ -64,7 +64,8 @@ static int inv_icm42600_probe(struct i2c_client *client)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- return inv_icm42600_core_probe(regmap, chip, inv_icm42600_i2c_bus_setup);
+ return inv_icm42600_core_probe(regmap, chip, client->irq,
+ inv_icm42600_i2c_bus_setup);
}
static const struct of_device_id inv_icm42600_of_matches[] = {
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
index a9c5e2fdbe2a..323789697a08 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
@@ -63,7 +63,8 @@ static int inv_icm42600_probe(struct spi_device *spi)
if (IS_ERR(regmap))
return PTR_ERR(regmap);
- return inv_icm42600_core_probe(regmap, chip, inv_icm42600_spi_bus_setup);
+ return inv_icm42600_core_probe(regmap, chip, spi->irq,
+ inv_icm42600_spi_bus_setup);
}
static const struct of_device_id inv_icm42600_of_matches[] = {
--
2.17.1
^ permalink raw reply related
* [PATCH v2 07/12] iio: imu: add Kconfig and Makefile for inv_icm42600 driver
From: Jean-Baptiste Maneyrol @ 2020-05-27 18:57 UTC (permalink / raw)
To: jic23, robh+dt, robh, mchehab+huawei, davem, gregkh
Cc: linux-iio, devicetree, linux-kernel, Jean-Baptiste Maneyrol
In-Reply-To: <20200527185711.21331-1-jmaneyrol@invensense.com>
Add 3 modules: inv-icm42600, inv-icm42600-i2c, inv-icm42600-spi.
Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
drivers/iio/imu/Kconfig | 1 +
drivers/iio/imu/Makefile | 1 +
drivers/iio/imu/inv_icm42600/Kconfig | 28 +++++++++++++++++++++++++++
drivers/iio/imu/inv_icm42600/Makefile | 13 +++++++++++++
4 files changed, 43 insertions(+)
create mode 100644 drivers/iio/imu/inv_icm42600/Kconfig
create mode 100644 drivers/iio/imu/inv_icm42600/Makefile
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index fc4123d518bc..f02883b08480 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -91,6 +91,7 @@ config KMX61
To compile this driver as module, choose M here: the module will
be called kmx61.
+source "drivers/iio/imu/inv_icm42600/Kconfig"
source "drivers/iio/imu/inv_mpu6050/Kconfig"
source "drivers/iio/imu/st_lsm6dsx/Kconfig"
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 88b2c4555230..13e9ff442b11 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_FXOS8700) += fxos8700_core.o
obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
+obj-y += inv_icm42600/
obj-y += inv_mpu6050/
obj-$(CONFIG_KMX61) += kmx61.o
diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig
new file mode 100644
index 000000000000..22390a72f0a3
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42600/Kconfig
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+config INV_ICM42600
+ tristate
+
+config INV_ICM42600_I2C
+ tristate "InvenSense ICM-426xx I2C driver"
+ depends on I2C
+ select INV_ICM42600
+ select REGMAP_I2C
+ help
+ This driver supports the InvenSense ICM-426xx motion tracking
+ devices over I2C.
+
+ This driver can be built as a module. The module will be called
+ inv-icm42600-i2c.
+
+config INV_ICM42600_SPI
+ tristate "InvenSense ICM-426xx SPI driver"
+ depends on SPI_MASTER
+ select INV_ICM42600
+ select REGMAP_SPI
+ help
+ This driver supports the InvenSense ICM-426xx motion tracking
+ devices over SPI.
+
+ This driver can be built as a module. The module will be called
+ inv-icm42600-spi.
diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile
new file mode 100644
index 000000000000..48965824f00c
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42600/Makefile
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+obj-$(CONFIG_INV_ICM42600) += inv-icm42600.o
+inv-icm42600-y += inv_icm42600_core.o
+inv-icm42600-y += inv_icm42600_gyro.o
+inv-icm42600-y += inv_icm42600_accel.o
+inv-icm42600-y += inv_icm42600_temp.o
+
+obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o
+inv-icm42600-i2c-y += inv_icm42600_i2c.o
+
+obj-$(CONFIG_INV_ICM42600_SPI) += inv-icm42600-spi.o
+inv-icm42600-spi-y += inv_icm42600_spi.o
--
2.17.1
^ permalink raw reply related
* [PATCH v2 11/12] dt-bindings: iio: imu: Add inv_icm42600 documentation
From: Jean-Baptiste Maneyrol @ 2020-05-27 18:57 UTC (permalink / raw)
To: jic23, robh+dt, robh, mchehab+huawei, davem, gregkh
Cc: linux-iio, devicetree, linux-kernel, Jean-Baptiste Maneyrol
In-Reply-To: <20200527185711.21331-1-jmaneyrol@invensense.com>
Document the ICM-426xxx devices devicetree bindings.
Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
.../bindings/iio/imu/invensense,icm42600.yaml | 86 +++++++++++++++++++
1 file changed, 86 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
new file mode 100644
index 000000000000..c5b046e0ce36
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/imu/invensense,icm42600.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: InvenSense ICM-426xx Inertial Measurement Unit
+
+maintainers:
+ - Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
+
+description: |
+ 6-axis MotionTracking device that combines a 3-axis gyroscope and a 3-axis accelerometer.
+
+ It has a configurable host interface that supports I3C, I2C and SPI serial communication, features a 2kB FIFO and
+ 2 programmable interrupts with ultra-low-power wake-on-motion support to minimize system power consumption.
+
+ Other industry-leading features include InvenSense on-chip APEX Motion Processing engine for gesture recognition,
+ activity classification, and pedometer, along with programmable digital filters, and an embedded temperature sensor.
+
+ https://invensense.tdk.com/wp-content/uploads/2020/03/DS-000292-ICM-42605-v1.4.pdf
+
+properties:
+ compatible:
+ enum:
+ - invensense,icm42600
+ - invensense,icm42602
+ - invensense,icm42605
+ - invensense,icm42622
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ drive-open-drain:
+ type: boolean
+
+ vdd-supply:
+ description: Regulator that provides power to the sensor
+
+ vddio-supply:
+ description: Regulator that provides power to the bus
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ i2c0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ icm42605@68 {
+ compatible = "invensense,icm42605";
+ reg = <0x68>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+ vdd-supply = <&vdd>;
+ vddio-supply = <&vddio>;
+ };
+ };
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+ spi0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ icm42602@0 {
+ compatible = "invensense,icm42602";
+ reg = <0>;
+ spi-max-frequency = <24000000>;
+ spi-cpha;
+ spi-cpol;
+ interrupt-parent = <&gpio1>;
+ interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+ vdd-supply = <&vdd>;
+ vddio-supply = <&vddio>;
+ };
+ };
--
2.17.1
^ permalink raw reply related
* [PATCH v2 12/12] MAINTAINERS: add entry for inv_icm42600 6-axis imu sensor
From: Jean-Baptiste Maneyrol @ 2020-05-27 18:57 UTC (permalink / raw)
To: jic23, robh+dt, robh, mchehab+huawei, davem, gregkh
Cc: linux-iio, devicetree, linux-kernel, Jean-Baptiste Maneyrol
In-Reply-To: <20200527185711.21331-1-jmaneyrol@invensense.com>
Add MAINTAINERS entry for InvenSense ICM-426xx IMU device.
Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
MAINTAINERS | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 60ed2963efaa..cd8b5fece94d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8861,6 +8861,14 @@ F: include/dt-bindings/interconnect/
F: include/linux/interconnect-provider.h
F: include/linux/interconnect.h
+INVENSENSE ICM-426xx IMU DRIVER
+M: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
+L: linux-iio@vger.kernel.org
+S: Maintained
+W https://invensense.tdk.com/
+F: Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+F: drivers/iio/imu/inv_icm42600/
+
INVENSENSE MPU-3050 GYROSCOPE DRIVER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-iio@vger.kernel.org
--
2.17.1
^ permalink raw reply related
* [PATCH v2 09/12] iio: imu: inv_icm42600: add buffer support in iio devices
From: Jean-Baptiste Maneyrol @ 2020-05-27 18:57 UTC (permalink / raw)
To: jic23, robh+dt, robh, mchehab+huawei, davem, gregkh
Cc: linux-iio, devicetree, linux-kernel, Jean-Baptiste Maneyrol
In-Reply-To: <20200527185711.21331-1-jmaneyrol@invensense.com>
Add all FIFO parsing and reading functions. Add accel and gyro
kfifo buffer and FIFO data parsing. Use device interrupt for
reading data FIFO and launching accel and gyro parsing.
Support hwfifo watermark by multiplexing gyro and accel settings.
Support hwfifo flush.
Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
drivers/iio/imu/inv_icm42600/Kconfig | 1 +
drivers/iio/imu/inv_icm42600/Makefile | 1 +
drivers/iio/imu/inv_icm42600/inv_icm42600.h | 8 +
.../iio/imu/inv_icm42600/inv_icm42600_accel.c | 160 ++++-
.../imu/inv_icm42600/inv_icm42600_buffer.c | 555 ++++++++++++++++++
.../imu/inv_icm42600/inv_icm42600_buffer.h | 98 ++++
.../iio/imu/inv_icm42600/inv_icm42600_core.c | 30 +
.../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 160 ++++-
8 files changed, 1011 insertions(+), 2 deletions(-)
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
diff --git a/drivers/iio/imu/inv_icm42600/Kconfig b/drivers/iio/imu/inv_icm42600/Kconfig
index 22390a72f0a3..50cbcfcb6cf1 100644
--- a/drivers/iio/imu/inv_icm42600/Kconfig
+++ b/drivers/iio/imu/inv_icm42600/Kconfig
@@ -2,6 +2,7 @@
config INV_ICM42600
tristate
+ select IIO_BUFFER
config INV_ICM42600_I2C
tristate "InvenSense ICM-426xx I2C driver"
diff --git a/drivers/iio/imu/inv_icm42600/Makefile b/drivers/iio/imu/inv_icm42600/Makefile
index 48965824f00c..0f49f6df3647 100644
--- a/drivers/iio/imu/inv_icm42600/Makefile
+++ b/drivers/iio/imu/inv_icm42600/Makefile
@@ -5,6 +5,7 @@ inv-icm42600-y += inv_icm42600_core.o
inv-icm42600-y += inv_icm42600_gyro.o
inv-icm42600-y += inv_icm42600_accel.o
inv-icm42600-y += inv_icm42600_temp.o
+inv-icm42600-y += inv_icm42600_buffer.o
obj-$(CONFIG_INV_ICM42600_I2C) += inv-icm42600-i2c.o
inv-icm42600-i2c-y += inv_icm42600_i2c.o
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index 43749f56426c..4d5811562a61 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -14,6 +14,8 @@
#include <linux/pm.h>
#include <linux/iio/iio.h>
+#include "inv_icm42600_buffer.h"
+
enum inv_icm42600_chip {
INV_CHIP_ICM42600,
INV_CHIP_ICM42602,
@@ -123,6 +125,7 @@ struct inv_icm42600_suspended {
* @indio_gyro: gyroscope IIO device.
* @indio_accel: accelerometer IIO device.
* @buffer: data transfer buffer aligned for DMA.
+ * @fifo: FIFO management structure.
*/
struct inv_icm42600_state {
struct mutex lock;
@@ -137,6 +140,7 @@ struct inv_icm42600_state {
struct iio_dev *indio_gyro;
struct iio_dev *indio_accel;
uint8_t buffer[2] ____cacheline_aligned;
+ struct inv_icm42600_fifo fifo;
};
/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
@@ -377,6 +381,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
int inv_icm42600_gyro_init(struct inv_icm42600_state *st);
+int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev);
+
int inv_icm42600_accel_init(struct inv_icm42600_state *st);
+int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev);
+
#endif
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index 6a615d7ffb24..c73ce204efc6 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -11,9 +11,12 @@
#include <linux/delay.h>
#include <linux/math64.h>
#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
#include "inv_icm42600.h"
#include "inv_icm42600_temp.h"
+#include "inv_icm42600_buffer.h"
#define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \
{ \
@@ -64,6 +67,76 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = {
INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP),
};
+/* IIO buffer data: 8 bytes */
+struct inv_icm42600_accel_buffer {
+ struct inv_icm42600_fifo_sensor_data accel;
+ int8_t temp;
+ uint8_t padding;
+};
+
+#define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \
+ (BIT(INV_ICM42600_ACCEL_SCAN_X) | \
+ BIT(INV_ICM42600_ACCEL_SCAN_Y) | \
+ BIT(INV_ICM42600_ACCEL_SCAN_Z))
+
+#define INV_ICM42600_SCAN_MASK_TEMP BIT(INV_ICM42600_ACCEL_SCAN_TEMP)
+
+static const unsigned long inv_icm42600_accel_scan_masks[] = {
+ /* 3-axis accel + temperature */
+ INV_ICM42600_SCAN_MASK_ACCEL_3AXIS | INV_ICM42600_SCAN_MASK_TEMP,
+ 0,
+};
+
+/* enable accelerometer sensor and FIFO write */
+static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
+ unsigned int fifo_en = 0;
+ unsigned int sleep_temp = 0;
+ unsigned int sleep_accel = 0;
+ unsigned int sleep;
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ if (*scan_mask & INV_ICM42600_SCAN_MASK_TEMP) {
+ /* enable temp sensor */
+ ret = inv_icm42600_set_temp_conf(st, true, &sleep_temp);
+ if (ret)
+ goto out_unlock;
+ fifo_en |= INV_ICM42600_SENSOR_TEMP;
+ }
+
+ if (*scan_mask & INV_ICM42600_SCAN_MASK_ACCEL_3AXIS) {
+ /* enable accel sensor */
+ conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
+ ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_accel);
+ if (ret)
+ goto out_unlock;
+ fifo_en |= INV_ICM42600_SENSOR_ACCEL;
+ }
+
+ /* update data FIFO write */
+ ret = inv_icm42600_buffer_set_fifo_en(st, fifo_en | st->fifo.en);
+ if (ret)
+ goto out_unlock;
+
+ ret = inv_icm42600_buffer_update_watermark(st);
+
+out_unlock:
+ mutex_unlock(&st->lock);
+ /* sleep maximum required time */
+ if (sleep_accel > sleep_temp)
+ sleep = sleep_accel;
+ else
+ sleep = sleep_temp;
+ if (sleep)
+ msleep(sleep);
+ return ret;
+}
+
static int inv_icm42600_accel_read_sensor(struct inv_icm42600_state *st,
struct iio_chan_spec const *chan,
int16_t *val)
@@ -248,7 +321,12 @@ static int inv_icm42600_accel_write_odr(struct inv_icm42600_state *st,
mutex_lock(&st->lock);
ret = inv_icm42600_set_accel_conf(st, &conf, NULL);
+ if (ret)
+ goto out_unlock;
+ inv_icm42600_buffer_update_fifo_period(st);
+ inv_icm42600_buffer_update_watermark(st);
+out_unlock:
mutex_unlock(&st->lock);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@@ -563,12 +641,51 @@ static int inv_icm42600_accel_write_raw_get_fmt(struct iio_dev *indio_dev,
}
}
+static int inv_icm42600_accel_hwfifo_set_watermark(struct iio_dev *indio_dev,
+ unsigned int val)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ st->fifo.watermark.accel = val;
+ ret = inv_icm42600_buffer_update_watermark(st);
+
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int inv_icm42600_accel_hwfifo_flush(struct iio_dev *indio_dev,
+ unsigned int count)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ if (count == 0)
+ return 0;
+
+ mutex_lock(&st->lock);
+
+ ret = inv_icm42600_buffer_hwfifo_flush(st, count);
+ if (!ret)
+ ret = st->fifo.nb.accel;
+
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
static const struct iio_info inv_icm42600_accel_info = {
.read_raw = inv_icm42600_accel_read_raw,
.read_avail = inv_icm42600_accel_read_avail,
.write_raw = inv_icm42600_accel_write_raw,
.write_raw_get_fmt = inv_icm42600_accel_write_raw_get_fmt,
.debugfs_reg_access = inv_icm42600_debugfs_reg,
+ .update_scan_mode = inv_icm42600_accel_update_scan_mode,
+ .hwfifo_set_watermark = inv_icm42600_accel_hwfifo_set_watermark,
+ .hwfifo_flush_to_buffer = inv_icm42600_accel_hwfifo_flush,
};
int inv_icm42600_accel_init(struct inv_icm42600_state *st)
@@ -576,6 +693,7 @@ int inv_icm42600_accel_init(struct inv_icm42600_state *st)
struct device *dev = regmap_get_device(st->map);
const char *name;
struct iio_dev *indio_dev;
+ struct iio_buffer *buffer;
name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->name);
if (!name)
@@ -585,14 +703,54 @@ int inv_icm42600_accel_init(struct inv_icm42600_state *st)
if (!indio_dev)
return -ENOMEM;
+ buffer = devm_iio_kfifo_allocate(dev);
+ if (!buffer)
+ return -ENOMEM;
+
iio_device_set_drvdata(indio_dev, st);
indio_dev->dev.parent = dev;
indio_dev->name = name;
indio_dev->info = &inv_icm42600_accel_info;
- indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
indio_dev->channels = inv_icm42600_accel_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_accel_channels);
+ indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks;
+ indio_dev->setup_ops = &inv_icm42600_buffer_ops;
+
+ iio_device_attach_buffer(indio_dev, buffer);
st->indio_accel = indio_dev;
return devm_iio_device_register(dev, st->indio_accel);
}
+
+int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ ssize_t i, size;
+ const void *accel, *gyro, *timestamp;
+ const int8_t *temp;
+ unsigned int odr;
+ struct inv_icm42600_accel_buffer buffer = {
+ .padding = 0,
+ };
+
+ /* parse all fifo packets */
+ for (i = 0; i < st->fifo.count; i += size) {
+ size = inv_icm42600_fifo_decode_packet(&st->fifo.data[i],
+ &accel, &gyro, &temp, ×tamp, &odr);
+ /* quit if error or FIFO is empty */
+ if (size <= 0)
+ return size;
+
+ /* skip packet if no accel data or data is invalid */
+ if (accel == NULL || !inv_icm42600_fifo_is_data_valid(accel))
+ continue;
+
+ /* fill and push data buffer */
+ memcpy(&buffer.accel, accel, sizeof(buffer.accel));
+ buffer.temp = temp ? *temp : 0;
+ iio_push_to_buffers(indio_dev, &buffer);
+ }
+
+ return 0;
+}
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
new file mode 100644
index 000000000000..c91075f62231
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
@@ -0,0 +1,555 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Invensense, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/math64.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+
+#include "inv_icm42600.h"
+#include "inv_icm42600_buffer.h"
+
+/* FIFO header: 1 byte */
+#define INV_ICM42600_FIFO_HEADER_MSG BIT(7)
+#define INV_ICM42600_FIFO_HEADER_ACCEL BIT(6)
+#define INV_ICM42600_FIFO_HEADER_GYRO BIT(5)
+#define INV_ICM42600_FIFO_HEADER_TMST_FSYNC GENMASK(3, 2)
+#define INV_ICM42600_FIFO_HEADER_ODR_ACCEL BIT(1)
+#define INV_ICM42600_FIFO_HEADER_ODR_GYRO BIT(0)
+
+struct inv_icm42600_fifo_1sensor_packet {
+ uint8_t header;
+ struct inv_icm42600_fifo_sensor_data data;
+ int8_t temp;
+} __packed;
+#define INV_ICM42600_FIFO_1SENSOR_PACKET_SIZE 8
+
+struct inv_icm42600_fifo_2sensors_packet {
+ uint8_t header;
+ struct inv_icm42600_fifo_sensor_data accel;
+ struct inv_icm42600_fifo_sensor_data gyro;
+ int8_t temp;
+ __be16 timestamp;
+} __packed;
+#define INV_ICM42600_FIFO_2SENSORS_PACKET_SIZE 16
+
+ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel,
+ const void **gyro, const int8_t **temp,
+ const void **timestamp, unsigned int *odr)
+{
+ const struct inv_icm42600_fifo_1sensor_packet *pack1 = packet;
+ const struct inv_icm42600_fifo_2sensors_packet *pack2 = packet;
+ uint8_t header = *((const uint8_t *)packet);
+
+ /* FIFO empty */
+ if (header & INV_ICM42600_FIFO_HEADER_MSG) {
+ *accel = NULL;
+ *gyro = NULL;
+ *temp = NULL;
+ *timestamp = NULL;
+ *odr = 0;
+ return 0;
+ }
+
+ /* handle odr flags */
+ *odr = 0;
+ if (header & INV_ICM42600_FIFO_HEADER_ODR_GYRO)
+ *odr |= INV_ICM42600_SENSOR_GYRO;
+ if (header & INV_ICM42600_FIFO_HEADER_ODR_ACCEL)
+ *odr |= INV_ICM42600_SENSOR_ACCEL;
+
+ /* accel + gyro */
+ if ((header & INV_ICM42600_FIFO_HEADER_ACCEL) &&
+ (header & INV_ICM42600_FIFO_HEADER_GYRO)) {
+ *accel = &pack2->accel;
+ *gyro = &pack2->gyro;
+ *temp = &pack2->temp;
+ *timestamp = &pack2->timestamp;
+ return INV_ICM42600_FIFO_2SENSORS_PACKET_SIZE;
+ }
+
+ /* accel only */
+ if (header & INV_ICM42600_FIFO_HEADER_ACCEL) {
+ *accel = &pack1->data;
+ *gyro = NULL;
+ *temp = &pack1->temp;
+ *timestamp = NULL;
+ return INV_ICM42600_FIFO_1SENSOR_PACKET_SIZE;
+ }
+
+ /* gyro only */
+ if (header & INV_ICM42600_FIFO_HEADER_GYRO) {
+ *accel = NULL;
+ *gyro = &pack1->data;
+ *temp = &pack1->temp;
+ *timestamp = NULL;
+ return INV_ICM42600_FIFO_1SENSOR_PACKET_SIZE;
+ }
+
+ /* invalid packet if here */
+ return -EINVAL;
+}
+
+void inv_icm42600_buffer_update_fifo_period(struct inv_icm42600_state *st)
+{
+ uint32_t period_gyro, period_accel, period;
+
+ if (st->fifo.en & INV_ICM42600_SENSOR_GYRO)
+ period_gyro = inv_icm42600_odr_to_period(st->conf.gyro.odr);
+ else
+ period_gyro = U32_MAX;
+
+ if (st->fifo.en & INV_ICM42600_SENSOR_ACCEL)
+ period_accel = inv_icm42600_odr_to_period(st->conf.accel.odr);
+ else
+ period_accel = U32_MAX;
+
+ if (period_gyro <= period_accel)
+ period = period_gyro;
+ else
+ period = period_accel;
+
+ st->fifo.period = period;
+}
+
+int inv_icm42600_buffer_set_fifo_en(struct inv_icm42600_state *st,
+ unsigned int fifo_en)
+{
+ unsigned int mask, val;
+ int ret;
+
+ /* update only FIFO EN bits */
+ mask = INV_ICM42600_FIFO_CONFIG1_TMST_FSYNC_EN |
+ INV_ICM42600_FIFO_CONFIG1_TEMP_EN |
+ INV_ICM42600_FIFO_CONFIG1_GYRO_EN |
+ INV_ICM42600_FIFO_CONFIG1_ACCEL_EN;
+
+ val = 0;
+ if (fifo_en & INV_ICM42600_SENSOR_GYRO)
+ val |= INV_ICM42600_FIFO_CONFIG1_GYRO_EN;
+ if (fifo_en & INV_ICM42600_SENSOR_ACCEL)
+ val |= INV_ICM42600_FIFO_CONFIG1_ACCEL_EN;
+ if (fifo_en & INV_ICM42600_SENSOR_TEMP)
+ val |= INV_ICM42600_FIFO_CONFIG1_TEMP_EN;
+
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_FIFO_CONFIG1,
+ mask, val);
+ if (ret)
+ return ret;
+
+ st->fifo.en = fifo_en;
+ inv_icm42600_buffer_update_fifo_period(st);
+
+ return 0;
+}
+
+static size_t inv_icm42600_get_packet_size(unsigned int fifo_en)
+{
+ size_t packet_size;
+
+ if ((fifo_en & INV_ICM42600_SENSOR_GYRO) &&
+ (fifo_en & INV_ICM42600_SENSOR_ACCEL))
+ packet_size = INV_ICM42600_FIFO_2SENSORS_PACKET_SIZE;
+ else
+ packet_size = INV_ICM42600_FIFO_1SENSOR_PACKET_SIZE;
+
+ return packet_size;
+}
+
+static unsigned int inv_icm42600_wm_truncate(unsigned int watermark,
+ size_t packet_size)
+{
+ size_t wm_size;
+ unsigned int wm;
+
+ wm_size = watermark * packet_size;
+ if (wm_size > INV_ICM42600_FIFO_WATERMARK_MAX)
+ wm_size = INV_ICM42600_FIFO_WATERMARK_MAX;
+
+ wm = wm_size / packet_size;
+
+ return wm;
+}
+
+int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st)
+{
+ size_t packet_size, wm_size;
+ unsigned int wm_gyro, wm_accel, watermark;
+ uint32_t period_gyro, period_accel, period;
+ int64_t latency_gyro, latency_accel, latency;
+ bool restore;
+ __le16 raw_wm;
+ int ret;
+
+ packet_size = inv_icm42600_get_packet_size(st->fifo.en);
+
+ /* get minimal latency, depending on sensor watermark and odr */
+ wm_gyro = inv_icm42600_wm_truncate(st->fifo.watermark.gyro,
+ packet_size);
+ wm_accel = inv_icm42600_wm_truncate(st->fifo.watermark.accel,
+ packet_size);
+ period_gyro = inv_icm42600_odr_to_period(st->conf.gyro.odr);
+ period_accel = inv_icm42600_odr_to_period(st->conf.accel.odr);
+ latency_gyro = (int64_t)period_gyro * (int64_t)wm_gyro;
+ latency_accel = (int64_t)period_accel * (int64_t)wm_accel;
+ if (latency_gyro == 0) {
+ latency = latency_accel;
+ watermark = wm_accel;
+ } else if (latency_accel == 0) {
+ latency = latency_gyro;
+ watermark = wm_gyro;
+ } else {
+ /* compute the smallest latency that is a multiple of both */
+ if (latency_gyro <= latency_accel) {
+ latency = latency_gyro;
+ latency -= latency_accel % latency_gyro;
+ } else {
+ latency = latency_accel;
+ latency -= latency_gyro % latency_accel;
+ }
+ /* use the shortest period */
+ if (period_gyro <= period_accel)
+ period = period_gyro;
+ else
+ period = period_accel;
+ /* all this works because periods are multiple of each others */
+ watermark = div_s64(latency, period);
+ if (watermark < 1)
+ watermark = 1;
+ }
+ wm_size = watermark * packet_size;
+
+ /* changing FIFO watermark requires to turn off watermark interrupt */
+ ret = regmap_update_bits_check(st->map, INV_ICM42600_REG_INT_SOURCE0,
+ INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
+ 0, &restore);
+ if (ret)
+ return ret;
+
+ raw_wm = INV_ICM42600_FIFO_WATERMARK_VAL(wm_size);
+ memcpy(st->buffer, &raw_wm, sizeof(raw_wm));
+ ret = regmap_bulk_write(st->map, INV_ICM42600_REG_FIFO_WATERMARK,
+ st->buffer, sizeof(raw_wm));
+ if (ret)
+ return ret;
+
+ /* restore watermark interrupt */
+ if (restore) {
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
+ INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
+ INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int inv_icm42600_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct device *dev = regmap_get_device(st->map);
+
+ pm_runtime_get_sync(dev);
+
+ return 0;
+}
+
+/*
+ * update_scan_mode callback is turning sensors on and setting data FIFO enable
+ * bits.
+ */
+static int inv_icm42600_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ /* exit if FIFO is already on */
+ if (st->fifo.on) {
+ ret = 0;
+ goto out_on;
+ }
+
+ /* set FIFO threshold interrupt */
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
+ INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
+ INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
+ if (ret)
+ goto out_unlock;
+
+ /* flush FIFO data */
+ ret = regmap_write(st->map, INV_ICM42600_REG_SIGNAL_PATH_RESET,
+ INV_ICM42600_SIGNAL_PATH_RESET_FIFO_FLUSH);
+ if (ret)
+ goto out_unlock;
+
+ /* set FIFO in streaming mode */
+ ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
+ INV_ICM42600_FIFO_CONFIG_STREAM);
+ if (ret)
+ goto out_unlock;
+
+ /* workaround: first read of FIFO count after reset is always 0 */
+ ret = regmap_bulk_read(st->map, INV_ICM42600_REG_FIFO_COUNT, st->buffer, 2);
+ if (ret)
+ goto out_unlock;
+
+out_on:
+ /* increase FIFO on counter */
+ st->fifo.on++;
+out_unlock:
+ mutex_unlock(&st->lock);
+ return ret;
+}
+
+static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ /* exit if there are several sensors using the FIFO */
+ if (st->fifo.on > 1) {
+ ret = 0;
+ goto out_off;
+ }
+
+ /* set FIFO in bypass mode */
+ ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
+ INV_ICM42600_FIFO_CONFIG_BYPASS);
+ if (ret)
+ goto out_unlock;
+
+ /* flush FIFO data */
+ ret = regmap_write(st->map, INV_ICM42600_REG_SIGNAL_PATH_RESET,
+ INV_ICM42600_SIGNAL_PATH_RESET_FIFO_FLUSH);
+ if (ret)
+ goto out_unlock;
+
+ /* disable FIFO threshold interrupt */
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
+ INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN, 0);
+ if (ret)
+ goto out_unlock;
+
+out_off:
+ /* decrease FIFO on counter */
+ st->fifo.on--;
+out_unlock:
+ mutex_unlock(&st->lock);
+ return ret;
+}
+
+static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct device *dev = regmap_get_device(st->map);
+ unsigned int sensor;
+ unsigned int *watermark;
+ struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
+ unsigned int sleep_temp = 0;
+ unsigned int sleep_sensor = 0;
+ unsigned int sleep;
+ int ret;
+
+ if (indio_dev == st->indio_gyro) {
+ sensor = INV_ICM42600_SENSOR_GYRO;
+ watermark = &st->fifo.watermark.gyro;
+ } else if (indio_dev == st->indio_accel) {
+ sensor = INV_ICM42600_SENSOR_ACCEL;
+ watermark = &st->fifo.watermark.accel;
+ } else {
+ return -EINVAL;
+ }
+
+ mutex_lock(&st->lock);
+
+ ret = inv_icm42600_buffer_set_fifo_en(st, st->fifo.en & ~sensor);
+ if (ret)
+ goto out_unlock;
+
+ *watermark = 0;
+ ret = inv_icm42600_buffer_update_watermark(st);
+ if (ret)
+ goto out_unlock;
+
+ conf.mode = INV_ICM42600_SENSOR_MODE_OFF;
+ if (sensor == INV_ICM42600_SENSOR_GYRO)
+ ret = inv_icm42600_set_gyro_conf(st, &conf, &sleep_sensor);
+ else
+ ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_sensor);
+ if (ret)
+ goto out_unlock;
+
+ /* if FIFO is off, turn temperature off */
+ if (!st->fifo.on)
+ ret = inv_icm42600_set_temp_conf(st, false, &sleep_temp);
+
+out_unlock:
+ mutex_unlock(&st->lock);
+
+ /* sleep maximum required time */
+ if (sleep_sensor > sleep_temp)
+ sleep = sleep_sensor;
+ else
+ sleep = sleep_temp;
+ if (sleep)
+ msleep(sleep);
+
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
+}
+
+const struct iio_buffer_setup_ops inv_icm42600_buffer_ops = {
+ .preenable = inv_icm42600_buffer_preenable,
+ .postenable = inv_icm42600_buffer_postenable,
+ .predisable = inv_icm42600_buffer_predisable,
+ .postdisable = inv_icm42600_buffer_postdisable,
+};
+
+int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
+ unsigned int max)
+{
+ size_t max_count;
+ __be16 *raw_fifo_count;
+ ssize_t i, size;
+ const void *accel, *gyro, *timestamp;
+ const int8_t *temp;
+ unsigned int odr;
+ int ret;
+
+ /* reset all samples counters */
+ st->fifo.count = 0;
+ st->fifo.nb.gyro = 0;
+ st->fifo.nb.accel = 0;
+ st->fifo.nb.total = 0;
+
+ /* compute maximum FIFO read size */
+ if (max == 0)
+ max_count = sizeof(st->fifo.data);
+ else
+ max_count = max * inv_icm42600_get_packet_size(st->fifo.en);
+
+ /* read FIFO count value */
+ raw_fifo_count = (__be16 *)st->buffer;
+ ret = regmap_bulk_read(st->map, INV_ICM42600_REG_FIFO_COUNT,
+ raw_fifo_count, sizeof(*raw_fifo_count));
+ if (ret)
+ return ret;
+ st->fifo.count = be16_to_cpup(raw_fifo_count);
+
+ /* check and clamp FIFO count value */
+ if (st->fifo.count == 0)
+ return 0;
+ if (st->fifo.count > max_count)
+ st->fifo.count = max_count;
+
+ /* read all FIFO data in internal buffer */
+ ret = regmap_noinc_read(st->map, INV_ICM42600_REG_FIFO_DATA,
+ st->fifo.data, st->fifo.count);
+ if (ret)
+ return ret;
+
+ /* compute number of samples for each sensor */
+ for (i = 0; i < st->fifo.count; i += size) {
+ size = inv_icm42600_fifo_decode_packet(&st->fifo.data[i],
+ &accel, &gyro, &temp, ×tamp, &odr);
+ if (size <= 0)
+ break;
+ if (gyro != NULL && inv_icm42600_fifo_is_data_valid(gyro))
+ st->fifo.nb.gyro++;
+ if (accel != NULL && inv_icm42600_fifo_is_data_valid(accel))
+ st->fifo.nb.accel++;
+ st->fifo.nb.total++;
+ }
+
+ return 0;
+}
+
+int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st)
+{
+ int ret;
+
+ if (st->fifo.nb.total == 0)
+ return 0;
+
+ if (st->fifo.nb.gyro > 0) {
+ ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro);
+ if (ret)
+ return ret;
+ }
+
+ if (st->fifo.nb.accel > 0) {
+ ret = inv_icm42600_accel_parse_fifo(st->indio_accel);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st,
+ unsigned int count)
+{
+ int ret;
+
+ ret = inv_icm42600_buffer_fifo_read(st, count);
+ if (ret)
+ return ret;
+
+ if (st->fifo.nb.total == 0)
+ return 0;
+
+ if (st->fifo.nb.gyro > 0) {
+ ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro);
+ if (ret)
+ return ret;
+ }
+
+ if (st->fifo.nb.accel > 0) {
+ ret = inv_icm42600_accel_parse_fifo(st->indio_accel);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int inv_icm42600_buffer_init(struct inv_icm42600_state *st)
+{
+ unsigned int val;
+ int ret;
+
+ /*
+ * Default FIFO configuration (bits 7 to 5)
+ * - use invalid value
+ * - FIFO count in bytes
+ * - FIFO count in big endian
+ */
+ val = INV_ICM42600_INTF_CONFIG0_FIFO_COUNT_ENDIAN;
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
+ GENMASK(7, 5), val);
+ if (ret)
+ return ret;
+
+ /*
+ * Enable FIFO partial read and continuous watermark interrupt.
+ * Disable all FIFO EN bits.
+ */
+ val = INV_ICM42600_FIFO_CONFIG1_RESUME_PARTIAL_RD |
+ INV_ICM42600_FIFO_CONFIG1_WM_GT_TH;
+ return regmap_update_bits(st->map, INV_ICM42600_REG_FIFO_CONFIG1,
+ GENMASK(6, 5) | GENMASK(3, 0), val);
+}
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
new file mode 100644
index 000000000000..de2a3949dcc7
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020 Invensense, Inc.
+ */
+
+#ifndef INV_ICM42600_BUFFER_H_
+#define INV_ICM42600_BUFFER_H_
+
+#include <linux/kernel.h>
+#include <linux/bits.h>
+
+struct inv_icm42600_state;
+
+#define INV_ICM42600_SENSOR_GYRO BIT(0)
+#define INV_ICM42600_SENSOR_ACCEL BIT(1)
+#define INV_ICM42600_SENSOR_TEMP BIT(2)
+
+/**
+ * struct inv_icm42600_fifo - FIFO state variables
+ * @on: reference counter for FIFO on.
+ * @en: bits field of INV_ICM42600_SENSOR_* for FIFO EN bits.
+ * @period: FIFO internal period.
+ * @watermark: watermark configuration values for accel and gyro.
+ * @count: number of bytes in the FIFO data buffer.
+ * @nb: gyro, accel and total samples in the FIFO data buffer.
+ * @data: FIFO data buffer aligned for DMA (2kB + 32 bytes of read cache).
+ */
+struct inv_icm42600_fifo {
+ unsigned int on;
+ unsigned int en;
+ uint32_t period;
+ struct {
+ unsigned int gyro;
+ unsigned int accel;
+ } watermark;
+ size_t count;
+ struct {
+ size_t gyro;
+ size_t accel;
+ size_t total;
+ } nb;
+ uint8_t data[2080] ____cacheline_aligned;
+};
+
+/* FIFO data packet */
+struct inv_icm42600_fifo_sensor_data {
+ __be16 x;
+ __be16 y;
+ __be16 z;
+} __packed;
+#define INV_ICM42600_FIFO_DATA_INVALID -32768
+
+static inline int16_t inv_icm42600_fifo_get_sensor_data(__be16 d)
+{
+ return be16_to_cpu(d);
+}
+
+static inline bool
+inv_icm42600_fifo_is_data_valid(const struct inv_icm42600_fifo_sensor_data *s)
+{
+ int16_t x, y, z;
+
+ x = inv_icm42600_fifo_get_sensor_data(s->x);
+ y = inv_icm42600_fifo_get_sensor_data(s->y);
+ z = inv_icm42600_fifo_get_sensor_data(s->z);
+
+ if (x == INV_ICM42600_FIFO_DATA_INVALID &&
+ y == INV_ICM42600_FIFO_DATA_INVALID &&
+ z == INV_ICM42600_FIFO_DATA_INVALID)
+ return false;
+
+ return true;
+}
+
+ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel,
+ const void **gyro, const int8_t **temp,
+ const void **timestamp, unsigned int *odr);
+
+extern const struct iio_buffer_setup_ops inv_icm42600_buffer_ops;
+
+int inv_icm42600_buffer_init(struct inv_icm42600_state *st);
+
+void inv_icm42600_buffer_update_fifo_period(struct inv_icm42600_state *st);
+
+int inv_icm42600_buffer_set_fifo_en(struct inv_icm42600_state *st,
+ unsigned int fifo_en);
+
+int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st);
+
+int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
+ unsigned int max);
+
+int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st);
+
+int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st,
+ unsigned int count);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index 246c1eb52231..6f1c1eb83953 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -18,6 +18,7 @@
#include <linux/iio/iio.h>
#include "inv_icm42600.h"
+#include "inv_icm42600_buffer.h"
static const struct regmap_range_cfg inv_icm42600_regmap_ranges[] = {
{
@@ -429,6 +430,18 @@ static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data)
if (status & INV_ICM42600_INT_STATUS_FIFO_FULL)
dev_warn(dev, "FIFO full data lost!\n");
+ /* FIFO threshold reached */
+ if (status & INV_ICM42600_INT_STATUS_FIFO_THS) {
+ ret = inv_icm42600_buffer_fifo_read(st, 0);
+ if (ret) {
+ dev_err(dev, "FIFO read error %d\n", ret);
+ goto out_unlock;
+ }
+ ret = inv_icm42600_buffer_fifo_parse(st);
+ if (ret)
+ dev_err(dev, "FIFO parsing error %d\n", ret);
+ }
+
out_unlock:
mutex_unlock(&st->lock);
return IRQ_HANDLED;
@@ -600,6 +613,10 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
if (ret)
return ret;
+ ret = inv_icm42600_buffer_init(st);
+ if (ret)
+ return ret;
+
ret = inv_icm42600_gyro_init(st);
if (ret)
return ret;
@@ -645,6 +662,14 @@ static int __maybe_unused inv_icm42600_suspend(struct device *dev)
goto out_unlock;
}
+ /* disable FIFO data streaming */
+ if (st->fifo.on) {
+ ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
+ INV_ICM42600_FIFO_CONFIG_BYPASS);
+ if (ret)
+ goto out_unlock;
+ }
+
ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
INV_ICM42600_SENSOR_MODE_OFF, false,
NULL);
@@ -684,6 +709,11 @@ static int __maybe_unused inv_icm42600_resume(struct device *dev)
if (ret)
goto out_unlock;
+ /* restore FIFO data streaming */
+ if (st->fifo.on)
+ ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
+ INV_ICM42600_FIFO_CONFIG_STREAM);
+
out_unlock:
mutex_unlock(&st->lock);
return ret;
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index 38654e0d217b..b05c33876b8d 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -11,9 +11,12 @@
#include <linux/delay.h>
#include <linux/math64.h>
#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
#include "inv_icm42600.h"
#include "inv_icm42600_temp.h"
+#include "inv_icm42600_buffer.h"
#define INV_ICM42600_GYRO_CHAN(_modifier, _index, _ext_info) \
{ \
@@ -64,6 +67,76 @@ static const struct iio_chan_spec inv_icm42600_gyro_channels[] = {
INV_ICM42600_TEMP_CHAN(INV_ICM42600_GYRO_SCAN_TEMP),
};
+/* IIO buffer data: 8 bytes */
+struct inv_icm42600_gyro_buffer {
+ struct inv_icm42600_fifo_sensor_data gyro;
+ int8_t temp;
+ uint8_t padding;
+};
+
+#define INV_ICM42600_SCAN_MASK_GYRO_3AXIS \
+ (BIT(INV_ICM42600_GYRO_SCAN_X) | \
+ BIT(INV_ICM42600_GYRO_SCAN_Y) | \
+ BIT(INV_ICM42600_GYRO_SCAN_Z))
+
+#define INV_ICM42600_SCAN_MASK_TEMP BIT(INV_ICM42600_GYRO_SCAN_TEMP)
+
+static const unsigned long inv_icm42600_gyro_scan_masks[] = {
+ /* 3-axis gyro + temperature */
+ INV_ICM42600_SCAN_MASK_GYRO_3AXIS | INV_ICM42600_SCAN_MASK_TEMP,
+ 0,
+};
+
+/* enable gyroscope sensor and FIFO write */
+static int inv_icm42600_gyro_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
+ unsigned int fifo_en = 0;
+ unsigned int sleep_gyro = 0;
+ unsigned int sleep_temp = 0;
+ unsigned int sleep;
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ if (*scan_mask & INV_ICM42600_SCAN_MASK_TEMP) {
+ /* enable temp sensor */
+ ret = inv_icm42600_set_temp_conf(st, true, &sleep_temp);
+ if (ret)
+ goto out_unlock;
+ fifo_en |= INV_ICM42600_SENSOR_TEMP;
+ }
+
+ if (*scan_mask & INV_ICM42600_SCAN_MASK_GYRO_3AXIS) {
+ /* enable gyro sensor */
+ conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
+ ret = inv_icm42600_set_gyro_conf(st, &conf, &sleep_gyro);
+ if (ret)
+ goto out_unlock;
+ fifo_en |= INV_ICM42600_SENSOR_GYRO;
+ }
+
+ /* update data FIFO write */
+ ret = inv_icm42600_buffer_set_fifo_en(st, fifo_en | st->fifo.en);
+ if (ret)
+ goto out_unlock;
+
+ ret = inv_icm42600_buffer_update_watermark(st);
+
+out_unlock:
+ mutex_unlock(&st->lock);
+ /* sleep maximum required time */
+ if (sleep_gyro > sleep_temp)
+ sleep = sleep_gyro;
+ else
+ sleep = sleep_temp;
+ if (sleep)
+ msleep(sleep);
+ return ret;
+}
+
static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st,
struct iio_chan_spec const *chan,
int16_t *val)
@@ -260,7 +333,12 @@ static int inv_icm42600_gyro_write_odr(struct inv_icm42600_state *st,
mutex_lock(&st->lock);
ret = inv_icm42600_set_gyro_conf(st, &conf, NULL);
+ if (ret)
+ goto out_unlock;
+ inv_icm42600_buffer_update_fifo_period(st);
+ inv_icm42600_buffer_update_watermark(st);
+out_unlock:
mutex_unlock(&st->lock);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
@@ -574,12 +652,51 @@ static int inv_icm42600_gyro_write_raw_get_fmt(struct iio_dev *indio_dev,
}
}
+static int inv_icm42600_gyro_hwfifo_set_watermark(struct iio_dev *indio_dev,
+ unsigned int val)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ st->fifo.watermark.gyro = val;
+ ret = inv_icm42600_buffer_update_watermark(st);
+
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int inv_icm42600_gyro_hwfifo_flush(struct iio_dev *indio_dev,
+ unsigned int count)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ if (count == 0)
+ return 0;
+
+ mutex_lock(&st->lock);
+
+ ret = inv_icm42600_buffer_hwfifo_flush(st, count);
+ if (!ret)
+ ret = st->fifo.nb.gyro;
+
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
static const struct iio_info inv_icm42600_gyro_info = {
.read_raw = inv_icm42600_gyro_read_raw,
.read_avail = inv_icm42600_gyro_read_avail,
.write_raw = inv_icm42600_gyro_write_raw,
.write_raw_get_fmt = inv_icm42600_gyro_write_raw_get_fmt,
.debugfs_reg_access = inv_icm42600_debugfs_reg,
+ .update_scan_mode = inv_icm42600_gyro_update_scan_mode,
+ .hwfifo_set_watermark = inv_icm42600_gyro_hwfifo_set_watermark,
+ .hwfifo_flush_to_buffer = inv_icm42600_gyro_hwfifo_flush,
};
int inv_icm42600_gyro_init(struct inv_icm42600_state *st)
@@ -587,6 +704,7 @@ int inv_icm42600_gyro_init(struct inv_icm42600_state *st)
struct device *dev = regmap_get_device(st->map);
const char *name;
struct iio_dev *indio_dev;
+ struct iio_buffer *buffer;
name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->name);
if (!name)
@@ -596,14 +714,54 @@ int inv_icm42600_gyro_init(struct inv_icm42600_state *st)
if (!indio_dev)
return -ENOMEM;
+ buffer = devm_iio_kfifo_allocate(dev);
+ if (!buffer)
+ return -ENOMEM;
+
iio_device_set_drvdata(indio_dev, st);
indio_dev->dev.parent = dev;
indio_dev->name = name;
indio_dev->info = &inv_icm42600_gyro_info;
- indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
indio_dev->channels = inv_icm42600_gyro_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_gyro_channels);
+ indio_dev->available_scan_masks = inv_icm42600_gyro_scan_masks;
+ indio_dev->setup_ops = &inv_icm42600_buffer_ops;
+
+ iio_device_attach_buffer(indio_dev, buffer);
st->indio_gyro = indio_dev;
return devm_iio_device_register(dev, st->indio_gyro);
}
+
+int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ ssize_t i, size;
+ const void *accel, *gyro, *timestamp;
+ const int8_t *temp;
+ unsigned int odr;
+ struct inv_icm42600_gyro_buffer buffer = {
+ .padding = 0,
+ };
+
+ /* parse all fifo packets */
+ for (i = 0; i < st->fifo.count; i += size) {
+ size = inv_icm42600_fifo_decode_packet(&st->fifo.data[i],
+ &accel, &gyro, &temp, ×tamp, &odr);
+ /* quit if error or FIFO is empty */
+ if (size <= 0)
+ return size;
+
+ /* skip packet if no gyro data or data is invalid */
+ if (gyro == NULL || !inv_icm42600_fifo_is_data_valid(gyro))
+ continue;
+
+ /* fill and push data buffer */
+ memcpy(&buffer.gyro, gyro, sizeof(buffer.gyro));
+ buffer.temp = temp ? *temp : 0;
+ iio_push_to_buffers(indio_dev, &buffer);
+ }
+
+ return 0;
+}
--
2.17.1
^ permalink raw reply related
* [PATCH v2 02/12] iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver
From: Jean-Baptiste Maneyrol @ 2020-05-27 18:57 UTC (permalink / raw)
To: jic23, robh+dt, robh, mchehab+huawei, davem, gregkh
Cc: linux-iio, devicetree, linux-kernel, Jean-Baptiste Maneyrol
In-Reply-To: <20200527185711.21331-1-jmaneyrol@invensense.com>
Add I2C driver for InvenSense ICM-426xxx devices.
Configure bus signal slew rates as indicated in the datasheet.
Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
.../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 100 ++++++++++++++++++
1 file changed, 100 insertions(+)
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
new file mode 100644
index 000000000000..4789cead23b3
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 InvenSense, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/property.h>
+
+#include "inv_icm42600.h"
+
+static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st)
+{
+ unsigned int mask, val;
+ int ret;
+
+ /* setup interface registers */
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6,
+ INV_ICM42600_INTF_CONFIG6_MASK,
+ INV_ICM42600_INTF_CONFIG6_I3C_EN);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4,
+ INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0);
+ if (ret)
+ return ret;
+
+ /* set slew rates for I2C and SPI */
+ mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK |
+ INV_ICM42600_DRIVE_CONFIG_SPI_MASK;
+ val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_12_36NS) |
+ INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_12_36NS);
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG,
+ mask, val);
+ if (ret)
+ return ret;
+
+ /* disable SPI bus */
+ return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
+ INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS);
+}
+
+static int inv_icm42600_probe(struct i2c_client *client)
+{
+ const void *match;
+ enum inv_icm42600_chip chip;
+ struct regmap *regmap;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
+ return -ENOTSUPP;
+
+ match = device_get_match_data(&client->dev);
+ if (!match)
+ return -EINVAL;
+ chip = (enum inv_icm42600_chip)match;
+
+ regmap = devm_regmap_init_i2c(client, &inv_icm42600_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return inv_icm42600_core_probe(regmap, chip, inv_icm42600_i2c_bus_setup);
+}
+
+static const struct of_device_id inv_icm42600_of_matches[] = {
+ {
+ .compatible = "invensense,icm42600",
+ .data = (void *)INV_CHIP_ICM42600,
+ }, {
+ .compatible = "invensense,icm42602",
+ .data = (void *)INV_CHIP_ICM42602,
+ }, {
+ .compatible = "invensense,icm42605",
+ .data = (void *)INV_CHIP_ICM42605,
+ }, {
+ .compatible = "invensense,icm42622",
+ .data = (void *)INV_CHIP_ICM42622,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches);
+
+static struct i2c_driver inv_icm42600_driver = {
+ .driver = {
+ .name = "inv-icm42600-i2c",
+ .of_match_table = inv_icm42600_of_matches,
+ .pm = &inv_icm42600_pm_ops,
+ },
+ .probe_new = inv_icm42600_probe,
+};
+module_i2c_driver(inv_icm42600_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-426xx I2C driver");
+MODULE_LICENSE("GPL");
--
2.17.1
^ permalink raw reply related
* [PATCH v2 03/12] iio: imu: inv_icm42600: add SPI driver for inv_icm42600 driver
From: Jean-Baptiste Maneyrol @ 2020-05-27 18:57 UTC (permalink / raw)
To: jic23, robh+dt, robh, mchehab+huawei, davem, gregkh
Cc: linux-iio, devicetree, linux-kernel, Jean-Baptiste Maneyrol
In-Reply-To: <20200527185711.21331-1-jmaneyrol@invensense.com>
Add SPI driver for InvenSense ICM-426xxx devices.
Configure bus signal slew rates as indicated in the datasheet.
Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
.../iio/imu/inv_icm42600/inv_icm42600_spi.c | 99 +++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
new file mode 100644
index 000000000000..a9c5e2fdbe2a
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 InvenSense, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/property.h>
+
+#include "inv_icm42600.h"
+
+static int inv_icm42600_spi_bus_setup(struct inv_icm42600_state *st)
+{
+ unsigned int mask, val;
+ int ret;
+
+ /* setup interface registers */
+ val = INV_ICM42600_INTF_CONFIG6_I3C_EN |
+ INV_ICM42600_INTF_CONFIG6_I3C_SDR_EN |
+ INV_ICM42600_INTF_CONFIG6_I3C_DDR_EN;
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG6,
+ INV_ICM42600_INTF_CONFIG6_MASK, val);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG4,
+ INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY, 0);
+ if (ret)
+ return ret;
+
+ /* set slew rates for I2C and SPI */
+ mask = INV_ICM42600_DRIVE_CONFIG_I2C_MASK |
+ INV_ICM42600_DRIVE_CONFIG_SPI_MASK;
+ val = INV_ICM42600_DRIVE_CONFIG_I2C(INV_ICM42600_SLEW_RATE_20_60NS) |
+ INV_ICM42600_DRIVE_CONFIG_SPI(INV_ICM42600_SLEW_RATE_INF_2NS);
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_DRIVE_CONFIG,
+ mask, val);
+ if (ret)
+ return ret;
+
+ /* disable i2c bus */
+ return regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
+ INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS);
+}
+
+static int inv_icm42600_probe(struct spi_device *spi)
+{
+ const void *match;
+ enum inv_icm42600_chip chip;
+ struct regmap *regmap;
+
+ match = device_get_match_data(&spi->dev);
+ if (!match)
+ return -EINVAL;
+ chip = (enum inv_icm42600_chip)match;
+
+ regmap = devm_regmap_init_spi(spi, &inv_icm42600_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return inv_icm42600_core_probe(regmap, chip, inv_icm42600_spi_bus_setup);
+}
+
+static const struct of_device_id inv_icm42600_of_matches[] = {
+ {
+ .compatible = "invensense,icm42600",
+ .data = (void *)INV_CHIP_ICM42600,
+ }, {
+ .compatible = "invensense,icm42602",
+ .data = (void *)INV_CHIP_ICM42602,
+ }, {
+ .compatible = "invensense,icm42605",
+ .data = (void *)INV_CHIP_ICM42605,
+ }, {
+ .compatible = "invensense,icm42622",
+ .data = (void *)INV_CHIP_ICM42622,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, inv_icm42600_of_matches);
+
+static struct spi_driver inv_icm42600_driver = {
+ .driver = {
+ .name = "inv-icm42600-spi",
+ .of_match_table = inv_icm42600_of_matches,
+ .pm = &inv_icm42600_pm_ops,
+ },
+ .probe = inv_icm42600_probe,
+};
+module_spi_driver(inv_icm42600_driver);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-426xx SPI driver");
+MODULE_LICENSE("GPL");
--
2.17.1
^ permalink raw reply related
* [PATCH v2 01/12] iio: imu: inv_icm42600: add core of new inv_icm42600 driver
From: Jean-Baptiste Maneyrol @ 2020-05-27 18:57 UTC (permalink / raw)
To: jic23, robh+dt, robh, mchehab+huawei, davem, gregkh
Cc: linux-iio, devicetree, linux-kernel, Jean-Baptiste Maneyrol
In-Reply-To: <20200527185711.21331-1-jmaneyrol@invensense.com>
Core component of a new driver for InvenSense ICM-426xx devices.
It includes registers definition, main probe/setup, and device
utility functions.
ICM-426xx devices are latest generation of 6-axis IMU,
gyroscope+accelerometer and temperature sensor. This device
includes a 2K FIFO, supports I2C/I3C/SPI, and provides
intelligent motion features like pedometer, tilt detection,
and tap detection.
Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com>
---
drivers/iio/imu/inv_icm42600/inv_icm42600.h | 372 ++++++++++
.../iio/imu/inv_icm42600/inv_icm42600_core.c | 635 ++++++++++++++++++
2 files changed, 1007 insertions(+)
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
new file mode 100644
index 000000000000..14c8ef152418
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -0,0 +1,372 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020 Invensense, Inc.
+ */
+
+#ifndef INV_ICM42600_H_
+#define INV_ICM42600_H_
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm.h>
+#include <linux/iio/iio.h>
+
+enum inv_icm42600_chip {
+ INV_CHIP_ICM42600,
+ INV_CHIP_ICM42602,
+ INV_CHIP_ICM42605,
+ INV_CHIP_ICM42622,
+ INV_CHIP_NB,
+};
+
+/* serial bus slew rates */
+enum inv_icm42600_slew_rate {
+ INV_ICM42600_SLEW_RATE_20_60NS,
+ INV_ICM42600_SLEW_RATE_12_36NS,
+ INV_ICM42600_SLEW_RATE_6_18NS,
+ INV_ICM42600_SLEW_RATE_4_12NS,
+ INV_ICM42600_SLEW_RATE_2_6NS,
+ INV_ICM42600_SLEW_RATE_INF_2NS,
+};
+
+enum inv_icm42600_sensor_mode {
+ INV_ICM42600_SENSOR_MODE_OFF,
+ INV_ICM42600_SENSOR_MODE_STANDBY,
+ INV_ICM42600_SENSOR_MODE_LOW_POWER,
+ INV_ICM42600_SENSOR_MODE_LOW_NOISE,
+ INV_ICM42600_SENSOR_MODE_NB,
+};
+
+/* gyroscope fullscale values */
+enum inv_icm42600_gyro_fs {
+ INV_ICM42600_GYRO_FS_2000DPS,
+ INV_ICM42600_GYRO_FS_1000DPS,
+ INV_ICM42600_GYRO_FS_500DPS,
+ INV_ICM42600_GYRO_FS_250DPS,
+ INV_ICM42600_GYRO_FS_125DPS,
+ INV_ICM42600_GYRO_FS_62_5DPS,
+ INV_ICM42600_GYRO_FS_31_25DPS,
+ INV_ICM42600_GYRO_FS_15_625DPS,
+ INV_ICM42600_GYRO_FS_NB,
+};
+
+/* accelerometer fullscale values */
+enum inv_icm42600_accel_fs {
+ INV_ICM42600_ACCEL_FS_16G,
+ INV_ICM42600_ACCEL_FS_8G,
+ INV_ICM42600_ACCEL_FS_4G,
+ INV_ICM42600_ACCEL_FS_2G,
+ INV_ICM42600_ACCEL_FS_NB,
+};
+
+/* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */
+enum inv_icm42600_odr {
+ INV_ICM42600_ODR_8KHZ_LN = 3,
+ INV_ICM42600_ODR_4KHZ_LN,
+ INV_ICM42600_ODR_2KHZ_LN,
+ INV_ICM42600_ODR_1KHZ_LN,
+ INV_ICM42600_ODR_200HZ,
+ INV_ICM42600_ODR_100HZ,
+ INV_ICM42600_ODR_50HZ,
+ INV_ICM42600_ODR_25HZ,
+ INV_ICM42600_ODR_12_5HZ,
+ INV_ICM42600_ODR_6_25HZ_LP,
+ INV_ICM42600_ODR_3_125HZ_LP,
+ INV_ICM42600_ODR_1_5625HZ_LP,
+ INV_ICM42600_ODR_500HZ,
+ INV_ICM42600_ODR_NB,
+};
+
+enum inv_icm42600_filter {
+ /* Low-Noise mode sensor data filter (3rd order filter by default) */
+ INV_ICM42600_FILTER_BW_ODR_DIV_2,
+
+ /* Low-Power mode sensor data filter (averaging) */
+ INV_ICM42600_FILTER_AVG_1X = 1,
+ INV_ICM42600_FILTER_AVG_16X = 6,
+};
+
+struct inv_icm42600_sensor_conf {
+ int mode;
+ int fs;
+ int odr;
+ int filter;
+};
+#define INV_ICM42600_SENSOR_CONF_INIT {-1, -1, -1, -1}
+
+struct inv_icm42600_conf {
+ struct inv_icm42600_sensor_conf gyro;
+ struct inv_icm42600_sensor_conf accel;
+ bool temp_en;
+};
+
+struct inv_icm42600_suspended {
+ enum inv_icm42600_sensor_mode gyro;
+ enum inv_icm42600_sensor_mode accel;
+ bool temp;
+};
+
+/**
+ * struct inv_icm42600_state - driver state variables
+ * @lock: lock for serializing multiple registers access.
+ * @chip: chip identifier.
+ * @name: chip name.
+ * @map: regmap pointer.
+ * @vdd_supply: VDD voltage regulator for the chip.
+ * @vddio_supply: I/O voltage regulator for the chip.
+ * @orientation: sensor chip orientation relative to main hardware.
+ * @conf: chip sensors configurations.
+ * @suspended: suspended sensors configuration.
+ */
+struct inv_icm42600_state {
+ struct mutex lock;
+ enum inv_icm42600_chip chip;
+ const char *name;
+ struct regmap *map;
+ struct regulator *vdd_supply;
+ struct regulator *vddio_supply;
+ struct iio_mount_matrix orientation;
+ struct inv_icm42600_conf conf;
+ struct inv_icm42600_suspended suspended;
+};
+
+/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
+
+/* Bank selection register, available in all banks */
+#define INV_ICM42600_REG_BANK_SEL 0x76
+#define INV_ICM42600_BANK_SEL_MASK GENMASK(2, 0)
+
+/* User bank 0 (MSB 0x00) */
+#define INV_ICM42600_REG_DEVICE_CONFIG 0x0011
+#define INV_ICM42600_DEVICE_CONFIG_SOFT_RESET BIT(0)
+
+#define INV_ICM42600_REG_DRIVE_CONFIG 0x0013
+#define INV_ICM42600_DRIVE_CONFIG_I2C_MASK GENMASK(5, 3)
+#define INV_ICM42600_DRIVE_CONFIG_I2C(_rate) \
+ FIELD_PREP(INV_ICM42600_DRIVE_CONFIG_I2C_MASK, (_rate))
+#define INV_ICM42600_DRIVE_CONFIG_SPI_MASK GENMASK(2, 0)
+#define INV_ICM42600_DRIVE_CONFIG_SPI(_rate) \
+ FIELD_PREP(INV_ICM42600_DRIVE_CONFIG_SPI_MASK, (_rate))
+
+#define INV_ICM42600_REG_INT_CONFIG 0x0014
+#define INV_ICM42600_INT_CONFIG_INT2_LATCHED BIT(5)
+#define INV_ICM42600_INT_CONFIG_INT2_PUSH_PULL BIT(4)
+#define INV_ICM42600_INT_CONFIG_INT2_ACTIVE_HIGH BIT(3)
+#define INV_ICM42600_INT_CONFIG_INT2_ACTIVE_LOW 0x00
+#define INV_ICM42600_INT_CONFIG_INT1_LATCHED BIT(2)
+#define INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL BIT(1)
+#define INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH BIT(0)
+#define INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW 0x00
+
+#define INV_ICM42600_REG_FIFO_CONFIG 0x0016
+#define INV_ICM42600_FIFO_CONFIG_MASK GENMASK(7, 6)
+#define INV_ICM42600_FIFO_CONFIG_BYPASS \
+ FIELD_PREP(INV_ICM42600_FIFO_CONFIG_MASK, 0)
+#define INV_ICM42600_FIFO_CONFIG_STREAM \
+ FIELD_PREP(INV_ICM42600_FIFO_CONFIG_MASK, 1)
+#define INV_ICM42600_FIFO_CONFIG_STOP_ON_FULL \
+ FIELD_PREP(INV_ICM42600_FIFO_CONFIG_MASK, 2)
+
+/* all sensor data are 16 bits (2 registers wide) in big-endian */
+#define INV_ICM42600_REG_TEMP_DATA 0x001D
+#define INV_ICM42600_REG_ACCEL_DATA_X 0x001F
+#define INV_ICM42600_REG_ACCEL_DATA_Y 0x0021
+#define INV_ICM42600_REG_ACCEL_DATA_Z 0x0023
+#define INV_ICM42600_REG_GYRO_DATA_X 0x0025
+#define INV_ICM42600_REG_GYRO_DATA_Y 0x0027
+#define INV_ICM42600_REG_GYRO_DATA_Z 0x0029
+#define INV_ICM42600_DATA_INVALID -32768
+
+#define INV_ICM42600_REG_INT_STATUS 0x002D
+#define INV_ICM42600_INT_STATUS_UI_FSYNC BIT(6)
+#define INV_ICM42600_INT_STATUS_PLL_RDY BIT(5)
+#define INV_ICM42600_INT_STATUS_RESET_DONE BIT(4)
+#define INV_ICM42600_INT_STATUS_DATA_RDY BIT(3)
+#define INV_ICM42600_INT_STATUS_FIFO_THS BIT(2)
+#define INV_ICM42600_INT_STATUS_FIFO_FULL BIT(1)
+#define INV_ICM42600_INT_STATUS_AGC_RDY BIT(0)
+
+/*
+ * FIFO access registers
+ * FIFO count is 16 bits (2 registers) big-endian
+ * FIFO data is a continuous read register to read FIFO content
+ */
+#define INV_ICM42600_REG_FIFO_COUNT 0x002E
+#define INV_ICM42600_REG_FIFO_DATA 0x0030
+
+#define INV_ICM42600_REG_SIGNAL_PATH_RESET 0x004B
+#define INV_ICM42600_SIGNAL_PATH_RESET_DMP_INIT_EN BIT(6)
+#define INV_ICM42600_SIGNAL_PATH_RESET_DMP_MEM_RESET BIT(5)
+#define INV_ICM42600_SIGNAL_PATH_RESET_RESET BIT(3)
+#define INV_ICM42600_SIGNAL_PATH_RESET_TMST_STROBE BIT(2)
+#define INV_ICM42600_SIGNAL_PATH_RESET_FIFO_FLUSH BIT(1)
+
+/* default configuration: all data big-endian and fifo count in bytes */
+#define INV_ICM42600_REG_INTF_CONFIG0 0x004C
+#define INV_ICM42600_INTF_CONFIG0_FIFO_HOLD_LAST_DATA BIT(7)
+#define INV_ICM42600_INTF_CONFIG0_FIFO_COUNT_REC BIT(6)
+#define INV_ICM42600_INTF_CONFIG0_FIFO_COUNT_ENDIAN BIT(5)
+#define INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN BIT(4)
+#define INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK GENMASK(1, 0)
+#define INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS \
+ FIELD_PREP(INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, 2)
+#define INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS \
+ FIELD_PREP(INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, 3)
+
+#define INV_ICM42600_REG_INTF_CONFIG1 0x004D
+#define INV_ICM42600_INTF_CONFIG1_ACCEL_LP_CLK_RC BIT(3)
+
+#define INV_ICM42600_REG_PWR_MGMT0 0x004E
+#define INV_ICM42600_PWR_MGMT0_TEMP_DIS BIT(5)
+#define INV_ICM42600_PWR_MGMT0_IDLE BIT(4)
+#define INV_ICM42600_PWR_MGMT0_GYRO(_mode) \
+ FIELD_PREP(GENMASK(3, 2), (_mode))
+#define INV_ICM42600_PWR_MGMT0_ACCEL(_mode) \
+ FIELD_PREP(GENMASK(1, 0), (_mode))
+
+#define INV_ICM42600_REG_GYRO_CONFIG0 0x004F
+#define INV_ICM42600_GYRO_CONFIG0_FS(_fs) \
+ FIELD_PREP(GENMASK(7, 5), (_fs))
+#define INV_ICM42600_GYRO_CONFIG0_ODR(_odr) \
+ FIELD_PREP(GENMASK(3, 0), (_odr))
+
+#define INV_ICM42600_REG_ACCEL_CONFIG0 0x0050
+#define INV_ICM42600_ACCEL_CONFIG0_FS(_fs) \
+ FIELD_PREP(GENMASK(7, 5), (_fs))
+#define INV_ICM42600_ACCEL_CONFIG0_ODR(_odr) \
+ FIELD_PREP(GENMASK(3, 0), (_odr))
+
+#define INV_ICM42600_REG_GYRO_ACCEL_CONFIG0 0x0052
+#define INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(_f) \
+ FIELD_PREP(GENMASK(7, 4), (_f))
+#define INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(_f) \
+ FIELD_PREP(GENMASK(3, 0), (_f))
+
+#define INV_ICM42600_REG_TMST_CONFIG 0x0054
+#define INV_ICM42600_TMST_CONFIG_MASK GENMASK(4, 0)
+#define INV_ICM42600_TMST_CONFIG_TMST_TO_REGS_EN BIT(4)
+#define INV_ICM42600_TMST_CONFIG_TMST_RES_16US BIT(3)
+#define INV_ICM42600_TMST_CONFIG_TMST_DELTA_EN BIT(2)
+#define INV_ICM42600_TMST_CONFIG_TMST_FSYNC_EN BIT(1)
+#define INV_ICM42600_TMST_CONFIG_TMST_EN BIT(0)
+
+#define INV_ICM42600_REG_FIFO_CONFIG1 0x005F
+#define INV_ICM42600_FIFO_CONFIG1_RESUME_PARTIAL_RD BIT(6)
+#define INV_ICM42600_FIFO_CONFIG1_WM_GT_TH BIT(5)
+#define INV_ICM42600_FIFO_CONFIG1_TMST_FSYNC_EN BIT(3)
+#define INV_ICM42600_FIFO_CONFIG1_TEMP_EN BIT(2)
+#define INV_ICM42600_FIFO_CONFIG1_GYRO_EN BIT(1)
+#define INV_ICM42600_FIFO_CONFIG1_ACCEL_EN BIT(0)
+
+/* FIFO watermark is 16 bits (2 registers wide) in little-endian */
+#define INV_ICM42600_REG_FIFO_WATERMARK 0x0060
+#define INV_ICM42600_FIFO_WATERMARK_VAL(_wm) \
+ cpu_to_le16((_wm) & GENMASK(11, 0))
+/* FIFO is 2048 bytes, let 12 samples for reading latency */
+#define INV_ICM42600_FIFO_WATERMARK_MAX (2048 - 12 * 16)
+
+#define INV_ICM42600_REG_INT_CONFIG1 0x0064
+#define INV_ICM42600_INT_CONFIG1_TPULSE_DURATION BIT(6)
+#define INV_ICM42600_INT_CONFIG1_TDEASSERT_DISABLE BIT(5)
+#define INV_ICM42600_INT_CONFIG1_ASYNC_RESET BIT(4)
+
+#define INV_ICM42600_REG_INT_SOURCE0 0x0065
+#define INV_ICM42600_INT_SOURCE0_UI_FSYNC_INT1_EN BIT(6)
+#define INV_ICM42600_INT_SOURCE0_PLL_RDY_INT1_EN BIT(5)
+#define INV_ICM42600_INT_SOURCE0_RESET_DONE_INT1_EN BIT(4)
+#define INV_ICM42600_INT_SOURCE0_UI_DRDY_INT1_EN BIT(3)
+#define INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN BIT(2)
+#define INV_ICM42600_INT_SOURCE0_FIFO_FULL_INT1_EN BIT(1)
+#define INV_ICM42600_INT_SOURCE0_UI_AGC_RDY_INT1_EN BIT(0)
+
+#define INV_ICM42600_REG_WHOAMI 0x0075
+#define INV_ICM42600_WHOAMI_ICM42600 0x40
+#define INV_ICM42600_WHOAMI_ICM42602 0x41
+#define INV_ICM42600_WHOAMI_ICM42605 0x42
+#define INV_ICM42600_WHOAMI_ICM42622 0x46
+
+/* User bank 1 (MSB 0x10) */
+#define INV_ICM42600_REG_SENSOR_CONFIG0 0x1003
+#define INV_ICM42600_SENSOR_CONFIG0_ZG_DISABLE BIT(5)
+#define INV_ICM42600_SENSOR_CONFIG0_YG_DISABLE BIT(4)
+#define INV_ICM42600_SENSOR_CONFIG0_XG_DISABLE BIT(3)
+#define INV_ICM42600_SENSOR_CONFIG0_ZA_DISABLE BIT(2)
+#define INV_ICM42600_SENSOR_CONFIG0_YA_DISABLE BIT(1)
+#define INV_ICM42600_SENSOR_CONFIG0_XA_DISABLE BIT(0)
+
+/* Timestamp value is 20 bits (3 registers) in little-endian */
+#define INV_ICM42600_REG_TMSTVAL 0x1062
+#define INV_ICM42600_TMSTVAL_MASK GENMASK(19, 0)
+
+#define INV_ICM42600_REG_INTF_CONFIG4 0x107A
+#define INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLY BIT(6)
+#define INV_ICM42600_INTF_CONFIG4_SPI_AP_4WIRE BIT(1)
+
+#define INV_ICM42600_REG_INTF_CONFIG6 0x107C
+#define INV_ICM42600_INTF_CONFIG6_MASK GENMASK(4, 0)
+#define INV_ICM42600_INTF_CONFIG6_I3C_EN BIT(4)
+#define INV_ICM42600_INTF_CONFIG6_I3C_IBI_BYTE_EN BIT(3)
+#define INV_ICM42600_INTF_CONFIG6_I3C_IBI_EN BIT(2)
+#define INV_ICM42600_INTF_CONFIG6_I3C_DDR_EN BIT(1)
+#define INV_ICM42600_INTF_CONFIG6_I3C_SDR_EN BIT(0)
+
+/* User bank 4 (MSB 0x40) */
+#define INV_ICM42600_REG_INT_SOURCE8 0x404F
+#define INV_ICM42600_INT_SOURCE8_FSYNC_IBI_EN BIT(5)
+#define INV_ICM42600_INT_SOURCE8_PLL_RDY_IBI_EN BIT(4)
+#define INV_ICM42600_INT_SOURCE8_UI_DRDY_IBI_EN BIT(3)
+#define INV_ICM42600_INT_SOURCE8_FIFO_THS_IBI_EN BIT(2)
+#define INV_ICM42600_INT_SOURCE8_FIFO_FULL_IBI_EN BIT(1)
+#define INV_ICM42600_INT_SOURCE8_AGC_RDY_IBI_EN BIT(0)
+
+#define INV_ICM42600_REG_OFFSET_USER0 0x4077
+#define INV_ICM42600_REG_OFFSET_USER1 0x4078
+#define INV_ICM42600_REG_OFFSET_USER2 0x4079
+#define INV_ICM42600_REG_OFFSET_USER3 0x407A
+#define INV_ICM42600_REG_OFFSET_USER4 0x407B
+#define INV_ICM42600_REG_OFFSET_USER5 0x407C
+#define INV_ICM42600_REG_OFFSET_USER6 0x407D
+#define INV_ICM42600_REG_OFFSET_USER7 0x407E
+#define INV_ICM42600_REG_OFFSET_USER8 0x407F
+
+/* Sleep times required by the driver */
+#define INV_ICM42600_POWER_UP_TIME_MS 100
+#define INV_ICM42600_RESET_TIME_MS 1
+#define INV_ICM42600_ACCEL_STARTUP_TIME_MS 20
+#define INV_ICM42600_GYRO_STARTUP_TIME_MS 60
+#define INV_ICM42600_GYRO_STOP_TIME_MS 150
+#define INV_ICM42600_TEMP_STARTUP_TIME_MS 14
+#define INV_ICM42600_SUSPEND_DELAY_MS 2000
+
+typedef int (*inv_icm42600_bus_setup)(struct inv_icm42600_state *);
+
+extern const struct regmap_config inv_icm42600_regmap_config;
+extern const struct dev_pm_ops inv_icm42600_pm_ops;
+
+const struct iio_mount_matrix *
+inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan);
+
+uint32_t inv_icm42600_odr_to_period(enum inv_icm42600_odr odr);
+
+int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
+ struct inv_icm42600_sensor_conf *conf,
+ unsigned int *sleep_ms);
+
+int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st,
+ struct inv_icm42600_sensor_conf *conf,
+ unsigned int *sleep_ms);
+
+int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
+ unsigned int *sleep_ms);
+
+int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval);
+
+int inv_icm42600_core_probe(struct regmap *regmap, int chip,
+ inv_icm42600_bus_setup bus_setup);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
new file mode 100644
index 000000000000..81b171d6782c
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -0,0 +1,635 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Invensense, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+
+#include "inv_icm42600.h"
+
+static const struct regmap_range_cfg inv_icm42600_regmap_ranges[] = {
+ {
+ .name = "user banks",
+ .range_min = 0x0000,
+ .range_max = 0x4FFF,
+ .selector_reg = INV_ICM42600_REG_BANK_SEL,
+ .selector_mask = INV_ICM42600_BANK_SEL_MASK,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 0x1000,
+ },
+};
+
+const struct regmap_config inv_icm42600_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x4FFF,
+ .ranges = inv_icm42600_regmap_ranges,
+ .num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges),
+};
+EXPORT_SYMBOL_GPL(inv_icm42600_regmap_config);
+
+struct inv_icm42600_hw {
+ uint8_t whoami;
+ const char *name;
+ const struct inv_icm42600_conf *conf;
+};
+
+/* chip initial default configuration */
+static const struct inv_icm42600_conf inv_icm42600_default_conf = {
+ .gyro = {
+ .mode = INV_ICM42600_SENSOR_MODE_OFF,
+ .fs = INV_ICM42600_GYRO_FS_2000DPS,
+ .odr = INV_ICM42600_ODR_50HZ,
+ .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
+ },
+ .accel = {
+ .mode = INV_ICM42600_SENSOR_MODE_OFF,
+ .fs = INV_ICM42600_ACCEL_FS_16G,
+ .odr = INV_ICM42600_ODR_50HZ,
+ .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
+ },
+ .temp_en = false,
+};
+
+static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = {
+ [INV_CHIP_ICM42600] = {
+ .whoami = INV_ICM42600_WHOAMI_ICM42600,
+ .name = "icm42600",
+ .conf = &inv_icm42600_default_conf,
+ },
+ [INV_CHIP_ICM42602] = {
+ .whoami = INV_ICM42600_WHOAMI_ICM42602,
+ .name = "icm42602",
+ .conf = &inv_icm42600_default_conf,
+ },
+ [INV_CHIP_ICM42605] = {
+ .whoami = INV_ICM42600_WHOAMI_ICM42605,
+ .name = "icm42605",
+ .conf = &inv_icm42600_default_conf,
+ },
+ [INV_CHIP_ICM42622] = {
+ .whoami = INV_ICM42600_WHOAMI_ICM42622,
+ .name = "icm42622",
+ .conf = &inv_icm42600_default_conf,
+ },
+};
+
+const struct iio_mount_matrix *
+inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ const struct inv_icm42600_state *st =
+ iio_device_get_drvdata((struct iio_dev *)indio_dev);
+
+ return &st->orientation;
+}
+
+uint32_t inv_icm42600_odr_to_period(enum inv_icm42600_odr odr)
+{
+ static uint32_t odr_periods[INV_ICM42600_ODR_NB] = {
+ /* reserved values */
+ 0, 0, 0,
+ /* 8kHz */
+ 125000,
+ /* 4kHz */
+ 250000,
+ /* 2kHz */
+ 500000,
+ /* 1kHz */
+ 1000000,
+ /* 200Hz */
+ 5000000,
+ /* 100Hz */
+ 10000000,
+ /* 50Hz */
+ 20000000,
+ /* 25Hz */
+ 40000000,
+ /* 12.5Hz */
+ 80000000,
+ /* 6.25Hz */
+ 160000000,
+ /* 3.125Hz */
+ 320000000,
+ /* 1.5625Hz */
+ 640000000,
+ /* 500Hz */
+ 2000000,
+ };
+
+ return odr_periods[odr];
+}
+
+static int inv_icm42600_set_pwr_mgmt0(struct inv_icm42600_state *st,
+ enum inv_icm42600_sensor_mode gyro,
+ enum inv_icm42600_sensor_mode accel,
+ bool temp, unsigned int *sleep_ms)
+{
+ enum inv_icm42600_sensor_mode oldgyro = st->conf.gyro.mode;
+ enum inv_icm42600_sensor_mode oldaccel = st->conf.accel.mode;
+ bool oldtemp = st->conf.temp_en;
+ unsigned int sleepval;
+ unsigned int val;
+ int ret;
+
+ /* if nothing changed, exit */
+ if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
+ return 0;
+
+ val = INV_ICM42600_PWR_MGMT0_GYRO(gyro) |
+ INV_ICM42600_PWR_MGMT0_ACCEL(accel);
+ if (!temp)
+ val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS;
+ ret = regmap_write(st->map, INV_ICM42600_REG_PWR_MGMT0, val);
+ if (ret)
+ return ret;
+
+ st->conf.gyro.mode = gyro;
+ st->conf.accel.mode = accel;
+ st->conf.temp_en = temp;
+
+ /* compute required wait time for sensors to stabilize */
+ sleepval = 0;
+ /* temperature stabilization time */
+ if (temp && !oldtemp) {
+ if (sleepval < INV_ICM42600_TEMP_STARTUP_TIME_MS)
+ sleepval = INV_ICM42600_TEMP_STARTUP_TIME_MS;
+ }
+ /* accel startup time */
+ if (accel != oldaccel && oldaccel == INV_ICM42600_SENSOR_MODE_OFF) {
+ /* block any register write for at least 200 µs */
+ usleep_range(200, 300);
+ if (sleepval < INV_ICM42600_ACCEL_STARTUP_TIME_MS)
+ sleepval = INV_ICM42600_ACCEL_STARTUP_TIME_MS;
+ }
+ if (gyro != oldgyro) {
+ /* gyro startup time */
+ if (oldgyro == INV_ICM42600_SENSOR_MODE_OFF) {
+ /* block any register write for at least 200 µs */
+ usleep_range(200, 300);
+ if (sleepval < INV_ICM42600_GYRO_STARTUP_TIME_MS)
+ sleepval = INV_ICM42600_GYRO_STARTUP_TIME_MS;
+ /* gyro stop time */
+ } else if (gyro == INV_ICM42600_SENSOR_MODE_OFF) {
+ if (sleepval < INV_ICM42600_GYRO_STOP_TIME_MS)
+ sleepval = INV_ICM42600_GYRO_STOP_TIME_MS;
+ }
+ }
+
+ /* deferred sleep value if sleep pointer is provided or direct sleep */
+ if (sleep_ms)
+ *sleep_ms = sleepval;
+ else if (sleepval)
+ msleep(sleepval);
+
+ return 0;
+}
+
+int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
+ struct inv_icm42600_sensor_conf *conf,
+ unsigned int *sleep_ms)
+{
+ struct inv_icm42600_sensor_conf *oldconf = &st->conf.accel;
+ unsigned int val;
+ int ret;
+
+ /* Sanitize missing values with current values */
+ if (conf->mode < 0)
+ conf->mode = oldconf->mode;
+ if (conf->fs < 0)
+ conf->fs = oldconf->fs;
+ if (conf->odr < 0)
+ conf->odr = oldconf->odr;
+ if (conf->filter < 0)
+ conf->filter = oldconf->filter;
+
+ /* set ACCEL_CONFIG0 register (accel fullscale & odr) */
+ if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+ val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->fs) |
+ INV_ICM42600_ACCEL_CONFIG0_ODR(conf->odr);
+ ret = regmap_write(st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val);
+ if (ret)
+ return ret;
+ oldconf->fs = conf->fs;
+ oldconf->odr = conf->odr;
+ }
+
+ /* set GYRO_ACCEL_CONFIG0 register (accel filter) */
+ if (conf->filter != oldconf->filter) {
+ val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->filter) |
+ INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(st->conf.gyro.filter);
+ ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
+ if (ret)
+ return ret;
+ oldconf->filter = conf->filter;
+ }
+
+ /* set PWR_MGMT0 register (accel sensor mode) */
+ return inv_icm42600_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode,
+ st->conf.temp_en, sleep_ms);
+}
+
+int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st,
+ struct inv_icm42600_sensor_conf *conf,
+ unsigned int *sleep_ms)
+{
+ struct inv_icm42600_sensor_conf *oldconf = &st->conf.gyro;
+ unsigned int val;
+ int ret;
+
+ /* sanitize missing values with current values */
+ if (conf->mode < 0)
+ conf->mode = oldconf->mode;
+ if (conf->fs < 0)
+ conf->fs = oldconf->fs;
+ if (conf->odr < 0)
+ conf->odr = oldconf->odr;
+ if (conf->filter < 0)
+ conf->filter = oldconf->filter;
+
+ /* set GYRO_CONFIG0 register (gyro fullscale & odr) */
+ if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+ val = INV_ICM42600_GYRO_CONFIG0_FS(conf->fs) |
+ INV_ICM42600_GYRO_CONFIG0_ODR(conf->odr);
+ ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_CONFIG0, val);
+ if (ret)
+ return ret;
+ oldconf->fs = conf->fs;
+ oldconf->odr = conf->odr;
+ }
+
+ /* set GYRO_ACCEL_CONFIG0 register (gyro filter) */
+ if (conf->filter != oldconf->filter) {
+ val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(st->conf.accel.filter) |
+ INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->filter);
+ ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
+ if (ret)
+ return ret;
+ oldconf->filter = conf->filter;
+ }
+
+ /* set PWR_MGMT0 register (gyro sensor mode) */
+ return inv_icm42600_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode,
+ st->conf.temp_en, sleep_ms);
+
+ return 0;
+}
+
+int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
+ unsigned int *sleep_ms)
+{
+ return inv_icm42600_set_pwr_mgmt0(st, st->conf.gyro.mode,
+ st->conf.accel.mode, enable,
+ sleep_ms);
+}
+
+int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ if (readval)
+ ret = regmap_read(st->map, reg, readval);
+ else
+ ret = regmap_write(st->map, reg, writeval);
+
+ mutex_unlock(&st->lock);
+
+ return ret;
+}
+
+static int inv_icm42600_set_conf(struct inv_icm42600_state *st,
+ const struct inv_icm42600_conf *conf)
+{
+ unsigned int val;
+ int ret;
+
+ /* set PWR_MGMT0 register (gyro & accel sensor mode, temp enabled) */
+ val = INV_ICM42600_PWR_MGMT0_GYRO(conf->gyro.mode) |
+ INV_ICM42600_PWR_MGMT0_ACCEL(conf->accel.mode);
+ if (!conf->temp_en)
+ val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS;
+ ret = regmap_write(st->map, INV_ICM42600_REG_PWR_MGMT0, val);
+ if (ret)
+ return ret;
+
+ /* set GYRO_CONFIG0 register (gyro fullscale & odr) */
+ val = INV_ICM42600_GYRO_CONFIG0_FS(conf->gyro.fs) |
+ INV_ICM42600_GYRO_CONFIG0_ODR(conf->gyro.odr);
+ ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ /* set ACCEL_CONFIG0 register (accel fullscale & odr) */
+ val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->accel.fs) |
+ INV_ICM42600_ACCEL_CONFIG0_ODR(conf->accel.odr);
+ ret = regmap_write(st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ /* set GYRO_ACCEL_CONFIG0 register (gyro & accel filters) */
+ val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->accel.filter) |
+ INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->gyro.filter);
+ ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ /* update internal conf */
+ st->conf = *conf;
+
+ return 0;
+}
+
+/**
+ * inv_icm42600_setup() - check and setup chip
+ * @st: driver internal state
+ * @bus_setup: callback for setting up bus specific registers
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int inv_icm42600_setup(struct inv_icm42600_state *st,
+ inv_icm42600_bus_setup bus_setup)
+{
+ const struct inv_icm42600_hw *hw = &inv_icm42600_hw[st->chip];
+ const struct device *dev = regmap_get_device(st->map);
+ unsigned int val;
+ int ret;
+
+ /* check chip self-identification value */
+ ret = regmap_read(st->map, INV_ICM42600_REG_WHOAMI, &val);
+ if (ret)
+ return ret;
+ if (val != hw->whoami) {
+ dev_err(dev, "invalid whoami %#02x expected %#02x (%s)\n",
+ val, hw->whoami, hw->name);
+ return -ENODEV;
+ }
+ st->name = hw->name;
+
+ /* reset to make sure previous state are not there */
+ ret = regmap_write(st->map, INV_ICM42600_REG_DEVICE_CONFIG,
+ INV_ICM42600_DEVICE_CONFIG_SOFT_RESET);
+ if (ret)
+ return ret;
+ msleep(INV_ICM42600_RESET_TIME_MS);
+
+ ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &val);
+ if (ret)
+ return ret;
+ if (!(val & INV_ICM42600_INT_STATUS_RESET_DONE)) {
+ dev_err(dev, "reset error, reset done bit not set\n");
+ return -ENODEV;
+ }
+
+ /* set chip bus configuration */
+ ret = bus_setup(st);
+ if (ret)
+ return ret;
+
+ /* sensor data in big-endian (default) */
+ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
+ INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN,
+ INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
+ if (ret)
+ return ret;
+
+ return inv_icm42600_set_conf(st, hw->conf);
+}
+
+static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st)
+{
+ int ret;
+
+ ret = regulator_enable(st->vddio_supply);
+ if (ret)
+ return ret;
+
+ /* wait a little for supply ramp */
+ usleep_range(3000, 4000);
+
+ return 0;
+}
+
+static void inv_icm42600_disable_vdd_reg(void *_data)
+{
+ struct inv_icm42600_state *st = _data;
+ const struct device *dev = regmap_get_device(st->map);
+ int ret;
+
+ ret = regulator_disable(st->vdd_supply);
+ if (ret)
+ dev_err(dev, "failed to disable vdd error %d\n", ret);
+}
+
+static void inv_icm42600_disable_vddio_reg(void *_data)
+{
+ struct inv_icm42600_state *st = _data;
+ const struct device *dev = regmap_get_device(st->map);
+ int ret;
+
+ ret = regulator_disable(st->vddio_supply);
+ if (ret)
+ dev_err(dev, "failed to disable vddio error %d\n", ret);
+}
+
+static void inv_icm42600_disable_pm(void *_data)
+{
+ struct device *dev = _data;
+
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+}
+
+int inv_icm42600_core_probe(struct regmap *regmap, int chip,
+ inv_icm42600_bus_setup bus_setup)
+{
+ struct device *dev = regmap_get_device(regmap);
+ struct inv_icm42600_state *st;
+ int ret;
+
+ if (chip < 0 || chip >= INV_CHIP_NB) {
+ dev_err(dev, "invalid chip = %d\n", chip);
+ return -ENODEV;
+ }
+
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, st);
+ mutex_init(&st->lock);
+ st->chip = chip;
+ st->map = regmap;
+
+ ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation);
+ if (ret) {
+ dev_err(dev, "failed to retrieve mounting matrix %d\n", ret);
+ return ret;
+ }
+
+ st->vdd_supply = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(st->vdd_supply))
+ return PTR_ERR(st->vdd_supply);
+
+ st->vddio_supply = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(st->vddio_supply))
+ return PTR_ERR(st->vddio_supply);
+
+ ret = regulator_enable(st->vdd_supply);
+ if (ret)
+ return ret;
+ msleep(INV_ICM42600_POWER_UP_TIME_MS);
+
+ ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vdd_reg, st);
+ if (ret)
+ return ret;
+
+ ret = inv_icm42600_enable_regulator_vddio(st);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vddio_reg, st);
+ if (ret)
+ return ret;
+
+ /* setup chip registers */
+ ret = inv_icm42600_setup(st, bus_setup);
+ if (ret)
+ return ret;
+
+ /* setup runtime power management */
+ ret = pm_runtime_set_active(dev);
+ if (ret)
+ return ret;
+ pm_runtime_get_noresume(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_set_autosuspend_delay(dev, INV_ICM42600_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_put(dev);
+
+ return devm_add_action_or_reset(dev, inv_icm42600_disable_pm, dev);
+}
+EXPORT_SYMBOL_GPL(inv_icm42600_core_probe);
+
+/*
+ * Suspend saves sensors state and turns everything off.
+ * Check first if runtime suspend has not already done the job.
+ */
+static int __maybe_unused inv_icm42600_suspend(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ st->suspended.gyro = st->conf.gyro.mode;
+ st->suspended.accel = st->conf.accel.mode;
+ st->suspended.temp = st->conf.temp_en;
+ if (pm_runtime_suspended(dev)) {
+ ret = 0;
+ goto out_unlock;
+ }
+
+ ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
+ INV_ICM42600_SENSOR_MODE_OFF, false,
+ NULL);
+ if (ret)
+ goto out_unlock;
+
+ regulator_disable(st->vddio_supply);
+
+out_unlock:
+ mutex_unlock(&st->lock);
+ return ret;
+}
+
+/*
+ * System resume gets the system back on and restores the sensors state.
+ * Manually put runtime power management in system active state.
+ */
+static int __maybe_unused inv_icm42600_resume(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ ret = inv_icm42600_enable_regulator_vddio(st);
+ if (ret)
+ goto out_unlock;
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
+ /* restore sensors state */
+ ret = inv_icm42600_set_pwr_mgmt0(st, st->suspended.gyro,
+ st->suspended.accel,
+ st->suspended.temp, NULL);
+ if (ret)
+ goto out_unlock;
+
+out_unlock:
+ mutex_unlock(&st->lock);
+ return ret;
+}
+
+/* Runtime suspend will turn off sensors that are enabled by iio devices. */
+static int __maybe_unused inv_icm42600_runtime_suspend(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ /* disable all sensors */
+ ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
+ INV_ICM42600_SENSOR_MODE_OFF, false,
+ NULL);
+ if (ret)
+ goto error_unlock;
+
+ regulator_disable(st->vddio_supply);
+
+error_unlock:
+ mutex_unlock(&st->lock);
+ return ret;
+}
+
+/* Sensors are enabled by iio devices, no need to turn them back on here. */
+static int __maybe_unused inv_icm42600_runtime_resume(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&st->lock);
+
+ ret = inv_icm42600_enable_regulator_vddio(st);
+
+ mutex_unlock(&st->lock);
+ return ret;
+}
+
+const struct dev_pm_ops inv_icm42600_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume)
+ SET_RUNTIME_PM_OPS(inv_icm42600_runtime_suspend,
+ inv_icm42600_runtime_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(inv_icm42600_pm_ops);
+
+MODULE_AUTHOR("InvenSense, Inc.");
+MODULE_DESCRIPTION("InvenSense ICM-426xx device driver");
+MODULE_LICENSE("GPL");
--
2.17.1
^ permalink raw reply related
* [PATCH v2 00/12] iio: imu: new inv_icm42600 driver
From: Jean-Baptiste Maneyrol @ 2020-05-27 18:56 UTC (permalink / raw)
To: jic23, robh+dt, robh, mchehab+huawei, davem, gregkh
Cc: linux-iio, devicetree, linux-kernel, Jean-Baptiste Maneyrol
Changelog
v1
-initial patch submission
v2
- formatting reworks, missing headers, code cleanup ...
- delete all debug traces
- add commentaries for better explanation of suspend/resume, timestamp, ...
- delete i2c/spi table ids keeping only of, and use I2C probe_new function
- switch calibbias to SI units and add calibias_available attribute
- use DMA-safe buffer for all regmap_bulk_* calls
- delete iio trigger usage and setup/handle interrupt in core module
- add open-drain interrupt support
- add FIFO on reference counter and buffer postenable/predisable to replace
iio trigger usage
- check that temperature data is present before copying in buffer
- add temperature sensor off when fifo is turned off
- delete timestamp channel reading
- move timestamp state in IIO device private data
- allow only 1 ODR change in a batch of data
- add driver-open-drain in devicetree YAML and delete spi options
This series add a new driver for managing InvenSense ICM-426xx 6-axis IMUs.
This next generation of chips includes new generations of 3-axis gyroscope
and 3-axis accelerometer, support of I3C in addition to I2C and SPI, and
intelligent MotionTracking features like pedometer, tilt detection, and
tap detection.
This series is delivering a driver supporting gyroscope, accelerometer and
temperature data, with polling and buffering using hwfifo and watermark,
on I2C and SPI busses.
Gyroscope and accelerometer sensors are completely independent and can have
different ODRs. Since there is only a single FIFO a specific value is used to
mark invalid data. For keeping the device standard we are de-multiplexing data
from the FIFO to 2 IIO devices with 2 buffers, 1 for the accelerometer and 1
for the gyroscope. This architecture also enables to easily turn each sensor
on/off without impacting the other. The device interrupt is used to read the
FIFO and launch parsing of accelerometer and gyroscope data. A complex
timestamping mechanism is added to handle correctly FIFO watermark and dynamic
changes of settings.
Jean-Baptiste Maneyrol (12):
iio: imu: inv_icm42600: add core of new inv_icm42600 driver
iio: imu: inv_icm42600: add I2C driver for inv_icm42600 driver
iio: imu: inv_icm42600: add SPI driver for inv_icm42600 driver
iio: imu: inv_icm42600: add gyroscope IIO device
iio: imu: inv_icm42600: add accelerometer IIO device
iio: imu: inv_icm42600: add temperature sensor support
iio: imu: add Kconfig and Makefile for inv_icm42600 driver
iio: imu: inv_icm42600: add device interrupt
iio: imu: inv_icm42600: add buffer support in iio devices
iio: imu: inv_icm42600: add accurate timestamping
dt-bindings: iio: imu: Add inv_icm42600 documentation
MAINTAINERS: add entry for inv_icm42600 6-axis imu sensor
.../bindings/iio/imu/invensense,icm42600.yaml | 86 ++
MAINTAINERS | 8 +
drivers/iio/imu/Kconfig | 1 +
drivers/iio/imu/Makefile | 1 +
drivers/iio/imu/inv_icm42600/Kconfig | 29 +
drivers/iio/imu/inv_icm42600/Makefile | 15 +
drivers/iio/imu/inv_icm42600/inv_icm42600.h | 395 +++++++++
.../iio/imu/inv_icm42600/inv_icm42600_accel.c | 784 +++++++++++++++++
.../imu/inv_icm42600/inv_icm42600_buffer.c | 583 +++++++++++++
.../imu/inv_icm42600/inv_icm42600_buffer.h | 98 +++
.../iio/imu/inv_icm42600/inv_icm42600_core.c | 782 +++++++++++++++++
.../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 795 ++++++++++++++++++
.../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 101 +++
.../iio/imu/inv_icm42600/inv_icm42600_spi.c | 100 +++
.../iio/imu/inv_icm42600/inv_icm42600_temp.c | 87 ++
.../iio/imu/inv_icm42600/inv_icm42600_temp.h | 30 +
.../imu/inv_icm42600/inv_icm42600_timestamp.c | 195 +++++
.../imu/inv_icm42600/inv_icm42600_timestamp.h | 85 ++
18 files changed, 4175 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
create mode 100644 drivers/iio/imu/inv_icm42600/Kconfig
create mode 100644 drivers/iio/imu/inv_icm42600/Makefile
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.c
create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_timestamp.h
--
2.17.1
^ permalink raw reply
* Re: [PATCH v3 006/105] dt-bindings: display: Convert VC4 bindings to schemas
From: Rob Herring @ 2020-05-27 19:12 UTC (permalink / raw)
To: Maxime Ripard
Cc: Nicolas Saenz Julienne, Eric Anholt, dri-devel, linux-rpi-kernel,
bcm-kernel-feedback-list, linux-arm-kernel, linux-kernel,
Dave Stevenson, Tim Gover, Phil Elwell, devicetree
In-Reply-To: <2dc6384c945c7d35ab4f75464d3a77046dc125b3.1590594512.git-series.maxime@cerno.tech>
On Wed, May 27, 2020 at 05:47:36PM +0200, Maxime Ripard wrote:
> The BCM283x SoCs have a display pipeline composed of several controllers
> with device tree bindings that are supported by Linux.
>
> Now that we have the DT validation in place, let's split into separate
> files and convert the device tree bindings for those controllers to
> schemas.
>
> This is just a 1:1 conversion though, and some bindings were incomplete so
> it results in example validation warnings that are going to be addressed in
> the following patches.
>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: devicetree@vger.kernel.org
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
> ---
> Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt | 174 +------------------------------------------------------------------------
> Documentation/devicetree/bindings/display/brcm,bcm2835-dpi.yaml | 66 +++++++++++++++++++++++++++-
> Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml | 73 ++++++++++++++++++++++++++++++-
> Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml | 75 +++++++++++++++++++++++++++++++-
> Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml | 37 +++++++++++++++-
> Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml | 40 +++++++++++++++++-
> Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml | 37 +++++++++++++++-
> Documentation/devicetree/bindings/display/brcm,bcm2835-v3d.yaml | 42 +++++++++++++++++-
> Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml | 34 ++++++++++++++-
> Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml | 44 ++++++++++++++++++-
> MAINTAINERS | 2 +-
> 11 files changed, 449 insertions(+), 175 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
> create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-dpi.yaml
> create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml
> create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-hdmi.yaml
> create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-hvs.yaml
> create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-pixelvalve0.yaml
> create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-txp.yaml
> create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-v3d.yaml
> create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-vc4.yaml
> create mode 100644 Documentation/devicetree/bindings/display/brcm,bcm2835-vec.yaml
> diff --git a/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml b/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml
> new file mode 100644
> index 000000000000..3887675f844e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/brcm,bcm2835-dsi0.yaml
> @@ -0,0 +1,73 @@
> +# SPDX-License-Identifier: GPL-2.0
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/brcm,bcm2835-dsi0.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Broadcom VC4 (VideoCore4) DSI Controller
> +
> +maintainers:
> + - Eric Anholt <eric@anholt.net>
> +
> +properties:
> + compatible:
> + enum:
> + - brcm,bcm2835-dsi0
> + - brcm,bcm2835-dsi1
> +
> + reg:
> + maxItems: 1
> +
> + clocks:
> + items:
> + - description: The DSI PLL clock feeding the DSI analog PHY
> + - description: The DSI ESC clock
> + - description: The DSI pixel clock
> +
> + clock-output-names: true
> + # FIXME: The meta-schemas don't seem to allow it for now
> + # items:
> + # - description: The DSI byte clock for the PHY
> + # - description: The DSI DDR2 clock
> + # - description: The DSI DDR clock
Doesn't pattern work for you?
pattern: '^dsi[0-1]_byte$'
Either way,
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 3/6] dt-bindings: serdev: ngsm: Add binding for GNSS child node
From: Rob Herring @ 2020-05-27 19:28 UTC (permalink / raw)
To: Tony Lindgren
Cc: Greg Kroah-Hartman, Johan Hovold, Alan Cox, Lee Jones, Jiri Slaby,
Merlijn Wajer, Pavel Machek, Peter Hurley, Sebastian Reichel,
linux-serial, devicetree, linux-kernel, linux-omap
In-Reply-To: <20200512214713.40501-4-tony@atomide.com>
On Tue, May 12, 2020 at 02:47:10PM -0700, Tony Lindgren wrote:
> For motorola modem case, we may have a GNSS device on channel 4.
> Let's add that to the binding and example.
>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
> ---
> .../devicetree/bindings/serdev/serdev-ngsm.yaml | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/serdev/serdev-ngsm.yaml b/Documentation/devicetree/bindings/serdev/serdev-ngsm.yaml
> --- a/Documentation/devicetree/bindings/serdev/serdev-ngsm.yaml
> +++ b/Documentation/devicetree/bindings/serdev/serdev-ngsm.yaml
> @@ -42,6 +42,10 @@ allOf:
> description: Name of the USB PHY
> const: usb
>
> + compatible:
> + description: GNSS receiver
> + const: motorola,mapphone-mdm6600-gnss
I'm not sure how this isn't failing on the example because it is wrong.
You're saying this compatible belongs at the same level as
phys/phy-names, but that would be the parent which already has a
compatible. You have to define a child node property (gnss@4) and have
'compatible' under it. At that point, this schema becomes very much
Motorola specific.
> +
> required:
> - phys
> - phy-names
> @@ -61,4 +65,9 @@ examples:
> phy-names = "usb";
> #address-cells = <1>;
> #size-cells = <0>;
> +
> + gnss@4 {
> + compatible = "motorola,mapphone-mdm6600-gnss";
> + reg = <4>;
> + };
> };
> --
> 2.26.2
^ permalink raw reply
* Re: [PATCH 1/4] dt-bindings: hwlock: qcom: Migrate binding to YAML
From: Rob Herring @ 2020-05-27 19:31 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Andy Gross, Ohad Ben-Cohen, Baolin Wang, linux-arm-msm,
linux-remoteproc, devicetree, linux-kernel
In-Reply-To: <20200513005441.1102586-2-bjorn.andersson@linaro.org>
On Tue, May 12, 2020 at 05:54:38PM -0700, Bjorn Andersson wrote:
> Migrate the Qualcomm TCSR mutex binding to YAML to allow validation.
Where's the deletion of the old text file?
Looks fine if this is existing. Lots of comments if this is a new
binding...
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
> .../bindings/hwlock/qcom-hwspinlock.yaml | 51 +++++++++++++++++++
> 1 file changed, 51 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.yaml
>
> diff --git a/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.yaml b/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.yaml
> new file mode 100644
> index 000000000000..71e63b52edd5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwlock/qcom-hwspinlock.yaml
> @@ -0,0 +1,51 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/hwlock/qcom-hwspinlock.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Qualcomm Hardware Mutex Block
> +
> +maintainers:
> + - Bjorn Andersson <bjorn.andersson@linaro.org>
> +
> +description:
> + The hardware block provides mutexes utilized between different processors on
> + the SoC as part of the communication protocol used by these processors.
> +
> +properties:
> + compatible:
> + enum:
> + - qcom,sfpb-mutex
> + - qcom,tcsr-mutex
> +
> + '#hwlock-cells':
> + const: 1
> +
> + syscon:
> + $ref: "/schemas/types.yaml#/definitions/phandle-array"
> + description:
> + Should be a triple of phandle referencing the TCSR mutex syscon, offset
> + of first mutex within the syscon and stride between each mutex.
> +
> +required:
> + - compatible
> + - '#hwlock-cells'
> + - syscon
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + tcsr_mutex_block: syscon@fd484000 {
> + compatible = "syscon";
> + reg = <0xfd484000 0x2000>;
> + };
> +
> + hwlock {
> + compatible = "qcom,tcsr-mutex";
> + syscon = <&tcsr_mutex_block 0 0x80>;
> +
> + #hwlock-cells = <1>;
> + };
> +...
> --
> 2.26.2
>
^ permalink raw reply
* Re: [PATCH] dt-bindings: watchdog: Convert UniPhier watchdog timer to json-schema
From: Rob Herring @ 2020-05-27 19:33 UTC (permalink / raw)
To: Kunihiko Hayashi
Cc: Wim Van Sebroeck, linux-watchdog, Masahiro Yamada, Guenter Roeck,
Rob Herring, devicetree, linux-kernel, linux-arm-kernel,
Keiji Hayashibara
In-Reply-To: <1589348545-22244-1-git-send-email-hayashi.kunihiko@socionext.com>
On Wed, 13 May 2020 14:42:25 +0900, Kunihiko Hayashi wrote:
> Convert UniPhier watchdog timer binding to DT schema format.
>
> Cc: Keiji Hayashibara <hayashibara.keiji@socionext.com>
> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
> ---
> .../bindings/watchdog/socionext,uniphier-wdt.yaml | 36 ++++++++++++++++++++++
> .../devicetree/bindings/watchdog/uniphier-wdt.txt | 20 ------------
> 2 files changed, 36 insertions(+), 20 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/watchdog/socionext,uniphier-wdt.yaml
> delete mode 100644 Documentation/devicetree/bindings/watchdog/uniphier-wdt.txt
>
Applied, thanks!
^ permalink raw reply
* [RESEND PATCH v4] ARM: dts: keystone: Rename "msmram" node to "sram"
From: Krzysztof Kozlowski @ 2020-05-27 19:35 UTC (permalink / raw)
To: Santosh Shilimkar, Rob Herring, linux-arm-kernel, devicetree,
linux-kernel
Cc: Krzysztof Kozlowski
The device node name should reflect generic class of a device so rename
the "msmram" node and its children to "sram". This will be also in sync
with upcoming DT schema. No functional change.
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
---
Changes since v3:
1. Rename also children.
v3 is here:
https://lore.kernel.org/linux-arm-kernel/20191002164316.14905-7-krzk@kernel.org/
---
arch/arm/boot/dts/keystone-k2e.dtsi | 4 ++--
arch/arm/boot/dts/keystone-k2g.dtsi | 4 ++--
arch/arm/boot/dts/keystone-k2hk.dtsi | 4 ++--
arch/arm/boot/dts/keystone-k2l.dtsi | 4 ++--
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/arch/arm/boot/dts/keystone-k2e.dtsi b/arch/arm/boot/dts/keystone-k2e.dtsi
index 085e7326ea8e..2d94faf31fab 100644
--- a/arch/arm/boot/dts/keystone-k2e.dtsi
+++ b/arch/arm/boot/dts/keystone-k2e.dtsi
@@ -86,14 +86,14 @@
};
};
- msm_ram: msmram@c000000 {
+ msm_ram: sram@c000000 {
compatible = "mmio-sram";
reg = <0x0c000000 0x200000>;
ranges = <0x0 0x0c000000 0x200000>;
#address-cells = <1>;
#size-cells = <1>;
- sram-bm@1f0000 {
+ bm-sram@1f0000 {
reg = <0x001f0000 0x8000>;
};
};
diff --git a/arch/arm/boot/dts/keystone-k2g.dtsi b/arch/arm/boot/dts/keystone-k2g.dtsi
index 08ba31780baa..05a75019275e 100644
--- a/arch/arm/boot/dts/keystone-k2g.dtsi
+++ b/arch/arm/boot/dts/keystone-k2g.dtsi
@@ -95,14 +95,14 @@
ranges = <0x0 0x0 0x0 0xc0000000>;
dma-ranges = <0x80000000 0x8 0x00000000 0x80000000>;
- msm_ram: msmram@c000000 {
+ msm_ram: sram@c000000 {
compatible = "mmio-sram";
reg = <0x0c000000 0x100000>;
ranges = <0x0 0x0c000000 0x100000>;
#address-cells = <1>;
#size-cells = <1>;
- sram-bm@f7000 {
+ bm-sram@f7000 {
reg = <0x000f7000 0x8000>;
};
};
diff --git a/arch/arm/boot/dts/keystone-k2hk.dtsi b/arch/arm/boot/dts/keystone-k2hk.dtsi
index ca0f198ba627..8a9447703310 100644
--- a/arch/arm/boot/dts/keystone-k2hk.dtsi
+++ b/arch/arm/boot/dts/keystone-k2hk.dtsi
@@ -57,14 +57,14 @@
&soc0 {
/include/ "keystone-k2hk-clocks.dtsi"
- msm_ram: msmram@c000000 {
+ msm_ram: sram@c000000 {
compatible = "mmio-sram";
reg = <0x0c000000 0x600000>;
ranges = <0x0 0x0c000000 0x600000>;
#address-cells = <1>;
#size-cells = <1>;
- sram-bm@5f0000 {
+ bm-sram@5f0000 {
reg = <0x5f0000 0x8000>;
};
};
diff --git a/arch/arm/boot/dts/keystone-k2l.dtsi b/arch/arm/boot/dts/keystone-k2l.dtsi
index 374c80124c4e..dff5fea72b2f 100644
--- a/arch/arm/boot/dts/keystone-k2l.dtsi
+++ b/arch/arm/boot/dts/keystone-k2l.dtsi
@@ -255,14 +255,14 @@
};
};
- msm_ram: msmram@c000000 {
+ msm_ram: sram@c000000 {
compatible = "mmio-sram";
reg = <0x0c000000 0x200000>;
ranges = <0x0 0x0c000000 0x200000>;
#address-cells = <1>;
#size-cells = <1>;
- sram-bm@1f8000 {
+ bm-sram@1f8000 {
reg = <0x001f8000 0x8000>;
};
};
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v2] dt-bindings: media: venus: Add an optional power domain for perf voting
From: Rob Herring @ 2020-05-27 19:36 UTC (permalink / raw)
To: Rajendra Nayak
Cc: stanimir.varbanov, agross, bjorn.andersson, linux-arm-msm,
linux-media, devicetree, linux-kernel, mka
In-Reply-To: <1589349807-10163-1-git-send-email-rnayak@codeaurora.org>
On Wed, May 13, 2020 at 11:33:27AM +0530, Rajendra Nayak wrote:
> Add an optional power domain which when specified can be used for
> setting the performance state of Venus.
>
> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
> ---
> Documentation/devicetree/bindings/media/qcom,sc7180-venus.yaml | 6 +++++-
> Documentation/devicetree/bindings/media/qcom,sdm845-venus-v2.yaml | 6 +++++-
> 2 files changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/media/qcom,sc7180-venus.yaml b/Documentation/devicetree/bindings/media/qcom,sc7180-venus.yaml
> index 764affa..ac1ed64 100644
> --- a/Documentation/devicetree/bindings/media/qcom,sc7180-venus.yaml
> +++ b/Documentation/devicetree/bindings/media/qcom,sc7180-venus.yaml
> @@ -25,12 +25,16 @@ properties:
> maxItems: 1
>
> power-domains:
> - maxItems: 2
> + minItems: 2
> + maxItems: 3
>
> power-domain-names:
> + minItems: 2
> + maxItems: 3
> items:
> - const: venus
> - const: vcodec0
> + - const: opp-pd
Humm, looks suspicious. This is a phyical power island in this block?
Because that's what 'power-domains' are supposed to represent. Not $os
pm-domain construct.
Rob
^ permalink raw reply
* [RESEND PATCH v3 1/2] arm64: dts: tegra: Rename sysram node to "sram"
From: Krzysztof Kozlowski @ 2020-05-27 19:36 UTC (permalink / raw)
To: Rob Herring, Thierry Reding, Jonathan Hunter, Nagarjuna Kristam,
Joseph Lo, Krzysztof Kozlowski, Sameer Pujar, Vidya Sagar, JC Kuo,
devicetree, linux-tegra, linux-kernel
The device node name should reflect generic class of a device so rename
the "sysram" node to "sram". This will be also in sync with upcoming DT
schema. No functional change.
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
---
arch/arm64/boot/dts/nvidia/tegra186.dtsi | 2 +-
arch/arm64/boot/dts/nvidia/tegra194.dtsi | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/nvidia/tegra186.dtsi b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
index 58100fb9cd8b..3ed7d7a26219 100644
--- a/arch/arm64/boot/dts/nvidia/tegra186.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra186.dtsi
@@ -1213,7 +1213,7 @@
power-domains = <&bpmp TEGRA186_POWER_DOMAIN_GPU>;
};
- sysram@30000000 {
+ sram@30000000 {
compatible = "nvidia,tegra186-sysram", "mmio-sram";
reg = <0x0 0x30000000 0x0 0x50000>;
#address-cells = <2>;
diff --git a/arch/arm64/boot/dts/nvidia/tegra194.dtsi b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
index 4bc187a4eacd..0533c45b9237 100644
--- a/arch/arm64/boot/dts/nvidia/tegra194.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra194.dtsi
@@ -1737,7 +1737,7 @@
nvidia,aspm-l0s-entrance-latency-us = <3>;
};
- sysram@40000000 {
+ sram@40000000 {
compatible = "nvidia,tegra194-sysram", "mmio-sram";
reg = <0x0 0x40000000 0x0 0x50000>;
#address-cells = <1>;
--
2.17.1
^ permalink raw reply related
* [RESEND PATCH v3 2/2] ARM: dts: tegra: Rename "iram" node to "sram"
From: Krzysztof Kozlowski @ 2020-05-27 19:36 UTC (permalink / raw)
To: Rob Herring, Thierry Reding, Jonathan Hunter, Nagarjuna Kristam,
Joseph Lo, Krzysztof Kozlowski, Sameer Pujar, Vidya Sagar, JC Kuo,
devicetree, linux-tegra, linux-kernel
In-Reply-To: <20200527193650.17617-1-krzk@kernel.org>
The device node name should reflect generic class of a device so rename
the "iram" node to "sram". This will be also in sync with upcoming DT
schema. No functional change.
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
---
arch/arm/boot/dts/tegra20.dtsi | 2 +-
arch/arm/boot/dts/tegra30.dtsi | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index c3b8ad53b967..36e82fc20d47 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -17,7 +17,7 @@
reg = <0 0>;
};
- iram@40000000 {
+ sram@40000000 {
compatible = "mmio-sram";
reg = <0x40000000 0x40000>;
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index d2d05f1da274..7ff85a651194 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -97,7 +97,7 @@
};
};
- iram@40000000 {
+ sram@40000000 {
compatible = "mmio-sram";
reg = <0x40000000 0x40000>;
#address-cells = <1>;
--
2.17.1
^ permalink raw reply related
* Re: [PATCH 2/2] MAINTAINERS: Add Purism Librem 5 section to the list
From: Martin Kepplinger @ 2020-05-27 19:40 UTC (permalink / raw)
To: Marco Felsch
Cc: robh, kernel, shawnguo, s.hauer, kernel, festevam, linux-imx,
mchehab, Anson.Huang, agx, angus, devicetree, linux-kernel,
linux-arm-kernel
In-Reply-To: <20200527094014.nn4cupjrvcceo5lv@pengutronix.de>
On 27.05.20 11:40, Marco Felsch wrote:
> On 20-05-14 17:57, Martin Kepplinger wrote:
>> Add development information for the devicetree files for hardware
>> by Purism SPC.
>>
>> Signed-off-by: Martin Kepplinger <martin.kepplinger@puri.sm>
>> ---
>> MAINTAINERS | 8 ++++++++
>> 1 file changed, 8 insertions(+)
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 0abba1aff1ae..176efec31010 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -13775,6 +13775,14 @@ T: git git://linuxtv.org/media_tree.git
>> F: Documentation/admin-guide/media/pulse8-cec.rst
>> F: drivers/media/cec/usb/pulse8/
>>
>> +PURISM LIBREM 5
>> +M: Purism Kernel Team <kernel@puri.sm>
>> +S: Supported
>> +B: https://source.puri.sm/Librem5/linux-next/issues
>> +T: https://source.puri.sm/Librem5/linux-next
>> +F: arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts
>> +F: arch/arm64/boot/dts/freescale/imx8mq-librem5.dts
>
> Is it okay to take care of all imx8mq-librem5* files?
>
> F: arch/arm64/boot/dts/freescale/imx8mq-librem5*
>
> Regards,
> Marco
>
hi Marco
it is. I'll change it for a next revision. thanks a lot for taking the
time to review this!
martin
^ permalink raw reply
* Re: [PATCH v3 4/7] mfd: arizona: Move binding over to dtschema
From: Rob Herring @ 2020-05-27 19:43 UTC (permalink / raw)
To: Charles Keepax
Cc: cw00.choi, lee.jones, linus.walleij, broonie, myungjoo.ham,
lgirdwood, linux-kernel, devicetree, patches
In-Reply-To: <20200513095720.8867-4-ckeepax@opensource.cirrus.com>
On Wed, May 13, 2020 at 10:57:17AM +0100, Charles Keepax wrote:
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
>
> Changes since v2:
> - Removed a couple more redundant descriptions
>
> Thanks,
> Charles
>
> Documentation/devicetree/bindings/mfd/arizona.txt | 101 -------
> .../devicetree/bindings/mfd/wlf,arizona.yaml | 289 +++++++++++++++++++++
> MAINTAINERS | 8 +-
> 3 files changed, 293 insertions(+), 105 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/mfd/arizona.txt
> create mode 100644 Documentation/devicetree/bindings/mfd/wlf,arizona.yaml
> diff --git a/Documentation/devicetree/bindings/mfd/wlf,arizona.yaml b/Documentation/devicetree/bindings/mfd/wlf,arizona.yaml
> new file mode 100644
> index 0000000000000..14b6aac64a7e0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/wlf,arizona.yaml
> @@ -0,0 +1,289 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/mfd/wlf,arizona.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cirrus Logic/Wolfson Microelectronics Arizona class audio SoCs
> +
> +maintainers:
> + - patches@opensource.cirrus.com
> +
> +description: |
> + These devices are audio SoCs with extensive digital capabilities and a
> + range of analogue I/O.
> +
> +allOf:
> + - $ref: /schemas/sound/wlf,arizona.yaml#
> + - $ref: /schemas/regulator/wlf,arizona.yaml#
> + - $ref: /schemas/extcon/wlf,arizona.yaml#
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - cirrus,cs47l24
> + - wlf,wm1831
> + then:
> + required:
> + - DCVDD-supply
> + - MICVDD-supply
> + else:
> + properties:
> + LDOVDD-supply:
> + description:
> + Digital power supply, used internally to generate DCVDD when
> + internally supplied.
> + $ref: /schemas/types.yaml#/definitions/phandle
Don't need a type. *-supply has one already.
I'll fix up when applying.
Rob
^ permalink raw reply
* Re: [PATCH v3 1/7] regulator: arizona-regulator: Move binding over to dtschema
From: Rob Herring @ 2020-05-27 19:43 UTC (permalink / raw)
To: Charles Keepax
Cc: linus.walleij, broonie, patches, myungjoo.ham, lgirdwood,
linux-kernel, devicetree, lee.jones, robh+dt, cw00.choi
In-Reply-To: <20200513095720.8867-1-ckeepax@opensource.cirrus.com>
On Wed, 13 May 2020 10:57:14 +0100, Charles Keepax wrote:
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
>
> No changes since v2.
>
> Thanks,
> Charles
>
> .../bindings/regulator/arizona-regulator.txt | 18 -----------
> .../devicetree/bindings/regulator/wlf,arizona.yaml | 37 ++++++++++++++++++++++
> 2 files changed, 37 insertions(+), 18 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/regulator/arizona-regulator.txt
> create mode 100644 Documentation/devicetree/bindings/regulator/wlf,arizona.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH v3 2/7] extcon: arizona: Move binding over to dtschema
From: Rob Herring @ 2020-05-27 19:43 UTC (permalink / raw)
To: Charles Keepax
Cc: linus.walleij, broonie, myungjoo.ham, devicetree, lgirdwood,
patches, linux-kernel, lee.jones, cw00.choi, robh+dt
In-Reply-To: <20200513095720.8867-2-ckeepax@opensource.cirrus.com>
On Wed, 13 May 2020 10:57:15 +0100, Charles Keepax wrote:
> Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
>
> No changes since v2.
>
> Thanks,
> Charles
>
> .../devicetree/bindings/extcon/extcon-arizona.txt | 76 -------------
> .../devicetree/bindings/extcon/wlf,arizona.yaml | 125 +++++++++++++++++++++
> 2 files changed, 125 insertions(+), 76 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/extcon/extcon-arizona.txt
> create mode 100644 Documentation/devicetree/bindings/extcon/wlf,arizona.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH v3 3/7] ASoC: arizona: Move binding over to dtschema
From: Rob Herring @ 2020-05-27 19:44 UTC (permalink / raw)
To: Charles Keepax
Cc: lgirdwood, myungjoo.ham, linux-kernel, devicetree, linus.walleij,
robh+dt, broonie, lee.jones, cw00.choi, patches
In-Reply-To: <20200513095720.8867-3-ckeepax@opensource.cirrus.com>
On Wed, 13 May 2020 10:57:16 +0100, Charles Keepax wrote:
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
>
> No changes since v2.
>
> Thanks,
> Charles
>
> .../devicetree/bindings/sound/wlf,arizona.txt | 53 ----------
> .../devicetree/bindings/sound/wlf,arizona.yaml | 114 +++++++++++++++++++++
> 2 files changed, 114 insertions(+), 53 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/sound/wlf,arizona.txt
> create mode 100644 Documentation/devicetree/bindings/sound/wlf,arizona.yaml
>
Applied, thanks!
^ permalink raw reply
* Re: [PATCH v3 4/7] mfd: arizona: Move binding over to dtschema
From: Rob Herring @ 2020-05-27 19:44 UTC (permalink / raw)
To: Charles Keepax
Cc: linus.walleij, broonie, devicetree, cw00.choi, robh+dt, lgirdwood,
patches, lee.jones, myungjoo.ham, linux-kernel
In-Reply-To: <20200513095720.8867-4-ckeepax@opensource.cirrus.com>
On Wed, 13 May 2020 10:57:17 +0100, Charles Keepax wrote:
> Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
> ---
>
> Changes since v2:
> - Removed a couple more redundant descriptions
>
> Thanks,
> Charles
>
> Documentation/devicetree/bindings/mfd/arizona.txt | 101 -------
> .../devicetree/bindings/mfd/wlf,arizona.yaml | 289 +++++++++++++++++++++
> MAINTAINERS | 8 +-
> 3 files changed, 293 insertions(+), 105 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/mfd/arizona.txt
> create mode 100644 Documentation/devicetree/bindings/mfd/wlf,arizona.yaml
>
Applied, thanks!
^ permalink raw reply
* [PATCH 1/4] power_supply: Add additional health properties to the header
From: Dan Murphy @ 2020-05-27 19:53 UTC (permalink / raw)
To: sre, afd, pali, robh
Cc: linux-pm, linux-kernel, devicetree, Dan Murphy,
Guru Das Srinagesh
Add HEALTH_WARM, HEALTH_COOL and HEALTH_HOT to the health enum.
HEALTH_WARM, HEALTH_COOL, and HEALTH_HOT properties are taken from the JEITA spec.
Tested-by: Guru Das Srinagesh <gurus@codeaurora.org>
Signed-off-by: Dan Murphy <dmurphy@ti.com>
---
Documentation/ABI/testing/sysfs-class-power | 2 +-
drivers/power/supply/power_supply_sysfs.c | 2 +-
include/linux/power_supply.h | 3 +++
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power
index bf3b48f022dc..9f3fd01a9373 100644
--- a/Documentation/ABI/testing/sysfs-class-power
+++ b/Documentation/ABI/testing/sysfs-class-power
@@ -190,7 +190,7 @@ Description:
Valid values: "Unknown", "Good", "Overheat", "Dead",
"Over voltage", "Unspecified failure", "Cold",
"Watchdog timer expire", "Safety timer expire",
- "Over current"
+ "Over current", "Warm", "Cool", "Hot"
What: /sys/class/power_supply/<supply_name>/precharge_current
Date: June 2017
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index f37ad4eae60b..d0d549611794 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -61,7 +61,7 @@ static const char * const power_supply_charge_type_text[] = {
static const char * const power_supply_health_text[] = {
"Unknown", "Good", "Overheat", "Dead", "Over voltage",
"Unspecified failure", "Cold", "Watchdog timer expire",
- "Safety timer expire", "Over current"
+ "Safety timer expire", "Over current", "Warm", "Cool", "Hot"
};
static const char * const power_supply_technology_text[] = {
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index dcd5a71e6c67..8670e90c1d51 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -61,6 +61,9 @@ enum {
POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE,
POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE,
POWER_SUPPLY_HEALTH_OVERCURRENT,
+ POWER_SUPPLY_HEALTH_WARM,
+ POWER_SUPPLY_HEALTH_COOL,
+ POWER_SUPPLY_HEALTH_HOT,
};
enum {
--
2.26.2
^ permalink raw reply related
* [PATCH 2/4] dt-bindings: power: Convert battery.txt to battery.yaml
From: Dan Murphy @ 2020-05-27 19:53 UTC (permalink / raw)
To: sre, afd, pali, robh; +Cc: linux-pm, linux-kernel, devicetree, Dan Murphy
In-Reply-To: <20200527195327.23163-1-dmurphy@ti.com>
Convert the battery.txt file to yaml and fix up the examples.
Signed-off-by: Dan Murphy <dmurphy@ti.com>
---
.../bindings/power/supply/battery.txt | 82 +---------
.../bindings/power/supply/battery.yaml | 143 ++++++++++++++++++
2 files changed, 144 insertions(+), 81 deletions(-)
create mode 100644 Documentation/devicetree/bindings/power/supply/battery.yaml
diff --git a/Documentation/devicetree/bindings/power/supply/battery.txt b/Documentation/devicetree/bindings/power/supply/battery.txt
index 3049cf88bdcf..b9a81621ce59 100644
--- a/Documentation/devicetree/bindings/power/supply/battery.txt
+++ b/Documentation/devicetree/bindings/power/supply/battery.txt
@@ -1,81 +1 @@
-Battery Characteristics
-
-The devicetree battery node provides static battery characteristics.
-In smart batteries, these are typically stored in non-volatile memory
-on a fuel gauge chip. The battery node should be used where there is
-no appropriate non-volatile memory, or it is unprogrammed/incorrect.
-
-Upstream dts files should not include battery nodes, unless the battery
-represented cannot easily be replaced in the system by one of a
-different type. This prevents unpredictable, potentially harmful,
-behavior should a replacement that changes the battery type occur
-without a corresponding update to the dtb.
-
-Required Properties:
- - compatible: Must be "simple-battery"
-
-Optional Properties:
- - voltage-min-design-microvolt: drained battery voltage
- - voltage-max-design-microvolt: fully charged battery voltage
- - energy-full-design-microwatt-hours: battery design energy
- - charge-full-design-microamp-hours: battery design capacity
- - precharge-current-microamp: current for pre-charge phase
- - charge-term-current-microamp: current for charge termination phase
- - constant-charge-current-max-microamp: maximum constant input current
- - constant-charge-voltage-max-microvolt: maximum constant input voltage
- - factory-internal-resistance-micro-ohms: battery factory internal resistance
- - ocv-capacity-table-0: An array providing the open circuit voltage (OCV)
- of the battery and corresponding battery capacity percent, which is used
- to look up battery capacity according to current OCV value. And the open
- circuit voltage unit is microvolt.
- - ocv-capacity-table-1: Same as ocv-capacity-table-0
- ......
- - ocv-capacity-table-n: Same as ocv-capacity-table-0
- - ocv-capacity-celsius: An array containing the temperature in degree Celsius,
- for each of the battery capacity lookup table. The first temperature value
- specifies the OCV table 0, and the second temperature value specifies the
- OCV table 1, and so on.
- - resistance-temp-table: An array providing the temperature in degree Celsius
- and corresponding battery internal resistance percent, which is used to look
- up the resistance percent according to current temperature to get a accurate
- batterty internal resistance in different temperatures.
-
-Battery properties are named, where possible, for the corresponding
-elements in enum power_supply_property, defined in
-https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/linux/power_supply.h
-
-Batteries must be referenced by chargers and/or fuel-gauges
-using a phandle. The phandle's property should be named
-"monitored-battery".
-
-Example:
-
- bat: battery {
- compatible = "simple-battery";
- voltage-min-design-microvolt = <3200000>;
- voltage-max-design-microvolt = <4200000>;
- energy-full-design-microwatt-hours = <5290000>;
- charge-full-design-microamp-hours = <1430000>;
- precharge-current-microamp = <256000>;
- charge-term-current-microamp = <128000>;
- constant-charge-current-max-microamp = <900000>;
- constant-charge-voltage-max-microvolt = <4200000>;
- factory-internal-resistance-micro-ohms = <250000>;
- ocv-capacity-celsius = <(-10) 0 10>;
- ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>, ...;
- ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>, ...;
- ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>, ...;
- resistance-temp-table = <20 100>, <10 90>, <0 80>, <(-10) 60>;
- };
-
- charger: charger@11 {
- ....
- monitored-battery = <&bat>;
- ...
- };
-
- fuel_gauge: fuel-gauge@22 {
- ....
- monitored-battery = <&bat>;
- ...
- };
+The contents of this file has been moved to battery.yaml
diff --git a/Documentation/devicetree/bindings/power/supply/battery.yaml b/Documentation/devicetree/bindings/power/supply/battery.yaml
new file mode 100644
index 000000000000..f0b544a22219
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/battery.yaml
@@ -0,0 +1,143 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/battery.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Battery Characteristics
+
+maintainers:
+ - Sebastian Reichel <sre@kernel.org>
+
+description: |
+ The devicetree battery node provides static battery characteristics.
+ In smart batteries, these are typically stored in non-volatile memory
+ on a fuel gauge chip. The battery node should be used where there is
+ no appropriate non-volatile memory, or it is unprogrammed/incorrect.
+
+ Upstream dts files should not include battery nodes, unless the battery
+ represented cannot easily be replaced in the system by one of a
+ different type. This prevents unpredictable, potentially harmful,
+ behavior should a replacement that changes the battery type occur
+ without a corresponding update to the dtb.
+
+ Battery properties are named, where possible, for the corresponding elements
+ in enum power_supply_property, defined in include/linux/power_supply.h
+
+ Batteries must be referenced by chargers and/or fuel-gauges using a phandle.
+ The phandle's property should be named "monitored-battery".
+
+properties:
+ compatible:
+ const: simple-battery
+
+ voltage-min-design-microvolt:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: drained battery voltage
+
+ voltage-max-design-microvolt:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: fully charged battery voltage
+
+ energy-full-design-microwatt-hours:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: battery design energy
+
+ charge-full-design-microamp-hours:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: battery design capacity
+
+ precharge-current-microamp:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: current for pre-charge phase
+
+ charge-term-current-microamp:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: current for charge termination phase
+
+ constant-charge-current-max-microamp:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: maximum constant input current
+
+ constant-charge-voltage-max-microvolt:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: maximum constant input voltage
+
+ factory-internal-resistance-micro-ohms:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: battery factory internal resistance
+
+ ocv-capacity-table-0:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ description: |
+ An array providing the open circuit voltage (OCV)
+ of the battery and corresponding battery capacity percent, which is used
+ to look up battery capacity according to current OCV value. And the open
+ circuit voltage unit is microvolt.
+
+ ocv-capacity-table-1:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ description: Same as ocv-capacity-table-0
+
+ ocv-capacity-table-n:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ description: Same as ocv-capacity-table-0
+
+ ocv-capacity-celsius:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description: |
+ An array containing the temperature in degree Celsius,
+ for each of the battery capacity lookup table. The first temperature value
+ specifies the OCV table 0, and the second temperature value specifies the
+ OCV table 1, and so on.
+
+ resistance-temp-table:
+ $ref: /schemas/types.yaml#/definitions/uint32-matrix
+ description: |
+ An array providing the temperature in degree Celsius
+ and corresponding battery internal resistance percent, which is used to
+ look up the resistance percent according to current temperature to get an
+ accurate batterty internal resistance in different temperatures.
+
+ monitored-battery:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: phandle to the battery node being monitored
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ power {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ battery:battery {
+ compatible = "simple-battery";
+ voltage-min-design-microvolt = <3200000>;
+ voltage-max-design-microvolt = <4200000>;
+ energy-full-design-microwatt-hours = <5290000>;
+ charge-full-design-microamp-hours = <1430000>;
+ precharge-current-microamp = <256000>;
+ charge-term-current-microamp = <128000>;
+ constant-charge-current-max-microamp = <900000>;
+ constant-charge-voltage-max-microvolt = <4200000>;
+ factory-internal-resistance-micro-ohms = <250000>;
+ ocv-capacity-celsius = <(-10) 0 10>;
+ ocv-capacity-table-0 = <4185000 100>, <4113000 95>, <4066000 90>;
+ ocv-capacity-table-1 = <4200000 100>, <4185000 95>, <4113000 90>;
+ resistance-temp-table = <20 100>, <10 90>, <0 80>, <(-10) 60>;
+ };
+
+ charger:charger@11 {
+ reg = <0x11>;
+ monitored-battery = <&battery>;
+ };
+
+ fuel_gauge:fuel-gauge@22 {
+ reg = <0x22>;
+ monitored-battery = <&battery>;
+ };
+ };
--
2.26.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox