iio: imu: inv_mpu6050: use runtime pm with autosuspend
Use runtime power management for handling chip power and sensor engines on/off. Simplifies things a lot since pm runtime already has reference counter. Usage of autosuspend reduces the number of power on/off. This makes polling interface now usable to get data at low frequency. Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@invensense.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
5e95ca3637
commit
4599cac846
3 changed files with 196 additions and 112 deletions
|
@ -16,6 +16,8 @@
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/pm.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include "inv_mpu_iio.h"
|
#include "inv_mpu_iio.h"
|
||||||
#include "inv_mpu_magn.h"
|
#include "inv_mpu_magn.h"
|
||||||
|
|
||||||
|
@ -396,30 +398,18 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
|
static int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st,
|
||||||
|
bool power_on)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (power_on) {
|
result = inv_mpu6050_pwr_mgmt_1_write(st, !power_on, -1, -1);
|
||||||
if (!st->powerup_count) {
|
|
||||||
result = inv_mpu6050_pwr_mgmt_1_write(st, false, -1, -1);
|
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
if (power_on)
|
||||||
usleep_range(INV_MPU6050_REG_UP_TIME_MIN,
|
usleep_range(INV_MPU6050_REG_UP_TIME_MIN,
|
||||||
INV_MPU6050_REG_UP_TIME_MAX);
|
INV_MPU6050_REG_UP_TIME_MAX);
|
||||||
}
|
|
||||||
st->powerup_count++;
|
|
||||||
} else {
|
|
||||||
if (st->powerup_count == 1) {
|
|
||||||
result = inv_mpu6050_pwr_mgmt_1_write(st, true, -1, -1);
|
|
||||||
if (result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
st->powerup_count--;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(regmap_get_device(st->map), "set power %d, count=%u\n",
|
|
||||||
power_on, st->powerup_count);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -563,6 +553,7 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
|
||||||
int *val)
|
int *val)
|
||||||
{
|
{
|
||||||
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
||||||
|
struct device *pdev = regmap_get_device(st->map);
|
||||||
unsigned int freq_hz, period_us, min_sleep_us, max_sleep_us;
|
unsigned int freq_hz, period_us, min_sleep_us, max_sleep_us;
|
||||||
int result;
|
int result;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -571,12 +562,15 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
|
||||||
freq_hz = INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider);
|
freq_hz = INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider);
|
||||||
period_us = 1000000 / freq_hz;
|
period_us = 1000000 / freq_hz;
|
||||||
|
|
||||||
result = inv_mpu6050_set_power_itg(st, true);
|
result = pm_runtime_get_sync(pdev);
|
||||||
if (result)
|
if (result < 0) {
|
||||||
|
pm_runtime_put_noidle(pdev);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
switch (chan->type) {
|
switch (chan->type) {
|
||||||
case IIO_ANGL_VEL:
|
case IIO_ANGL_VEL:
|
||||||
|
if (!st->chip_config.gyro_en) {
|
||||||
result = inv_mpu6050_switch_engine(st, true,
|
result = inv_mpu6050_switch_engine(st, true,
|
||||||
INV_MPU6050_SENSOR_GYRO);
|
INV_MPU6050_SENSOR_GYRO);
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -585,14 +579,12 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
|
||||||
min_sleep_us = 2 * period_us;
|
min_sleep_us = 2 * period_us;
|
||||||
max_sleep_us = 2 * (period_us + period_us / 2);
|
max_sleep_us = 2 * (period_us + period_us / 2);
|
||||||
usleep_range(min_sleep_us, max_sleep_us);
|
usleep_range(min_sleep_us, max_sleep_us);
|
||||||
|
}
|
||||||
ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
|
ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
|
||||||
chan->channel2, val);
|
chan->channel2, val);
|
||||||
result = inv_mpu6050_switch_engine(st, false,
|
|
||||||
INV_MPU6050_SENSOR_GYRO);
|
|
||||||
if (result)
|
|
||||||
goto error_power_off;
|
|
||||||
break;
|
break;
|
||||||
case IIO_ACCEL:
|
case IIO_ACCEL:
|
||||||
|
if (!st->chip_config.accl_en) {
|
||||||
result = inv_mpu6050_switch_engine(st, true,
|
result = inv_mpu6050_switch_engine(st, true,
|
||||||
INV_MPU6050_SENSOR_ACCL);
|
INV_MPU6050_SENSOR_ACCL);
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -601,14 +593,12 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
|
||||||
min_sleep_us = period_us;
|
min_sleep_us = period_us;
|
||||||
max_sleep_us = period_us + period_us / 2;
|
max_sleep_us = period_us + period_us / 2;
|
||||||
usleep_range(min_sleep_us, max_sleep_us);
|
usleep_range(min_sleep_us, max_sleep_us);
|
||||||
|
}
|
||||||
ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
|
ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
|
||||||
chan->channel2, val);
|
chan->channel2, val);
|
||||||
result = inv_mpu6050_switch_engine(st, false,
|
|
||||||
INV_MPU6050_SENSOR_ACCL);
|
|
||||||
if (result)
|
|
||||||
goto error_power_off;
|
|
||||||
break;
|
break;
|
||||||
case IIO_TEMP:
|
case IIO_TEMP:
|
||||||
|
if (!st->chip_config.temp_en) {
|
||||||
result = inv_mpu6050_switch_engine(st, true,
|
result = inv_mpu6050_switch_engine(st, true,
|
||||||
INV_MPU6050_SENSOR_TEMP);
|
INV_MPU6050_SENSOR_TEMP);
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -617,14 +607,12 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
|
||||||
min_sleep_us = period_us;
|
min_sleep_us = period_us;
|
||||||
max_sleep_us = period_us + period_us / 2;
|
max_sleep_us = period_us + period_us / 2;
|
||||||
usleep_range(min_sleep_us, max_sleep_us);
|
usleep_range(min_sleep_us, max_sleep_us);
|
||||||
|
}
|
||||||
ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
|
ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
|
||||||
IIO_MOD_X, val);
|
IIO_MOD_X, val);
|
||||||
result = inv_mpu6050_switch_engine(st, false,
|
|
||||||
INV_MPU6050_SENSOR_TEMP);
|
|
||||||
if (result)
|
|
||||||
goto error_power_off;
|
|
||||||
break;
|
break;
|
||||||
case IIO_MAGN:
|
case IIO_MAGN:
|
||||||
|
if (!st->chip_config.magn_en) {
|
||||||
result = inv_mpu6050_switch_engine(st, true,
|
result = inv_mpu6050_switch_engine(st, true,
|
||||||
INV_MPU6050_SENSOR_MAGN);
|
INV_MPU6050_SENSOR_MAGN);
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -638,25 +626,21 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev,
|
||||||
min_sleep_us = 2 * period_us;
|
min_sleep_us = 2 * period_us;
|
||||||
max_sleep_us = 2 * (period_us + period_us / 2);
|
max_sleep_us = 2 * (period_us + period_us / 2);
|
||||||
usleep_range(min_sleep_us, max_sleep_us);
|
usleep_range(min_sleep_us, max_sleep_us);
|
||||||
|
}
|
||||||
ret = inv_mpu_magn_read(st, chan->channel2, val);
|
ret = inv_mpu_magn_read(st, chan->channel2, val);
|
||||||
result = inv_mpu6050_switch_engine(st, false,
|
|
||||||
INV_MPU6050_SENSOR_MAGN);
|
|
||||||
if (result)
|
|
||||||
goto error_power_off;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = inv_mpu6050_set_power_itg(st, false);
|
pm_runtime_mark_last_busy(pdev);
|
||||||
if (result)
|
pm_runtime_put_autosuspend(pdev);
|
||||||
goto error_power_off;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
error_power_off:
|
error_power_off:
|
||||||
inv_mpu6050_set_power_itg(st, false);
|
pm_runtime_put_autosuspend(pdev);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,6 +779,7 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
|
||||||
int val, int val2, long mask)
|
int val, int val2, long mask)
|
||||||
{
|
{
|
||||||
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
||||||
|
struct device *pdev = regmap_get_device(st->map);
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -806,9 +791,11 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
mutex_lock(&st->lock);
|
mutex_lock(&st->lock);
|
||||||
result = inv_mpu6050_set_power_itg(st, true);
|
result = pm_runtime_get_sync(pdev);
|
||||||
if (result)
|
if (result < 0) {
|
||||||
|
pm_runtime_put_noidle(pdev);
|
||||||
goto error_write_raw_unlock;
|
goto error_write_raw_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
switch (mask) {
|
switch (mask) {
|
||||||
case IIO_CHAN_INFO_SCALE:
|
case IIO_CHAN_INFO_SCALE:
|
||||||
|
@ -846,7 +833,8 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
result |= inv_mpu6050_set_power_itg(st, false);
|
pm_runtime_mark_last_busy(pdev);
|
||||||
|
pm_runtime_put_autosuspend(pdev);
|
||||||
error_write_raw_unlock:
|
error_write_raw_unlock:
|
||||||
mutex_unlock(&st->lock);
|
mutex_unlock(&st->lock);
|
||||||
iio_device_release_direct_mode(indio_dev);
|
iio_device_release_direct_mode(indio_dev);
|
||||||
|
@ -903,6 +891,7 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
|
||||||
int result;
|
int result;
|
||||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||||
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
||||||
|
struct device *pdev = regmap_get_device(st->map);
|
||||||
|
|
||||||
if (kstrtoint(buf, 10, &fifo_rate))
|
if (kstrtoint(buf, 10, &fifo_rate))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -920,9 +909,11 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
|
||||||
result = 0;
|
result = 0;
|
||||||
goto fifo_rate_fail_unlock;
|
goto fifo_rate_fail_unlock;
|
||||||
}
|
}
|
||||||
result = inv_mpu6050_set_power_itg(st, true);
|
result = pm_runtime_get_sync(pdev);
|
||||||
if (result)
|
if (result < 0) {
|
||||||
|
pm_runtime_put_noidle(pdev);
|
||||||
goto fifo_rate_fail_unlock;
|
goto fifo_rate_fail_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
result = regmap_write(st->map, st->reg->sample_rate_div, d);
|
result = regmap_write(st->map, st->reg->sample_rate_div, d);
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -938,8 +929,9 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
|
||||||
if (result)
|
if (result)
|
||||||
goto fifo_rate_fail_power_off;
|
goto fifo_rate_fail_power_off;
|
||||||
|
|
||||||
|
pm_runtime_mark_last_busy(pdev);
|
||||||
fifo_rate_fail_power_off:
|
fifo_rate_fail_power_off:
|
||||||
result |= inv_mpu6050_set_power_itg(st, false);
|
pm_runtime_put_autosuspend(pdev);
|
||||||
fifo_rate_fail_unlock:
|
fifo_rate_fail_unlock:
|
||||||
mutex_unlock(&st->lock);
|
mutex_unlock(&st->lock);
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -1385,6 +1377,14 @@ static void inv_mpu_core_disable_regulator_action(void *_data)
|
||||||
inv_mpu_core_disable_regulator_vddio(st);
|
inv_mpu_core_disable_regulator_vddio(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void inv_mpu_pm_disable(void *data)
|
||||||
|
{
|
||||||
|
struct device *dev = data;
|
||||||
|
|
||||||
|
pm_runtime_put_sync_suspend(dev);
|
||||||
|
pm_runtime_disable(dev);
|
||||||
|
}
|
||||||
|
|
||||||
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||||
int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type)
|
int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type)
|
||||||
{
|
{
|
||||||
|
@ -1409,7 +1409,6 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||||
st = iio_priv(indio_dev);
|
st = iio_priv(indio_dev);
|
||||||
mutex_init(&st->lock);
|
mutex_init(&st->lock);
|
||||||
st->chip_type = chip_type;
|
st->chip_type = chip_type;
|
||||||
st->powerup_count = 0;
|
|
||||||
st->irq = irq;
|
st->irq = irq;
|
||||||
st->map = regmap;
|
st->map = regmap;
|
||||||
|
|
||||||
|
@ -1521,8 +1520,16 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||||
goto error_power_off;
|
goto error_power_off;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* chip init is done, turning off */
|
/* chip init is done, turning on runtime power management */
|
||||||
result = inv_mpu6050_set_power_itg(st, false);
|
result = pm_runtime_set_active(dev);
|
||||||
|
if (result)
|
||||||
|
goto error_power_off;
|
||||||
|
pm_runtime_get_noresume(dev);
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
pm_runtime_set_autosuspend_delay(dev, INV_MPU6050_SUSPEND_DELAY_MS);
|
||||||
|
pm_runtime_use_autosuspend(dev);
|
||||||
|
pm_runtime_put(dev);
|
||||||
|
result = devm_add_action_or_reset(dev, inv_mpu_pm_disable, dev);
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
@ -1590,11 +1597,10 @@ error_power_off:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(inv_mpu_core_probe);
|
EXPORT_SYMBOL_GPL(inv_mpu_core_probe);
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
static int __maybe_unused inv_mpu_resume(struct device *dev)
|
||||||
|
|
||||||
static int inv_mpu_resume(struct device *dev)
|
|
||||||
{
|
{
|
||||||
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||||
|
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
mutex_lock(&st->lock);
|
mutex_lock(&st->lock);
|
||||||
|
@ -1603,27 +1609,101 @@ static int inv_mpu_resume(struct device *dev)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
result = inv_mpu6050_set_power_itg(st, true);
|
result = inv_mpu6050_set_power_itg(st, true);
|
||||||
|
if (result)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
result = inv_mpu6050_switch_engine(st, true, st->suspended_sensors);
|
||||||
|
if (result)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
if (iio_buffer_enabled(indio_dev))
|
||||||
|
result = inv_mpu6050_prepare_fifo(st, true);
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&st->lock);
|
mutex_unlock(&st->lock);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int inv_mpu_suspend(struct device *dev)
|
static int __maybe_unused inv_mpu_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||||
|
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
mutex_lock(&st->lock);
|
mutex_lock(&st->lock);
|
||||||
|
|
||||||
|
if (iio_buffer_enabled(indio_dev)) {
|
||||||
|
result = inv_mpu6050_prepare_fifo(st, false);
|
||||||
|
if (result)
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->suspended_sensors = 0;
|
||||||
|
if (st->chip_config.accl_en)
|
||||||
|
st->suspended_sensors |= INV_MPU6050_SENSOR_ACCL;
|
||||||
|
if (st->chip_config.gyro_en)
|
||||||
|
st->suspended_sensors |= INV_MPU6050_SENSOR_GYRO;
|
||||||
|
if (st->chip_config.temp_en)
|
||||||
|
st->suspended_sensors |= INV_MPU6050_SENSOR_TEMP;
|
||||||
|
if (st->chip_config.magn_en)
|
||||||
|
st->suspended_sensors |= INV_MPU6050_SENSOR_MAGN;
|
||||||
|
result = inv_mpu6050_switch_engine(st, false, st->suspended_sensors);
|
||||||
|
if (result)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
result = inv_mpu6050_set_power_itg(st, false);
|
result = inv_mpu6050_set_power_itg(st, false);
|
||||||
|
if (result)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
inv_mpu_core_disable_regulator_vddio(st);
|
inv_mpu_core_disable_regulator_vddio(st);
|
||||||
|
out_unlock:
|
||||||
mutex_unlock(&st->lock);
|
mutex_unlock(&st->lock);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
|
||||||
|
|
||||||
SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume);
|
static int __maybe_unused inv_mpu_runtime_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
|
||||||
|
unsigned int sensors;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&st->lock);
|
||||||
|
|
||||||
|
sensors = INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_GYRO |
|
||||||
|
INV_MPU6050_SENSOR_TEMP | INV_MPU6050_SENSOR_MAGN;
|
||||||
|
ret = inv_mpu6050_switch_engine(st, false, sensors);
|
||||||
|
if (ret)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
ret = inv_mpu6050_set_power_itg(st, false);
|
||||||
|
if (ret)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
inv_mpu_core_disable_regulator_vddio(st);
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
mutex_unlock(&st->lock);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused inv_mpu_runtime_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = inv_mpu_core_enable_regulator_vddio(st);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return inv_mpu6050_set_power_itg(st, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct dev_pm_ops inv_mpu_pmops = {
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(inv_mpu_suspend, inv_mpu_resume)
|
||||||
|
SET_RUNTIME_PM_OPS(inv_mpu_runtime_suspend, inv_mpu_runtime_resume, NULL)
|
||||||
|
};
|
||||||
EXPORT_SYMBOL_GPL(inv_mpu_pmops);
|
EXPORT_SYMBOL_GPL(inv_mpu_pmops);
|
||||||
|
|
||||||
MODULE_AUTHOR("Invensense Corporation");
|
MODULE_AUTHOR("Invensense Corporation");
|
||||||
|
|
|
@ -164,6 +164,7 @@ struct inv_mpu6050_hw {
|
||||||
* @magn_disabled: magnetometer disabled for backward compatibility reason.
|
* @magn_disabled: magnetometer disabled for backward compatibility reason.
|
||||||
* @magn_raw_to_gauss: coefficient to convert mag raw value to Gauss.
|
* @magn_raw_to_gauss: coefficient to convert mag raw value to Gauss.
|
||||||
* @magn_orient: magnetometer sensor chip orientation if available.
|
* @magn_orient: magnetometer sensor chip orientation if available.
|
||||||
|
* @suspended_sensors: sensors mask of sensors turned off for suspend
|
||||||
*/
|
*/
|
||||||
struct inv_mpu6050_state {
|
struct inv_mpu6050_state {
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
|
@ -174,7 +175,6 @@ struct inv_mpu6050_state {
|
||||||
enum inv_devices chip_type;
|
enum inv_devices chip_type;
|
||||||
struct i2c_mux_core *muxc;
|
struct i2c_mux_core *muxc;
|
||||||
struct i2c_client *mux_client;
|
struct i2c_client *mux_client;
|
||||||
unsigned int powerup_count;
|
|
||||||
struct inv_mpu6050_platform_data plat_data;
|
struct inv_mpu6050_platform_data plat_data;
|
||||||
struct iio_mount_matrix orientation;
|
struct iio_mount_matrix orientation;
|
||||||
struct regmap *map;
|
struct regmap *map;
|
||||||
|
@ -189,6 +189,7 @@ struct inv_mpu6050_state {
|
||||||
bool magn_disabled;
|
bool magn_disabled;
|
||||||
s32 magn_raw_to_gauss[3];
|
s32 magn_raw_to_gauss[3];
|
||||||
struct iio_mount_matrix magn_orient;
|
struct iio_mount_matrix magn_orient;
|
||||||
|
unsigned int suspended_sensors;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*register and associated bit definition*/
|
/*register and associated bit definition*/
|
||||||
|
@ -312,6 +313,7 @@ struct inv_mpu6050_state {
|
||||||
#define INV_MPU6050_ACCEL_UP_TIME 20
|
#define INV_MPU6050_ACCEL_UP_TIME 20
|
||||||
#define INV_MPU6050_GYRO_UP_TIME 35
|
#define INV_MPU6050_GYRO_UP_TIME 35
|
||||||
#define INV_MPU6050_GYRO_DOWN_TIME 150
|
#define INV_MPU6050_GYRO_DOWN_TIME 150
|
||||||
|
#define INV_MPU6050_SUSPEND_DELAY_MS 2000
|
||||||
|
|
||||||
/* delay time in microseconds */
|
/* delay time in microseconds */
|
||||||
#define INV_MPU6050_REG_UP_TIME_MIN 5000
|
#define INV_MPU6050_REG_UP_TIME_MIN 5000
|
||||||
|
@ -439,7 +441,6 @@ int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable);
|
||||||
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en,
|
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en,
|
||||||
unsigned int mask);
|
unsigned int mask);
|
||||||
int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
|
int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
|
||||||
int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
|
|
||||||
int inv_mpu_acpi_create_mux_client(struct i2c_client *client);
|
int inv_mpu_acpi_create_mux_client(struct i2c_client *client);
|
||||||
void inv_mpu_acpi_delete_mux_client(struct i2c_client *client);
|
void inv_mpu_acpi_delete_mux_client(struct i2c_client *client);
|
||||||
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* Copyright (C) 2012 Invensense, Inc.
|
* Copyright (C) 2012 Invensense, Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include "inv_mpu_iio.h"
|
#include "inv_mpu_iio.h"
|
||||||
|
|
||||||
static unsigned int inv_scan_query_mpu6050(struct iio_dev *indio_dev)
|
static unsigned int inv_scan_query_mpu6050(struct iio_dev *indio_dev)
|
||||||
|
@ -156,41 +157,43 @@ int inv_mpu6050_prepare_fifo(struct inv_mpu6050_state *st, bool enable)
|
||||||
static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
|
static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
|
||||||
{
|
{
|
||||||
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
struct inv_mpu6050_state *st = iio_priv(indio_dev);
|
||||||
|
struct device *pdev = regmap_get_device(st->map);
|
||||||
unsigned int scan;
|
unsigned int scan;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
scan = inv_scan_query(indio_dev);
|
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
result = inv_mpu6050_set_power_itg(st, true);
|
scan = inv_scan_query(indio_dev);
|
||||||
if (result)
|
result = pm_runtime_get_sync(pdev);
|
||||||
|
if (result < 0) {
|
||||||
|
pm_runtime_put_noidle(pdev);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* In case autosuspend didn't trigger, turn off first not
|
||||||
|
* required sensors.
|
||||||
|
*/
|
||||||
|
result = inv_mpu6050_switch_engine(st, false, ~scan);
|
||||||
|
if (result)
|
||||||
|
goto error_power_off;
|
||||||
result = inv_mpu6050_switch_engine(st, true, scan);
|
result = inv_mpu6050_switch_engine(st, true, scan);
|
||||||
if (result)
|
if (result)
|
||||||
goto error_power_off;
|
goto error_power_off;
|
||||||
st->skip_samples = inv_compute_skip_samples(st);
|
st->skip_samples = inv_compute_skip_samples(st);
|
||||||
result = inv_mpu6050_prepare_fifo(st, true);
|
result = inv_mpu6050_prepare_fifo(st, true);
|
||||||
if (result)
|
if (result)
|
||||||
goto error_sensors_off;
|
goto error_power_off;
|
||||||
} else {
|
} else {
|
||||||
result = inv_mpu6050_prepare_fifo(st, false);
|
result = inv_mpu6050_prepare_fifo(st, false);
|
||||||
if (result)
|
|
||||||
goto error_sensors_off;
|
|
||||||
result = inv_mpu6050_switch_engine(st, false, scan);
|
|
||||||
if (result)
|
|
||||||
goto error_power_off;
|
|
||||||
|
|
||||||
result = inv_mpu6050_set_power_itg(st, false);
|
|
||||||
if (result)
|
if (result)
|
||||||
goto error_power_off;
|
goto error_power_off;
|
||||||
|
pm_runtime_mark_last_busy(pdev);
|
||||||
|
pm_runtime_put_autosuspend(pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_sensors_off:
|
|
||||||
inv_mpu6050_switch_engine(st, false, scan);
|
|
||||||
error_power_off:
|
error_power_off:
|
||||||
inv_mpu6050_set_power_itg(st, false);
|
pm_runtime_put_autosuspend(pdev);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue