]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
iio: imu: inv_icm42600: add wakeup functionality for Wake-on-Motion
authorJean-Baptiste Maneyrol <jean-baptiste.maneyrol@tdk.com>
Mon, 30 Jun 2025 19:47:31 +0000 (21:47 +0200)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Mon, 14 Jul 2025 18:20:51 +0000 (19:20 +0100)
When Wake-on-Motion is on, enable system wakeup and keep the chip on
for waking up the system with an interrupt.

Signed-off-by: Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@tdk.com>
Link: https://patch.msgid.link/20250630-losd-3-inv-icm42600-add-wom-support-v6-3-5bb0c84800d9@tdk.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/imu/inv_icm42600/inv_icm42600.h
drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
drivers/iio/imu/inv_icm42600/inv_icm42600_core.c

index 6af96df9f0ed195a211c40ca0075678f80b9424f..1430ab4f1dea5d5ba6277d74275fc44a6cd30eb8 100644 (file)
@@ -151,6 +151,7 @@ struct inv_icm42600_apex {
  *  @map:              regmap pointer.
  *  @vdd_supply:       VDD voltage regulator for the chip.
  *  @vddio_supply:     I/O voltage regulator for the chip.
+ *  @irq:              chip irq, required to enable/disable and set wakeup
  *  @orientation:      sensor chip orientation relative to main hardware.
  *  @conf:             chip sensors configurations.
  *  @suspended:                suspended sensors configuration.
@@ -168,6 +169,7 @@ struct inv_icm42600_state {
        struct regmap *map;
        struct regulator *vdd_supply;
        struct regulator *vddio_supply;
+       int irq;
        struct iio_mount_matrix orientation;
        struct inv_icm42600_conf conf;
        struct inv_icm42600_suspended suspended;
index c52d77cab040dcfb11bc1f9430a3b1dfd52660a9..7a28051330b79098bfa94b8c8c78c2bce20b7230 100644 (file)
@@ -1206,6 +1206,11 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
        if (ret)
                return ERR_PTR(ret);
 
+       /* accel events are wakeup capable */
+       ret = devm_device_init_wakeup(&indio_dev->dev);
+       if (ret)
+               return ERR_PTR(ret);
+
        return indio_dev;
 }
 
index 283483ed82ff42b4f9b80d99084c118786054c37..a4d42e7e21807f7954def431e9cf03dffaa5bd5e 100644 (file)
@@ -765,6 +765,7 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip,
        mutex_init(&st->lock);
        st->chip = chip;
        st->map = regmap;
+       st->irq = irq;
 
        ret = iio_read_mount_matrix(dev, &st->orientation);
        if (ret) {
@@ -843,6 +844,9 @@ EXPORT_SYMBOL_NS_GPL(inv_icm42600_core_probe, "IIO_ICM42600");
 static int inv_icm42600_suspend(struct device *dev)
 {
        struct inv_icm42600_state *st = dev_get_drvdata(dev);
+       struct device *accel_dev;
+       bool wakeup;
+       int accel_conf;
        int ret;
 
        mutex_lock(&st->lock);
@@ -863,20 +867,32 @@ static int inv_icm42600_suspend(struct device *dev)
                        goto out_unlock;
        }
 
-       /* disable APEX features */
-       if (st->apex.wom.enable) {
-               ret = inv_icm42600_disable_wom(st);
-               if (ret)
-                       goto out_unlock;
+       /* keep chip on and wake-up capable if APEX and wakeup on */
+       accel_dev = &st->indio_accel->dev;
+       wakeup = st->apex.on && device_may_wakeup(accel_dev);
+       if (wakeup) {
+               /* keep accel on and setup irq for wakeup */
+               accel_conf = st->conf.accel.mode;
+               enable_irq_wake(st->irq);
+               disable_irq(st->irq);
+       } else {
+               /* disable APEX features and accel if wakeup disabled */
+               if (st->apex.wom.enable) {
+                       ret = inv_icm42600_disable_wom(st);
+                       if (ret)
+                               goto out_unlock;
+               }
+               accel_conf = INV_ICM42600_SENSOR_MODE_OFF;
        }
 
        ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
-                                        INV_ICM42600_SENSOR_MODE_OFF, false,
-                                        NULL);
+                                        accel_conf, false, NULL);
        if (ret)
                goto out_unlock;
 
-       regulator_disable(st->vddio_supply);
+       /* disable vddio regulator if chip is sleeping */
+       if (!wakeup)
+               regulator_disable(st->vddio_supply);
 
 out_unlock:
        mutex_unlock(&st->lock);
@@ -892,13 +908,24 @@ static int inv_icm42600_resume(struct device *dev)
        struct inv_icm42600_state *st = dev_get_drvdata(dev);
        struct inv_icm42600_sensor_state *gyro_st = iio_priv(st->indio_gyro);
        struct inv_icm42600_sensor_state *accel_st = iio_priv(st->indio_accel);
+       struct device *accel_dev;
+       bool wakeup;
        int ret;
 
        mutex_lock(&st->lock);
 
-       ret = inv_icm42600_enable_regulator_vddio(st);
-       if (ret)
-               goto out_unlock;
+       /* check wakeup capability */
+       accel_dev = &st->indio_accel->dev;
+       wakeup = st->apex.on && device_may_wakeup(accel_dev);
+       /* restore irq state or vddio if cut off */
+       if (wakeup) {
+               enable_irq(st->irq);
+               disable_irq_wake(st->irq);
+       } else {
+               ret = inv_icm42600_enable_regulator_vddio(st);
+               if (ret)
+                       goto out_unlock;
+       }
 
        pm_runtime_disable(dev);
        pm_runtime_set_active(dev);
@@ -911,8 +938,8 @@ static int inv_icm42600_resume(struct device *dev)
        if (ret)
                goto out_unlock;
 
-       /* restore APEX features */
-       if (st->apex.wom.enable) {
+       /* restore APEX features if disabled */
+       if (!wakeup && st->apex.wom.enable) {
                ret = inv_icm42600_enable_wom(st);
                if (ret)
                        goto out_unlock;