summaryrefslogtreecommitdiffstats
path: root/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/imu/inv_mpu6050/inv_mpu_core.c')
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c183
1 files changed, 110 insertions, 73 deletions
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index 88a7c5d4e4d2..44830bce13df 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -188,7 +188,6 @@ int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
int result = 0;
if (power_on) {
- /* Already under indio-dev->mlock mutex */
if (!st->powerup_count)
result = regmap_write(st->map, st->reg->pwr_mgmt_1, 0);
if (!result)
@@ -329,50 +328,37 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
int result;
ret = IIO_VAL_INT;
- result = 0;
- mutex_lock(&indio_dev->mlock);
- if (!st->chip_config.enable) {
- result = inv_mpu6050_set_power_itg(st, true);
- if (result)
- goto error_read_raw;
- }
- /* when enable is on, power is already on */
+ mutex_lock(&st->lock);
+ result = iio_device_claim_direct_mode(indio_dev);
+ if (result)
+ goto error_read_raw_unlock;
+ result = inv_mpu6050_set_power_itg(st, true);
+ if (result)
+ goto error_read_raw_release;
switch (chan->type) {
case IIO_ANGL_VEL:
- if (!st->chip_config.gyro_fifo_enable ||
- !st->chip_config.enable) {
- result = inv_mpu6050_switch_engine(st, true,
- INV_MPU6050_BIT_PWR_GYRO_STBY);
- if (result)
- goto error_read_raw;
- }
+ result = inv_mpu6050_switch_engine(st, true,
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
+ if (result)
+ goto error_read_raw_power_off;
ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
chan->channel2, val);
- if (!st->chip_config.gyro_fifo_enable ||
- !st->chip_config.enable) {
- result = inv_mpu6050_switch_engine(st, false,
- INV_MPU6050_BIT_PWR_GYRO_STBY);
- if (result)
- goto error_read_raw;
- }
+ result = inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_GYRO_STBY);
+ if (result)
+ goto error_read_raw_power_off;
break;
case IIO_ACCEL:
- if (!st->chip_config.accl_fifo_enable ||
- !st->chip_config.enable) {
- result = inv_mpu6050_switch_engine(st, true,
- INV_MPU6050_BIT_PWR_ACCL_STBY);
- if (result)
- goto error_read_raw;
- }
+ result = inv_mpu6050_switch_engine(st, true,
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
+ if (result)
+ goto error_read_raw_power_off;
ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
chan->channel2, val);
- if (!st->chip_config.accl_fifo_enable ||
- !st->chip_config.enable) {
- result = inv_mpu6050_switch_engine(st, false,
- INV_MPU6050_BIT_PWR_ACCL_STBY);
- if (result)
- goto error_read_raw;
- }
+ result = inv_mpu6050_switch_engine(st, false,
+ INV_MPU6050_BIT_PWR_ACCL_STBY);
+ if (result)
+ goto error_read_raw_power_off;
break;
case IIO_TEMP:
/* wait for stablization */
@@ -384,10 +370,12 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev,
ret = -EINVAL;
break;
}
-error_read_raw:
- if (!st->chip_config.enable)
- result |= inv_mpu6050_set_power_itg(st, false);
- mutex_unlock(&indio_dev->mlock);
+error_read_raw_power_off:
+ result |= inv_mpu6050_set_power_itg(st, false);
+error_read_raw_release:
+ iio_device_release_direct_mode(indio_dev);
+error_read_raw_unlock:
+ mutex_unlock(&st->lock);
if (result)
return result;
@@ -396,13 +384,17 @@ error_read_raw:
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
+ mutex_lock(&st->lock);
*val = 0;
*val2 = gyro_scale_6050[st->chip_config.fsr];
+ mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_NANO;
case IIO_ACCEL:
+ mutex_lock(&st->lock);
*val = 0;
*val2 = accel_scale[st->chip_config.accl_fs];
+ mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP:
@@ -425,12 +417,16 @@ error_read_raw:
case IIO_CHAN_INFO_CALIBBIAS:
switch (chan->type) {
case IIO_ANGL_VEL:
+ mutex_lock(&st->lock);
ret = inv_mpu6050_sensor_show(st, st->reg->gyro_offset,
chan->channel2, val);
+ mutex_unlock(&st->lock);
return IIO_VAL_INT;
case IIO_ACCEL:
+ mutex_lock(&st->lock);
ret = inv_mpu6050_sensor_show(st, st->reg->accl_offset,
chan->channel2, val);
+ mutex_unlock(&st->lock);
return IIO_VAL_INT;
default:
@@ -506,18 +502,17 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
struct inv_mpu6050_state *st = iio_priv(indio_dev);
int result;
- mutex_lock(&indio_dev->mlock);
+ mutex_lock(&st->lock);
/*
* we should only update scale when the chip is disabled, i.e.
* not running
*/
- if (st->chip_config.enable) {
- result = -EBUSY;
- goto error_write_raw;
- }
+ result = iio_device_claim_direct_mode(indio_dev);
+ if (result)
+ goto error_write_raw_unlock;
result = inv_mpu6050_set_power_itg(st, true);
if (result)
- goto error_write_raw;
+ goto error_write_raw_release;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
@@ -553,9 +548,11 @@ static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
break;
}
-error_write_raw:
result |= inv_mpu6050_set_power_itg(st, false);
- mutex_unlock(&indio_dev->mlock);
+error_write_raw_release:
+ iio_device_release_direct_mode(indio_dev);
+error_write_raw_unlock:
+ mutex_unlock(&st->lock);
return result;
}
@@ -611,31 +608,35 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr,
if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE ||
fifo_rate > INV_MPU6050_MAX_FIFO_RATE)
return -EINVAL;
- if (fifo_rate == st->chip_config.fifo_rate)
- return count;
- mutex_lock(&indio_dev->mlock);
- if (st->chip_config.enable) {
- result = -EBUSY;
- goto fifo_rate_fail;
+ mutex_lock(&st->lock);
+ if (fifo_rate == st->chip_config.fifo_rate) {
+ result = 0;
+ goto fifo_rate_fail_unlock;
}
+ result = iio_device_claim_direct_mode(indio_dev);
+ if (result)
+ goto fifo_rate_fail_unlock;
result = inv_mpu6050_set_power_itg(st, true);
if (result)
- goto fifo_rate_fail;
+ goto fifo_rate_fail_release;
d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1;
result = regmap_write(st->map, st->reg->sample_rate_div, d);
if (result)
- goto fifo_rate_fail;
+ goto fifo_rate_fail_power_off;
st->chip_config.fifo_rate = fifo_rate;
result = inv_mpu6050_set_lpf(st, fifo_rate);
if (result)
- goto fifo_rate_fail;
+ goto fifo_rate_fail_power_off;
-fifo_rate_fail:
+fifo_rate_fail_power_off:
result |= inv_mpu6050_set_power_itg(st, false);
- mutex_unlock(&indio_dev->mlock);
+fifo_rate_fail_release:
+ iio_device_release_direct_mode(indio_dev);
+fifo_rate_fail_unlock:
+ mutex_unlock(&st->lock);
if (result)
return result;
@@ -650,8 +651,13 @@ inv_fifo_rate_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev));
+ unsigned fifo_rate;
+
+ mutex_lock(&st->lock);
+ fifo_rate = st->chip_config.fifo_rate;
+ mutex_unlock(&st->lock);
- return sprintf(buf, "%d\n", st->chip_config.fifo_rate);
+ return scnprintf(buf, PAGE_SIZE, "%u\n", fifo_rate);
}
/**
@@ -678,7 +684,8 @@ static ssize_t inv_attr_show(struct device *dev, struct device_attribute *attr,
case ATTR_ACCL_MATRIX:
m = st->plat_data.orientation;
- return sprintf(buf, "%d, %d, %d; %d, %d, %d; %d, %d, %d\n",
+ return scnprintf(buf, PAGE_SIZE,
+ "%d, %d, %d; %d, %d, %d; %d, %d, %d\n",
m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
default:
return -EINVAL;
@@ -803,27 +810,42 @@ static int inv_check_and_setup_chip(struct inv_mpu6050_state *st)
{
int result;
unsigned int regval;
+ int i;
st->hw = &hw_info[st->chip_type];
st->reg = hw_info[st->chip_type].reg;
- /* reset to make sure previous state are not there */
- result = regmap_write(st->map, st->reg->pwr_mgmt_1,
- INV_MPU6050_BIT_H_RESET);
- if (result)
- return result;
- msleep(INV_MPU6050_POWER_UP_TIME);
-
/* check chip self-identification */
result = regmap_read(st->map, INV_MPU6050_REG_WHOAMI, &regval);
if (result)
return result;
if (regval != st->hw->whoami) {
- dev_warn(regmap_get_device(st->map),
- "whoami mismatch got %#02x expected %#02hhx for %s\n",
+ /* check whoami against all possible values */
+ for (i = 0; i < INV_NUM_PARTS; ++i) {
+ if (regval == hw_info[i].whoami) {
+ dev_warn(regmap_get_device(st->map),
+ "whoami mismatch got %#02x (%s)"
+ "expected %#02hhx (%s)\n",
+ regval, hw_info[i].name,
+ st->hw->whoami, st->hw->name);
+ break;
+ }
+ }
+ if (i >= INV_NUM_PARTS) {
+ dev_err(regmap_get_device(st->map),
+ "invalid whoami %#02x expected %#02hhx (%s)\n",
regval, st->hw->whoami, st->hw->name);
+ return -ENODEV;
+ }
}
+ /* reset to make sure previous state are not there */
+ result = regmap_write(st->map, st->reg->pwr_mgmt_1,
+ INV_MPU6050_BIT_H_RESET);
+ if (result)
+ return result;
+ msleep(INV_MPU6050_POWER_UP_TIME);
+
/*
* toggle power state. After reset, the sleep bit could be on
* or off depending on the OTP settings. Toggling power would
@@ -869,6 +891,7 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
return -ENODEV;
}
st = iio_priv(indio_dev);
+ mutex_init(&st->lock);
st->chip_type = chip_type;
st->powerup_count = 0;
st->irq = irq;
@@ -962,12 +985,26 @@ EXPORT_SYMBOL_GPL(inv_mpu_core_remove);
static int inv_mpu_resume(struct device *dev)
{
- return inv_mpu6050_set_power_itg(iio_priv(dev_get_drvdata(dev)), true);
+ struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
+ int result;
+
+ mutex_lock(&st->lock);
+ result = inv_mpu6050_set_power_itg(st, true);
+ mutex_unlock(&st->lock);
+
+ return result;
}
static int inv_mpu_suspend(struct device *dev)
{
- return inv_mpu6050_set_power_itg(iio_priv(dev_get_drvdata(dev)), false);
+ struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
+ int result;
+
+ mutex_lock(&st->lock);
+ result = inv_mpu6050_set_power_itg(st, false);
+ mutex_unlock(&st->lock);
+
+ return result;
}
#endif /* CONFIG_PM_SLEEP */