/* * this is the gyro scale translated from dynamic range plus/minus * {250, 500, 1000, 2000} to rad/s
*/ staticconstint gyro_scale_6050[] = {133090, 266181, 532362, 1064724};
/* * this is the accel scale translated from dynamic range plus/minus * {2, 4, 8, 16} to m/s^2
*/ staticconstint accel_scale[] = {598, 1196, 2392, 4785};
staticint inv_mpu6050_pwr_mgmt_1_write(struct inv_mpu6050_state *st, bool sleep, bool cycle, int clock, int temp_dis)
{
u8 val;
if (clock < 0)
clock = st->chip_config.clk; if (temp_dis < 0)
temp_dis = !st->chip_config.temp_en;
val = clock & INV_MPU6050_BIT_CLK_MASK; if (temp_dis)
val |= INV_MPU6050_BIT_TEMP_DIS; if (sleep)
val |= INV_MPU6050_BIT_SLEEP; if (cycle)
val |= INV_MPU6050_BIT_CYCLE;
staticint inv_mpu6050_clock_switch(struct inv_mpu6050_state *st, unsignedint clock)
{ int ret;
switch (st->chip_type) { case INV_MPU6050: case INV_MPU6000: case INV_MPU9150: /* old chips: switch clock manually */
ret = inv_mpu6050_pwr_mgmt_1_write(st, false, false, clock, -1); if (ret) return ret;
st->chip_config.clk = clock; break; default: /* automatic clock switching, nothing to do */ break;
}
return 0;
}
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, unsignedint mask)
{ unsignedint sleep, val;
u8 pwr_mgmt2, user_ctrl; int ret;
/* delete useless requests */ if (mask & INV_MPU6050_SENSOR_ACCL && en == st->chip_config.accl_en)
mask &= ~INV_MPU6050_SENSOR_ACCL; if (mask & INV_MPU6050_SENSOR_GYRO && en == st->chip_config.gyro_en)
mask &= ~INV_MPU6050_SENSOR_GYRO; if (mask & INV_MPU6050_SENSOR_TEMP && en == st->chip_config.temp_en)
mask &= ~INV_MPU6050_SENSOR_TEMP; if (mask & INV_MPU6050_SENSOR_MAGN && en == st->chip_config.magn_en)
mask &= ~INV_MPU6050_SENSOR_MAGN; if (mask & INV_MPU6050_SENSOR_WOM && en == st->chip_config.wom_en)
mask &= ~INV_MPU6050_SENSOR_WOM;
/* force accel on if WoM is on and not going off */ if (!en && (mask & INV_MPU6050_SENSOR_ACCL) && st->chip_config.wom_en &&
!(mask & INV_MPU6050_SENSOR_WOM))
mask &= ~INV_MPU6050_SENSOR_ACCL;
if (mask == 0) return 0;
/* turn on/off temperature sensor */ if (mask & INV_MPU6050_SENSOR_TEMP) {
ret = inv_mpu6050_pwr_mgmt_1_write(st, false, false, -1, !en); if (ret) return ret;
st->chip_config.temp_en = en;
}
/* update user_crtl for driving magnetometer */ if (mask & INV_MPU6050_SENSOR_MAGN) {
user_ctrl = st->chip_config.user_ctrl; if (en)
user_ctrl |= INV_MPU6050_BIT_I2C_MST_EN; else
user_ctrl &= ~INV_MPU6050_BIT_I2C_MST_EN;
ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl); if (ret) return ret;
st->chip_config.user_ctrl = user_ctrl;
st->chip_config.magn_en = en;
}
/* manage accel & gyro engines */ if (mask & (INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_GYRO)) { /* compute power management 2 current value */
pwr_mgmt2 = 0; if (!st->chip_config.accl_en)
pwr_mgmt2 |= INV_MPU6050_BIT_PWR_ACCL_STBY; if (!st->chip_config.gyro_en)
pwr_mgmt2 |= INV_MPU6050_BIT_PWR_GYRO_STBY;
/* update to new requested value */ if (mask & INV_MPU6050_SENSOR_ACCL) { if (en)
pwr_mgmt2 &= ~INV_MPU6050_BIT_PWR_ACCL_STBY; else
pwr_mgmt2 |= INV_MPU6050_BIT_PWR_ACCL_STBY;
} if (mask & INV_MPU6050_SENSOR_GYRO) { if (en)
pwr_mgmt2 &= ~INV_MPU6050_BIT_PWR_GYRO_STBY; else
pwr_mgmt2 |= INV_MPU6050_BIT_PWR_GYRO_STBY;
}
/* switch clock to internal when turning gyro off */ if (mask & INV_MPU6050_SENSOR_GYRO && !en) {
ret = inv_mpu6050_clock_switch(st, INV_CLK_INTERNAL); if (ret) return ret;
}
/* update sensors engine */
dev_dbg(regmap_get_device(st->map), "pwr_mgmt_2: 0x%x\n",
pwr_mgmt2);
ret = regmap_write(st->map, st->reg->pwr_mgmt_2, pwr_mgmt2); if (ret) return ret; if (mask & INV_MPU6050_SENSOR_ACCL)
st->chip_config.accl_en = en; if (mask & INV_MPU6050_SENSOR_GYRO)
st->chip_config.gyro_en = en;
/* compute required time to have sensors stabilized */
sleep = 0; if (en) { if (mask & INV_MPU6050_SENSOR_ACCL) { if (sleep < st->hw->startup_time.accel)
sleep = st->hw->startup_time.accel;
} if (mask & INV_MPU6050_SENSOR_GYRO) { if (sleep < st->hw->startup_time.gyro)
sleep = st->hw->startup_time.gyro;
}
} else { if (mask & INV_MPU6050_SENSOR_GYRO) { if (sleep < INV_MPU6050_GYRO_DOWN_TIME)
sleep = INV_MPU6050_GYRO_DOWN_TIME;
}
} if (sleep)
msleep(sleep);
/* switch clock to PLL when turning gyro on */ if (mask & INV_MPU6050_SENSOR_GYRO && en) {
ret = inv_mpu6050_clock_switch(st, INV_CLK_PLL); if (ret) return ret;
}
}
/* enable/disable accel intelligence control */ if (mask & INV_MPU6050_SENSOR_WOM) {
val = en ? INV_MPU6500_BIT_ACCEL_INTEL_EN |
INV_MPU6500_BIT_ACCEL_INTEL_MODE : 0;
ret = regmap_write(st->map, INV_MPU6500_REG_ACCEL_INTEL_CTRL, val); if (ret) return ret;
st->chip_config.wom_en = en;
}
return 0;
}
staticint inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
{ int result;
result = inv_mpu6050_pwr_mgmt_1_write(st, !power_on, false, -1, -1); if (result) return result;
if (power_on)
usleep_range(INV_MPU6050_REG_UP_TIME_MIN,
INV_MPU6050_REG_UP_TIME_MAX);
data = val << gyro_shift; return regmap_write(st->map, st->reg->gyro_config, data);
}
staticint inv_mpu6050_set_accel_lpf_regs(struct inv_mpu6050_state *st, enum inv_mpu6050_filter_e val)
{ switch (st->chip_type) { case INV_MPU6050: case INV_MPU6000: case INV_MPU9150: /* old chips, nothing to do */ return 0; case INV_ICM20689: case INV_ICM20690: case INV_IAM20680HT: case INV_IAM20680HP: /* set FIFO size to maximum value */
val |= INV_ICM20689_BITS_FIFO_SIZE_MAX; break; default: break;
}
/* * inv_mpu6050_set_lpf_regs() - set low pass filter registers, chip dependent * * MPU60xx/MPU9150 use only 1 register for accelerometer + gyroscope * MPU6500 and above have a dedicated register for accelerometer
*/ staticint inv_mpu6050_set_lpf_regs(struct inv_mpu6050_state *st, enum inv_mpu6050_filter_e val)
{ int result;
result = regmap_write(st->map, st->reg->lpf, val); if (result) return result;
/* set accel lpf */ return inv_mpu6050_set_accel_lpf_regs(st, val);
}
result = inv_mpu6050_set_gyro_fsr(st, st->chip_config.fsr); if (result) return result;
result = inv_mpu6050_set_lpf_regs(st, st->chip_config.lpf); if (result) return result;
d = st->chip_config.divider;
result = regmap_write(st->map, st->reg->sample_rate_div, d); if (result) return result;
d = (st->chip_config.accl_fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
result = regmap_write(st->map, st->reg->accl_config, d); if (result) return result;
result = regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask); if (result) return result;
result = pm_runtime_resume_and_get(pdev); if (result) return result;
switch (chan->type) { case IIO_ANGL_VEL: if (!st->chip_config.gyro_en) {
result = inv_mpu6050_switch_engine(st, true,
INV_MPU6050_SENSOR_GYRO); if (result) goto error_power_off; /* need to wait 2 periods to have first valid sample */
min_sleep_us = 2 * period_us;
max_sleep_us = 2 * (period_us + period_us / 2);
usleep_range(min_sleep_us, max_sleep_us);
}
ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
chan->channel2, val); break; case IIO_ACCEL: if (!st->chip_config.accl_en) {
result = inv_mpu6050_switch_engine(st, true,
INV_MPU6050_SENSOR_ACCL); if (result) goto error_power_off; /* wait 1 period for first sample availability */
min_sleep_us = period_us;
max_sleep_us = period_us + period_us / 2;
usleep_range(min_sleep_us, max_sleep_us);
}
ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
chan->channel2, val); break; case IIO_TEMP: /* temperature sensor work only with accel and/or gyro */ if (!st->chip_config.accl_en && !st->chip_config.gyro_en) {
result = -EBUSY; goto error_power_off;
} if (!st->chip_config.temp_en) {
result = inv_mpu6050_switch_engine(st, true,
INV_MPU6050_SENSOR_TEMP); if (result) goto error_power_off; /* wait 1 period for first sample availability */
min_sleep_us = period_us;
max_sleep_us = period_us + period_us / 2;
usleep_range(min_sleep_us, max_sleep_us);
}
ret = inv_mpu6050_sensor_show(st, st->reg->temperature,
IIO_MOD_X, val); break; case IIO_MAGN: if (!st->chip_config.magn_en) {
result = inv_mpu6050_switch_engine(st, true,
INV_MPU6050_SENSOR_MAGN); if (result) goto error_power_off; /* frequency is limited for magnetometer */ if (freq_hz > INV_MPU_MAGN_FREQ_HZ_MAX) {
freq_hz = INV_MPU_MAGN_FREQ_HZ_MAX;
period_us = 1000000 / freq_hz;
} /* need to wait 2 periods to have first valid sample */
min_sleep_us = 2 * period_us;
max_sleep_us = 2 * (period_us + period_us / 2);
usleep_range(min_sleep_us, max_sleep_us);
}
ret = inv_mpu_magn_read(st, chan->channel2, val); break; default:
ret = -EINVAL; break;
}
staticint
inv_mpu6050_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct inv_mpu6050_state *st = iio_priv(indio_dev); int ret = 0;
switch (mask) { case IIO_CHAN_INFO_RAW: if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
mutex_lock(&st->lock);
ret = inv_mpu6050_read_channel_data(indio_dev, chan, val);
mutex_unlock(&st->lock);
iio_device_release_direct(indio_dev); return ret; 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);
staticint inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val, int val2)
{ int result, i;
if (val != 0) return -EINVAL;
for (i = 0; i < ARRAY_SIZE(gyro_scale_6050); ++i) { if (gyro_scale_6050[i] == val2) {
result = inv_mpu6050_set_gyro_fsr(st, i); if (result) return result;
staticint inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val, int val2)
{ int result, i;
u8 d;
if (val != 0) return -EINVAL;
for (i = 0; i < ARRAY_SIZE(accel_scale); ++i) { if (accel_scale[i] == val2) {
d = (i << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
result = regmap_write(st->map, st->reg->accl_config, d); if (result) return result;
st->chip_config.accl_fs = i; return 0;
}
}
return -EINVAL;
}
staticint inv_mpu6050_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ struct inv_mpu6050_state *st = iio_priv(indio_dev); struct device *pdev = regmap_get_device(st->map); int result;
/* * we should only update scale when the chip is disabled, i.e. * not running
*/ if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
mutex_lock(&st->lock);
result = pm_runtime_resume_and_get(pdev); if (result) goto error_write_raw_unlock;
switch (mask) { case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL:
result = inv_mpu6050_write_gyro_scale(st, val, val2); break; case IIO_ACCEL:
result = inv_mpu6050_write_accel_scale(st, val, val2); break; default:
result = -EINVAL; break;
} break; case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { case IIO_ANGL_VEL:
result = inv_mpu6050_sensor_set(st,
st->reg->gyro_offset,
chan->channel2, val); break; case IIO_ACCEL:
result = inv_mpu6050_sensor_set(st,
st->reg->accl_offset,
chan->channel2, val); break; default:
result = -EINVAL; break;
} break; default:
result = -EINVAL; break;
}
switch (st->chip_type) { case INV_MPU6050: case INV_MPU6500: case INV_MPU6515: case INV_MPU6880: case INV_MPU6000: case INV_MPU9150: case INV_MPU9250: case INV_MPU9255:
reg_val = INV_MPU6500_BIT_WOM_INT_EN; break; default:
reg_val = INV_ICM20608_BIT_WOM_INT_EN; break;
}
/* convert roc to wom threshold and convert back to handle clipping */
threshold = inv_mpu6050_convert_roc_to_wom(value, freq_div);
value = inv_mpu6050_convert_wom_to_roc(threshold, freq_div);
switch (st->chip_type) { case INV_ICM20609: case INV_ICM20689: case INV_ICM20600: case INV_ICM20602: case INV_ICM20690: /* nothing to do */
*lp_div = INV_MPU6050_FREQ_DIVIDER(st); return 0; default: break;
}
/* found the nearest superior frequency divider */
i = ARRAY_SIZE(reg_values) - 1;
val = reg_values[i];
*lp_div = freq_dividers[i]; for (i = 0; i < ARRAY_SIZE(freq_dividers); ++i) { if (freq_div <= freq_dividers[i]) {
val = reg_values[i];
*lp_div = freq_dividers[i]; break;
}
}
if (en) {
result = pm_runtime_resume_and_get(pdev); if (result) return result;
mask = INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_WOM;
result = inv_mpu6050_switch_engine(st, true, mask); if (result) goto error_suspend;
result = inv_mpu6050_set_wom_int(st, true); if (result) goto error_suspend;
} else {
result = inv_mpu6050_set_wom_int(st, false); if (result)
dev_err(pdev, "error %d disabling WoM interrupt bit", result);
/* disable only WoM and let accel be disabled by autosuspend */
result = inv_mpu6050_switch_engine(st, false, INV_MPU6050_SENSOR_WOM); if (result) {
dev_err(pdev, "error %d disabling WoM force off", result); /* force WoM off */
st->chip_config.wom_en = false;
}
/* support only WoM (accel roc rising) event value */ if (chan->type != IIO_ACCEL || type != IIO_EV_TYPE_ROC ||
dir != IIO_EV_DIR_RISING || info != IIO_EV_INFO_VALUE) return -EINVAL;
guard(mutex)(&st->lock);
/* return value in micro */
*val = div_u64_rem(st->chip_config.roc_threshold, 1000000U, &rem);
*val2 = rem;
/* support only WoM (accel roc rising) event value */ if (chan->type != IIO_ACCEL || type != IIO_EV_TYPE_ROC ||
dir != IIO_EV_DIR_RISING || info != IIO_EV_INFO_VALUE) return -EINVAL;
if (val < 0 || val2 < 0) return -EINVAL;
guard(mutex)(&st->lock);
result = pm_runtime_resume_and_get(pdev); if (result) return result;
value = (u64)val * 1000000ULL + (u64)val2;
result = inv_mpu6050_set_wom_threshold(st, value, INV_MPU6050_FREQ_DIVIDER(st));
/* * inv_mpu6050_set_lpf() - set low pass filer based on fifo rate. * * Based on the Nyquist principle, the bandwidth of the low * pass filter must not exceed the signal sampling rate divided * by 2, or there would be aliasing. * This function basically search for the correct low pass * parameters based on the fifo rate, e.g, sampling frequency. * * lpf is set automatically when setting sampling rate to avoid any aliases.
*/ staticint inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate)
{ staticconstint hz[] = {400, 200, 90, 40, 20, 10}; staticconstint d[] = {
INV_MPU6050_FILTER_200HZ, INV_MPU6050_FILTER_100HZ,
INV_MPU6050_FILTER_45HZ, INV_MPU6050_FILTER_20HZ,
INV_MPU6050_FILTER_10HZ, INV_MPU6050_FILTER_5HZ
}; int i, result;
u8 data;
data = INV_MPU6050_FILTER_5HZ; for (i = 0; i < ARRAY_SIZE(hz); ++i) { if (rate >= hz[i]) {
data = d[i]; break;
}
}
result = inv_mpu6050_set_lpf_regs(st, data); if (result) return result;
st->chip_config.lpf = data;
if (kstrtoint(buf, 10, &fifo_rate)) return -EINVAL; if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE ||
fifo_rate > INV_MPU6050_MAX_FIFO_RATE) return -EINVAL;
/* compute the chip sample rate divider */
d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(fifo_rate); /* compute back the fifo rate to handle truncation cases */
fifo_rate = INV_MPU6050_DIVIDER_TO_FIFO_RATE(d);
fifo_period = NSEC_PER_SEC / fifo_rate;
mutex_lock(&st->lock); if (d == st->chip_config.divider) {
result = 0; goto fifo_rate_fail_unlock;
}
fifo_on = st->chip_config.accl_fifo_enable ||
st->chip_config.gyro_fifo_enable ||
st->chip_config.magn_fifo_enable;
result = inv_sensors_timestamp_update_odr(&st->timestamp, fifo_period, fifo_on); if (result) goto fifo_rate_fail_unlock;
result = pm_runtime_resume_and_get(pdev); if (result) goto fifo_rate_fail_unlock;
result = regmap_write(st->map, st->reg->sample_rate_div, d); if (result) goto fifo_rate_fail_power_off;
st->chip_config.divider = d;
result = inv_mpu6050_set_lpf(st, fifo_rate); if (result) goto fifo_rate_fail_power_off;
/* update rate for magn, noop if not present in chip */
result = inv_mpu_magn_set_rate(st, fifo_rate); if (result) goto fifo_rate_fail_power_off;
/* update wom threshold since roc is dependent on sampling frequency */
result = inv_mpu6050_set_wom_threshold(st, st->chip_config.roc_threshold,
INV_MPU6050_FREQ_DIVIDER(st)); if (result) goto fifo_rate_fail_power_off;
pm_runtime_mark_last_busy(pdev);
fifo_rate_fail_power_off:
pm_runtime_put_autosuspend(pdev);
fifo_rate_fail_unlock:
mutex_unlock(&st->lock); if (result) return result;
return count;
}
/* * inv_fifo_rate_show() - Get the current sampling rate.
*/ static ssize_t
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;
/* * inv_attr_show() - calling this function will show current * parameters. * * Deprecated in favor of IIO mounting matrix API. * * See inv_get_mount_matrix()
*/ static ssize_t inv_attr_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev)); struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
s8 *m;
switch (this_attr->address) { /* * In MPU6050, the two matrix are the same because gyro and accel * are integrated in one chip
*/ case ATTR_GYRO_MATRIX: case ATTR_ACCL_MATRIX:
m = st->plat_data.orientation;
/* * The user can choose any frequency between INV_MPU6050_MIN_FIFO_RATE and * INV_MPU6050_MAX_FIFO_RATE, but only these frequencies are matched by the * low-pass filter. Specifically, each of these sampling rates are about twice * the bandwidth of a corresponding low-pass filter, which should eliminate * aliasing following the Nyquist principle. By picking a frequency different * from these, the user risks aliasing effects.
*/ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500"); static IIO_CONST_ATTR(in_anglvel_scale_available, "0.000133090 0.000266181 0.000532362 0.001064724"); static IIO_CONST_ATTR(in_accel_scale_available, "0.000598 0.001196 0.002392 0.004785"); static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show,
inv_mpu6050_fifo_rate_store);
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);
/* check chip self-identification */
result = regmap_read(st->map, INV_MPU6050_REG_WHOAMI, ®val); if (result) return result; if (regval != st->hw->whoami) { /* 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 0x%02x (%s) expected 0x%02x (%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 0x%02x expected 0x%02x (%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); switch (st->chip_type) { case INV_MPU6000: case INV_MPU6500: case INV_MPU6515: case INV_MPU6880: case INV_MPU9250: case INV_MPU9255: /* reset signal path (required for spi connection) */
regval = INV_MPU6050_BIT_TEMP_RST | INV_MPU6050_BIT_ACCEL_RST |
INV_MPU6050_BIT_GYRO_RST;
result = regmap_write(st->map, INV_MPU6050_REG_SIGNAL_PATH_RESET,
regval); if (result) return result;
msleep(INV_MPU6050_POWER_UP_TIME); break; default: break;
}
/* * Turn power on. After reset, the sleep bit could be on * or off depending on the OTP settings. Turning power on * make it in a definite state as well as making the hardware * state align with the software state
*/
result = inv_mpu6050_set_power_itg(st, true); if (result) return result;
mask = INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_GYRO |
INV_MPU6050_SENSOR_TEMP | INV_MPU6050_SENSOR_MAGN;
result = inv_mpu6050_switch_engine(st, false, mask); if (result) goto error_power_off;
staticint inv_mpu_core_enable_regulator_vddio(struct inv_mpu6050_state *st)
{ int result;
result = regulator_enable(st->vddio_supply); if (result) {
dev_err(regmap_get_device(st->map), "Failed to enable vddio regulator: %d\n", result);
} else { /* Give the device a little bit of time to start up. */
usleep_range(3000, 5000);
}
return result;
}
staticint inv_mpu_core_disable_regulator_vddio(struct inv_mpu6050_state *st)
{ int result;
result = regulator_disable(st->vddio_supply); if (result)
dev_err(regmap_get_device(st->map), "Failed to disable vddio regulator: %d\n", result);
st->vdd_supply = devm_regulator_get(dev, "vdd"); if (IS_ERR(st->vdd_supply)) return dev_err_probe(dev, PTR_ERR(st->vdd_supply), "Failed to get vdd regulator\n");
st->vddio_supply = devm_regulator_get(dev, "vddio"); if (IS_ERR(st->vddio_supply)) return dev_err_probe(dev, PTR_ERR(st->vddio_supply), "Failed to get vddio regulator\n");
result = regulator_enable(st->vdd_supply); if (result) {
dev_err(dev, "Failed to enable vdd regulator: %d\n", result); return result;
}
msleep(INV_MPU6050_POWER_UP_TIME);
result = inv_mpu_core_enable_regulator_vddio(st); if (result) {
regulator_disable(st->vdd_supply); return result;
}
result = devm_add_action_or_reset(dev, inv_mpu_core_disable_regulator_action,
st); if (result) {
dev_err(dev, "Failed to setup regulator cleanup action %d\n",
result); return result;
}
/* fill magnetometer orientation */
result = inv_mpu_magn_set_orient(st); if (result) return result;
/* power is turned on inside check chip type*/
result = inv_check_and_setup_chip(st); if (result) return result;
result = inv_mpu6050_init_config(indio_dev); if (result) {
dev_err(dev, "Could not initialize device.\n"); goto error_power_off;
}
dev_set_drvdata(dev, indio_dev); /* name will be NULL when enumerated via ACPI */ if (name)
indio_dev->name = name; else
indio_dev->name = dev_name(dev);
/* requires parent device set in indio_dev */ if (inv_mpu_bus_setup) {
result = inv_mpu_bus_setup(indio_dev); if (result) goto error_power_off;
}
/* chip init is done, turning on runtime power management */
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) return result;
switch (chip_type) { case INV_MPU6000: case INV_MPU6050:
indio_dev->channels = inv_mpu6050_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu6050_channels);
indio_dev->available_scan_masks = inv_mpu_scan_masks; break; case INV_MPU9150:
indio_dev->channels = inv_mpu9150_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu9150_channels);
indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; break; case INV_MPU9250: case INV_MPU9255:
indio_dev->channels = inv_mpu9250_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; break; case INV_IAM20380:
indio_dev->channels = inv_iam20380_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_iam20380_channels);
indio_dev->available_scan_masks = inv_iam20380_scan_masks; break; case INV_ICM20600: case INV_ICM20602:
indio_dev->channels = inv_mpu6500_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu6500_channels);
indio_dev->available_scan_masks = inv_icm20602_scan_masks; break; default:
indio_dev->channels = inv_mpu6500_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu6500_channels);
indio_dev->available_scan_masks = inv_mpu_scan_masks; break;
} /* * Use magnetometer inside the chip only if there is no i2c * auxiliary device in use. Otherwise Going back to 6-axis only.
*/ if (st->magn_disabled) { switch (chip_type) { case INV_MPU9150:
indio_dev->channels = inv_mpu6050_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu6050_channels);
indio_dev->available_scan_masks = inv_mpu_scan_masks; break; default:
indio_dev->channels = inv_mpu6500_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu6500_channels);
indio_dev->available_scan_masks = inv_mpu_scan_masks; break;
}
}
indio_dev->info = &mpu_info;
if (irq > 0) { /* * The driver currently only supports buffered capture with its * own trigger. So no IRQ, no trigger, no buffer
*/
result = devm_iio_triggered_buffer_setup(dev, indio_dev,
iio_pollfunc_store_time,
inv_mpu6050_read_fifo,
NULL); if (result) {
dev_err(dev, "configure buffer fail %d\n", result); return result;
}
result = inv_mpu6050_probe_trigger(indio_dev, irq_type); if (result) {
dev_err(dev, "trigger probe fail %d\n", result); return result;
}
}
result = devm_iio_device_register(dev, indio_dev); if (result) {
dev_err(dev, "IIO register fail %d\n", result); return result;
}
if (wakeup) {
enable_irq(st->irq);
disable_irq_wake(st->irq);
result = inv_mpu6050_set_wom_lp(st, false); if (result) return result;
} else {
result = inv_mpu_core_enable_regulator_vddio(st); if (result) return result;
result = inv_mpu6050_set_power_itg(st, true); if (result) return result;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.