/* Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include "nvi.h" #include "nvi_dmp_icm.h" #define BYTES_PER_SENSOR 6 /* full scale and LPF setting */ #define ICM_SELFTEST_GYRO_FS ((0 << 3) | 1) #define ICM_SELFTEST_ACCEL_FS ((7 << 3) | 1) /* register settings */ #define ICM_SELFTEST_GYRO_SMPLRT_DIV 10 #define ICM_SELFTEST_GYRO_AVGCFG 3 #define ICM_SELFTEST_ACCEL_SMPLRT_DIV 10 #define ICM_SELFTEST_ACCEL_DEC3_CFG 2 #define ICM_SELFTEST_GYRO_SENS (32768 / 250) #define BIT_ACCEL_CTEN 0x1C #define BIT_GYRO_CTEN 0x38 /* wait time before collecting data */ #define ICM_MAX_PACKETS 20 #define ICM_SELFTEST_WAIT_TIME (ICM_MAX_PACKETS * 10) #define ICM_GYRO_ENGINE_UP_TIME 50 #define ICM_ST_STABLE_TIME 20 #define ICM_GYRO_SCALE 131 #define ICM_ST_PRECISION 1000 #define ICM_ST_ACCEL_FS_MG 2000UL #define ICM_ST_SCALE 32768 #define ICM_ST_TRY_TIMES 2 #define ICM_ST_SAMPLES 200 #define ICM_ACCEL_ST_SHIFT_DELTA_MIN 500 #define ICM_ACCEL_ST_SHIFT_DELTA_MAX 1500 #define ICM_GYRO_CT_SHIFT_DELTA 500 /* Gyro Offset Max Value (dps) */ #define ICM_GYRO_OFFSET_MAX 20 /* Gyro Self Test Absolute Limits ST_AL (dps) */ #define ICM_GYRO_ST_AL 60 /* Accel Self Test Absolute Limits ST_AL (mg) */ #define ICM_ACCEL_ST_AL_MIN ((225 * ICM_ST_SCALE \ / ICM_ST_ACCEL_FS_MG) * ICM_ST_PRECISION) #define ICM_ACCEL_ST_AL_MAX ((675 * ICM_ST_SCALE \ / ICM_ST_ACCEL_FS_MG) * ICM_ST_PRECISION) static const u16 icm_st_tb[256] = { 2620, 2646, 2672, 2699, 2726, 2753, 2781, 2808, 2837, 2865, 2894, 2923, 2952, 2981, 3011, 3041, 3072, 3102, 3133, 3165, 3196, 3228, 3261, 3293, 3326, 3359, 3393, 3427, 3461, 3496, 3531, 3566, 3602, 3638, 3674, 3711, 3748, 3786, 3823, 3862, 3900, 3939, 3979, 4019, 4059, 4099, 4140, 4182, 4224, 4266, 4308, 4352, 4395, 4439, 4483, 4528, 4574, 4619, 4665, 4712, 4759, 4807, 4855, 4903, 4953, 5002, 5052, 5103, 5154, 5205, 5257, 5310, 5363, 5417, 5471, 5525, 5581, 5636, 5693, 5750, 5807, 5865, 5924, 5983, 6043, 6104, 6165, 6226, 6289, 6351, 6415, 6479, 6544, 6609, 6675, 6742, 6810, 6878, 6946, 7016, 7086, 7157, 7229, 7301, 7374, 7448, 7522, 7597, 7673, 7750, 7828, 7906, 7985, 8065, 8145, 8227, 8309, 8392, 8476, 8561, 8647, 8733, 8820, 8909, 8998, 9088, 9178, 9270, 9363, 9457, 9551, 9647, 9743, 9841, 9939, 10038, 10139, 10240, 10343, 10446, 10550, 10656, 10763, 10870, 10979, 11089, 11200, 11312, 11425, 11539, 11654, 11771, 11889, 12008, 12128, 12249, 12371, 12495, 12620, 12746, 12874, 13002, 13132, 13264, 13396, 13530, 13666, 13802, 13940, 14080, 14221, 14363, 14506, 14652, 14798, 14946, 15096, 15247, 15399, 15553, 15709, 15866, 16024, 16184, 16346, 16510, 16675, 16842, 17010, 17180, 17352, 17526, 17701, 17878, 18057, 18237, 18420, 18604, 18790, 18978, 19167, 19359, 19553, 19748, 19946, 20145, 20347, 20550, 20756, 20963, 21173, 21385, 21598, 21814, 22033, 22253, 22475, 22700, 22927, 23156, 23388, 23622, 23858, 24097, 24338, 24581, 24827, 25075, 25326, 25579, 25835, 26093, 26354, 26618, 26884, 27153, 27424, 27699, 27976, 28255, 28538, 28823, 29112, 29403, 29697, 29994, 30294, 30597, 30903, 31212, 31524, 31839, 32157, 32479, 32804 }; /** * inv_icm_st_gyr_chk() - check gyro self test. * this function returns zero as success. A non-zero return * value indicates failure in self test. * @*st: main data structure. * @*reg_avg: average value of normal test. * @*st_avg: average value of self test */ static int inv_icm_st_gyr_chk(struct nvi_state *st, int *reg_avg, int *st_avg) { u8 *regs; int ret = 0; int otp_value_zero = 0; int st_shift_prod[AXIS_N]; int st_shift_cust[AXIS_N]; int i; regs = &st->st_data[DEV_GYR][0]; if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s data: %02x %02x %02x\n", __func__, regs[0], regs[1], regs[2]); for (i = 0; i < AXIS_N; i++) { if (regs[i] != 0) { st_shift_prod[i] = icm_st_tb[regs[i] - 1]; } else { st_shift_prod[i] = 0; otp_value_zero = 1; } } if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s st_shift_prod: %+d %+d %+d\n", __func__, st_shift_prod[0], st_shift_prod[1], st_shift_prod[2]); for (i = 0; i < AXIS_N; i++) { st_shift_cust[i] = st_avg[i] - reg_avg[i]; if (!otp_value_zero) { /* Self Test Pass/Fail Criteria A */ if (st_shift_cust[i] < (ICM_GYRO_CT_SHIFT_DELTA * st_shift_prod[i])) { ret = 1; if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s FAIL A axis %d\n", __func__, i); } } else { /* Self Test Pass/Fail Criteria B */ if (st_shift_cust[i] < (ICM_GYRO_ST_AL * ICM_SELFTEST_GYRO_SENS * ICM_ST_PRECISION)) { ret = 1; if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s FAIL B axis %d\n", __func__, i); } } } if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s st_shift_cust: %+d %+d %+d\n", __func__, st_shift_cust[0], st_shift_cust[1], st_shift_cust[2]); if (ret == 0) { /* Self Test Pass/Fail Criteria C */ for (i = 0; i < AXIS_N; i++) { if (abs(reg_avg[i]) > (ICM_GYRO_OFFSET_MAX * ICM_SELFTEST_GYRO_SENS * ICM_ST_PRECISION)) { ret = 1; if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s FAIL C axis %d\n", __func__, i); } } } return ret; } /** * inv_icm_st_acc_chk() - check accel self test. * this function returns zero as success. A non-zero return * value indicates failure in self test. * @*st: main data structure. * @*reg_avg: average value of normal test. * @*st_avg: average value of self test */ static int inv_icm_st_acc_chk(struct nvi_state *st, int *reg_avg, int *st_avg) { u8 *regs; int i; int st_shift_prod[AXIS_N]; int st_shift_cust[AXIS_N]; int otp_value_zero = 0; int ret = 0; regs = &st->st_data[DEV_ACC][0]; if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s data: %02x %02x %02x\n", __func__, regs[0], regs[1], regs[2]); for (i = 0; i < AXIS_N; i++) { if (regs[i] != 0) { st_shift_prod[i] = icm_st_tb[regs[i] - 1]; } else { st_shift_prod[i] = 0; otp_value_zero = 1; } } if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s st_shift_prod: %+d %+d %+d\n", __func__, st_shift_prod[0], st_shift_prod[1], st_shift_prod[2]); if (!otp_value_zero) { /* Self Test Pass/Fail Criteria A */ for (i = 0; i < AXIS_N; i++) { st_shift_cust[i] = st_avg[i] - reg_avg[i]; if (st_shift_cust[i] < (ICM_ACCEL_ST_SHIFT_DELTA_MIN * st_shift_prod[i])) { ret = 1; if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s FAIL A (min) axis %d\n", __func__, i); } if (st_shift_cust[i] > (ICM_ACCEL_ST_SHIFT_DELTA_MAX * st_shift_prod[i])) { ret = 1; if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s FAIL A (max) axis %d\n", __func__, i); } } } else { /* Self Test Pass/Fail Criteria B */ for (i = 0; i < AXIS_N; i++) { st_shift_cust[i] = abs(st_avg[i] - reg_avg[i]); if ((st_shift_cust[i] < ICM_ACCEL_ST_AL_MIN) || (st_shift_cust[i] > ICM_ACCEL_ST_AL_MAX)) { ret = 1; if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s FAIL B axis %d\n", __func__, i); } } } if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s st_shift_cust: %+d %+d %+d\n", __func__, st_shift_cust[0], st_shift_cust[1], st_shift_cust[2]); return ret; } static int inv_icm_st_setup(struct nvi_state *st) { int axis; int ret; /* Wake up and stop sensors */ ret = nvi_pm_wr(st, __func__, INV_CLK_PLL, BIT_PWR_PRESSURE_STBY | BIT_PWR_ACCEL_STBY | BIT_PWR_GYRO_STBY, 0); /* Perform a soft-reset of the chip * This will clear any prior states in the chip */ ret |= nvi_wr_pm1(st, __func__, BIT_H_RESET); if (ret) return ret; msleep(POWER_UP_TIME); /* Wake up */ ret = nvi_wr_pm1(st, __func__, INV_CLK_PLL); ret |= nvi_i2c_wr_rc(st, &st->hal->reg->user_ctrl, BIT_FIFO_EN, __func__, &st->rc.user_ctrl); /* Configure FIFO */ ret |= nvi_wr_fifo_cfg(st, -1); /* Set cycle mode */ ret |= nvi_i2c_wr_rc(st, &st->hal->reg->lp_config, 0x70, __func__, &st->rc.lp_config); /* Configure FSR and DLPF */ ret |= nvi_i2c_write_rc(st, &st->hal->reg->smplrt[DEV_GYR], ICM_SELFTEST_GYRO_SMPLRT_DIV, __func__, (u8 *)&st->rc.smplrt[DEV_GYR], true); ret |= nvi_i2c_wr_rc(st, &st->hal->reg->gyro_config1, ICM_SELFTEST_GYRO_FS, __func__, &st->rc.gyro_config1); ret |= nvi_i2c_wr_rc(st, &st->hal->reg->gyro_config2, ICM_SELFTEST_GYRO_AVGCFG, __func__, &st->rc.gyro_config2); ret |= nvi_i2c_write_rc(st, &st->hal->reg->smplrt[DEV_ACC], ICM_SELFTEST_ACCEL_SMPLRT_DIV, __func__, (u8 *)&st->rc.smplrt[DEV_ACC], true); ret |= nvi_i2c_wr_rc(st, &st->hal->reg->accel_config, ICM_SELFTEST_ACCEL_FS, __func__, &st->rc.accel_config); ret |= nvi_i2c_wr_rc(st, &st->hal->reg->accel_config2, ICM_SELFTEST_ACCEL_DEC3_CFG, __func__, &st->rc.accel_config2); if (ret) return ret; /* Read selftest values */ for (axis = 0; axis < AXIS_N; axis++) ret |= nvi_i2c_rd(st, &st->hal->reg->self_test_g[axis], &st->st_data[DEV_GYR][axis]); for (axis = 0; axis < AXIS_N; axis++) ret |= nvi_i2c_rd(st, &st->hal->reg->self_test_a[axis], &st->st_data[DEV_ACC][axis]); ret |= nvi_pm_wr(st, __func__, INV_CLK_PLL, BIT_PWR_PRESSURE_STBY, 0x70); if (ret) return ret; msleep(ICM_GYRO_ENGINE_UP_TIME); return ret; } static int inv_icm_st_rd(struct nvi_state *st, int dev, int *sum_result, int *s) { u16 fifo_count; s16 vals[AXIS_N]; u8 d[ICM_MAX_PACKETS * BYTES_PER_SENSOR]; int packet_count; int i; int j; int t; int ret; ret = nvi_i2c_write_rc(st, &st->hal->reg->fifo_en, 0, __func__, (u8 *)&st->rc.fifo_en, false); /* Reset FIFO */ ret |= nvi_i2c_wr(st, &st->hal->reg->fifo_rst, 0x1F, __func__); ret |= nvi_i2c_wr(st, &st->hal->reg->fifo_rst, 0x1E, __func__); if (ret) return ret; while (*s < ICM_ST_SAMPLES) { ret = nvi_i2c_write_rc(st, &st->hal->reg->fifo_en, st->hal->dev[dev]->fifo_en_msk, __func__, (u8 *)&st->rc.fifo_en, false); if (ret) return ret; msleep(ICM_SELFTEST_WAIT_TIME); ret = nvi_i2c_write_rc(st, &st->hal->reg->fifo_en, 0, __func__, (u8 *)&st->rc.fifo_en, false); if (ret) return ret; ret = nvi_i2c_rd(st, &st->hal->reg->fifo_count_h, d); if (ret) return ret; fifo_count = be16_to_cpup((__be16 *)(&d[0])); if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s fifo_count=%d\n", __func__, fifo_count); if (ICM_MAX_PACKETS * BYTES_PER_SENSOR < fifo_count) { ret = nvi_i2c_r(st, st->hal->reg->fifo_rw.bank, st->hal->reg->fifo_rw.reg, ICM_MAX_PACKETS * BYTES_PER_SENSOR, d); packet_count = ICM_MAX_PACKETS; } else { ret = nvi_i2c_r(st, st->hal->reg->fifo_rw.bank, st->hal->reg->fifo_rw.reg, fifo_count, d); packet_count = fifo_count / BYTES_PER_SENSOR; } if (ret) return ret; i = 0; while (i < packet_count) { for (j = 0; j < AXIS_N; j++) { t = 2 * j + i * BYTES_PER_SENSOR; vals[j] = (s16)be16_to_cpup((__be16 *)(&d[t])); sum_result[j] += vals[j]; } if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s %s %d: %+d %+d %+d\n", __func__, st->snsr[dev].cfg.name, *s, vals[0], vals[1], vals[2]); (*s)++; i++; } } return 0; } /* * inv_icm_st_acc_do() - do the actual test of self testing */ static int inv_icm_st_acc_do(struct nvi_state *st, int *accel_result, int *accel_st_result) { int accel_s; int i; int j; int ret; for (i = 0; i < AXIS_N; i++) { accel_result[i] = 0; accel_st_result[i] = 0; } accel_s = 0; ret = inv_icm_st_rd(st, DEV_ACC, accel_result, &accel_s); if (ret || accel_s <= 0) return -1; for (j = 0; j < AXIS_N; j++) { accel_result[j] = accel_result[j] / accel_s; accel_result[j] *= ICM_ST_PRECISION; } /* Set Self-Test Bit */ ret = nvi_i2c_wr_rc(st, &st->hal->reg->accel_config2, BIT_ACCEL_CTEN | ICM_SELFTEST_ACCEL_DEC3_CFG, __func__, &st->rc.accel_config2); if (ret) return ret; msleep(ICM_ST_STABLE_TIME); accel_s = 0; ret = inv_icm_st_rd(st, DEV_ACC, accel_st_result, &accel_s); if (ret || accel_s <= 0) return -1; for (j = 0; j < AXIS_N; j++) { accel_st_result[j] = accel_st_result[j] / accel_s; accel_st_result[j] *= ICM_ST_PRECISION; } if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s %d, %d, %d\n", __func__, accel_result[0], accel_result[1], accel_result[2]); return 0; } /* * inv_icm_st_gyr_do() - do the actual test of self testing */ static int inv_icm_st_gyr_do(struct nvi_state *st, int *gyro_result, int *gyro_st_result) { int gyro_s; int i; int j; int ret; for (i = 0; i < AXIS_N; i++) { gyro_result[i] = 0; gyro_st_result[i] = 0; } gyro_s = 0; ret = inv_icm_st_rd(st, DEV_GYR, gyro_result, &gyro_s); if (ret || gyro_s <= 0) return -1; for (j = 0; j < AXIS_N; j++) { gyro_result[j] = gyro_result[j] / gyro_s; gyro_result[j] *= ICM_ST_PRECISION; } /* Set Self-Test Bit */ ret = nvi_i2c_wr_rc(st, &st->hal->reg->gyro_config2, BIT_GYRO_CTEN | ICM_SELFTEST_GYRO_AVGCFG, __func__, &st->rc.gyro_config2); if (ret) return ret; msleep(ICM_ST_STABLE_TIME); gyro_s = 0; ret = inv_icm_st_rd(st, DEV_GYR, gyro_st_result, &gyro_s); if (ret || gyro_s <= 0) return -1; for (j = 0; j < AXIS_N; j++) { gyro_st_result[j] = gyro_st_result[j] / gyro_s; gyro_st_result[j] *= ICM_ST_PRECISION; } if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s %d, %d, %d\n", __func__, gyro_result[0], gyro_result[1], gyro_result[2]); return 0; } static int inv_st_gyr_icm(struct nvi_state *st) { int ret; int gyr_bias_st[AXIS_N]; int gyr_bias_regular[AXIS_N]; int test_times; int i; char gyro_result; ret = inv_icm_st_setup(st); if (ret) return ret; test_times = ICM_ST_TRY_TIMES; while (test_times > 0) { ret = inv_icm_st_gyr_do(st, gyr_bias_regular, gyr_bias_st); if (ret == -EAGAIN) test_times--; else test_times = 0; } if (ret) return ret; if (st->sts & NVI_DBG_SPEW_MSG) { dev_info(&st->i2c->dev, "%s gyro bias_regular: %+d %+d %+d\n", __func__, gyr_bias_regular[0], gyr_bias_regular[1], gyr_bias_regular[2]); dev_info(&st->i2c->dev, "%s gyro bias_st: %+d %+d %+d\n", __func__, gyr_bias_st[0], gyr_bias_st[1], gyr_bias_st[2]); } for (i = 0; i < AXIS_N; i++) st->bias[DEV_GYR][i] = (gyr_bias_regular[i] / ICM_ST_PRECISION); gyro_result = inv_icm_st_gyr_chk(st, gyr_bias_regular, gyr_bias_st); if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s gyro_result %hhd\n", __func__, gyro_result); return gyro_result; } static int inv_st_acc_icm(struct nvi_state *st) { int ret; int acc_bias_st[AXIS_N]; int acc_bias_regular[AXIS_N]; int test_times; int i; char accel_result; ret = inv_icm_st_setup(st); if (ret) return ret; test_times = ICM_ST_TRY_TIMES; while (test_times > 0) { ret = inv_icm_st_acc_do(st, acc_bias_regular, acc_bias_st); if (ret == -EAGAIN) test_times--; else break; } if (ret) return ret; if (st->sts & NVI_DBG_SPEW_MSG) { dev_info(&st->i2c->dev, "%s acc_bias_regular: %+d %+d %+d\n", __func__, acc_bias_regular[0], acc_bias_regular[1], acc_bias_regular[2]); dev_info(&st->i2c->dev, "%s acc_bias_st: %+d %+d %+d\n", __func__, acc_bias_st[0], acc_bias_st[1], acc_bias_st[2]); } for (i = 0; i < AXIS_N; i++) st->bias[DEV_ACC][i] = (acc_bias_regular[i] / ICM_ST_PRECISION); accel_result = inv_icm_st_acc_chk(st, acc_bias_regular, acc_bias_st); if (st->sts & NVI_DBG_SPEW_MSG) dev_info(&st->i2c->dev, "%s accel_result %hhd\n", __func__, accel_result); return accel_result; } static int nvi_pm_icm(struct nvi_state *st, u8 pm1, u8 pm2, u8 lp) { int ret; ret = nvi_i2c_wr_rc(st, &st->hal->reg->lp_config, 0x70, __func__, &st->rc.lp_config); /* the DMP changes pm2 so we can't use the cache */ ret |= nvi_i2c_wr(st, &st->hal->reg->pm2, pm2, __func__); ret |= nvi_i2c_wr_rc(st, &st->hal->reg->pm1, pm1, __func__, &st->rc.pm1); return ret; } static int nvi_en_gyr_icm(struct nvi_state *st) { u8 val; int i; int ret = 0; st->snsr[DEV_GYR].buf_n = 6; for (i = 0; i < AXIS_N; i++) ret |= nvi_wr_gyro_offset(st, i, (u16)(st->rom_offset[DEV_GYR][i] + st->dev_offset[DEV_GYR][i])); ret |= nvi_i2c_wr_rc(st, &st->hal->reg->gyro_config2, 0, __func__, &st->rc.gyro_config2); val = (st->snsr[DEV_GYR].usr_cfg << 1) | 0x01; ret |= nvi_i2c_wr_rc(st, &st->hal->reg->gyro_config1, val, __func__, &st->rc.gyro_config1); return ret; } static int nvi_en_acc_icm(struct nvi_state *st) { u8 val; int i; int ret = 0; st->snsr[DEV_ACC].buf_n = 6; st->snsr[DEV_ACC].buf_shft = 0; for (i = 0; i < AXIS_N; i++) ret |= nvi_wr_accel_offset(st, i, (u16)(st->rom_offset[DEV_ACC][i] + (st->dev_offset[DEV_ACC][i] << 1))); ret |= nvi_i2c_wr_rc(st, &st->hal->reg->accel_config2, 0, __func__, &st->rc.accel_config2); val = (st->snsr[DEV_ACC].usr_cfg << 1); ret |= nvi_i2c_wr_rc(st, &st->hal->reg->accel_config, val, __func__, &st->rc.accel_config); return ret; } static int nvi_init_icm(struct nvi_state *st) { u8 val; s8 t; unsigned int src; int ret; st->snsr[DEV_ACC].cfg.thresh_hi = 0; /* no ACC LP on ICM */ st->snsr[DEV_SM].cfg.thresh_lo = ICM_SMD_THLD_INIT; st->snsr[DEV_SM].cfg.thresh_hi = ICM_SMD_THLD_N_INIT; st->snsr[DEV_SM].cfg.delay_us_min = ICM_SMD_TIMER_INIT; st->snsr[DEV_SM].cfg.delay_us_max = ICM_SMD_TIMER2_INIT; st->snsr[DEV_SM].cfg.report_n = ICM_SMD_RESET_INIT; ret = nvi_i2c_rd(st, &st->hal->reg->tbc_pll, &val); if (ret) return ret; t = abs(val & 0x7F); if (val & 0x80) t = -t; st->src[SRC_GYR].base_t = NSEC_PER_SEC - t * 769903 + ((t * 769903) / 1270) * t; st->src[SRC_ACC].base_t = NSEC_PER_SEC; st->src[SRC_AUX].base_t = NSEC_PER_SEC; for (src = 0; src < st->hal->src_n; src++) st->src[src].base_t /= ICM_BASE_SAMPLE_RATE; /* calculate the period_us_max */ st->src[SRC_GYR].period_us_max = (st->src[SRC_GYR].base_t * 0xFF) / 1000; /* WAR: limit SRC_ACC to SRC_GYR since same period required by WAR */ st->src[SRC_ACC].period_us_max = st->src[SRC_GYR].period_us_max; st->src[SRC_AUX].period_us_max = st->hal->src[SRC_AUX].period_us_max; for (src = 0; src < st->hal->src_n; src++) st->src[src].period_us_min = st->hal->src[src].period_us_min; nvi_en_gyr_icm(st); nvi_en_acc_icm(st); return 0; } struct nvi_fn nvi_fn_icm = { .pm = nvi_pm_icm, .init = nvi_init_icm, .st_acc = inv_st_acc_icm, .st_gyr = inv_st_gyr_icm, .en_acc = nvi_en_acc_icm, .en_gyr = nvi_en_gyr_icm, }; static int nvi_src(struct nvi_state *st, unsigned int src) { unsigned int rate; int ret; rate = (st->src[src].period_us_req * 1000) / st->src[src].base_t; if (rate) rate--; ret = nvi_i2c_write_rc(st, &st->hal->reg->smplrt[src], rate, __func__, (u8 *)&st->rc.smplrt[src], true); if (!ret) st->src[src].period_us_src = ((rate + 1) * st->src[src].base_t) / 1000; if (st->sts & (NVS_STS_SPEW_MSG | NVI_DBG_SPEW_MSG)) dev_info(&st->i2c->dev, "%s src[%u] period_req=%u period_src=%u err=%d\n", __func__, src, st->src[src].period_us_req, st->src[src].period_us_src, ret); return ret; } static int nvi_src_gyr(struct nvi_state *st) { return nvi_src(st, SRC_GYR); } static int nvi_src_acc(struct nvi_state *st) { return nvi_src(st, SRC_ACC); } static unsigned int nvi_aux_period_us[] = { 29127111, 14563556, 7281778, 3640889, 1820444, 910222, 455111, 227556, 113778, 56889, 28444, 14222, }; static int nvi_src_aux(struct nvi_state *st) { u8 val; unsigned int i; int ret; for (i = 0; i < ARRAY_SIZE(nvi_aux_period_us); i++) { if (st->src[SRC_AUX].period_us_req >= nvi_aux_period_us[i]) break; } if (i >= ARRAY_SIZE(nvi_aux_period_us)) i = ARRAY_SIZE(nvi_aux_period_us) - 1; val = 0x0F - i; ret = nvi_i2c_wr_rc(st, &st->hal->reg->i2c_mst_odr_config, val, __func__, &st->rc.i2c_mst_odr_config); if (!ret) { st->src[SRC_AUX].period_us_src = nvi_aux_period_us[i]; ret = nvi_aux_delay(st, __func__); } if (st->sts & (NVS_STS_SPEW_MSG | NVI_DBG_SPEW_MSG)) dev_info(&st->i2c->dev, "%s src[SRC_AUX] period_req=%u period_src=%u err=%d\n", __func__, st->src[SRC_AUX].period_us_req, st->src[SRC_AUX].period_us_src, ret); return ret; } static const struct nvi_hal_src src[] = { [SRC_GYR] { .dev_msk = (1 << DEV_GYR) | (1 << DEV_GYU), .period_us_min = 10000, .period_us_max = 200000, .fn_period = nvi_src_gyr, }, [SRC_ACC] { .dev_msk = (1 << DEV_ACC), .period_us_min = 10000, .period_us_max = 200000, .fn_period = nvi_src_acc, }, [SRC_AUX] { .dev_msk = (1 << DEV_AUX), .period_us_min = 14222, .period_us_max = 29127111, .fn_period = nvi_src_aux, }, }; static int nvi_fifo_devs[] = { DEV_GYR, DEV_ACC, -1, DEV_AUX, }; static const unsigned long nvi_lp_dly_us_tbl[] = { 4096000,/* 4096ms */ 2048000,/* 2048ms */ 1024000,/* 1024ms */ 512000, /* 512ms */ 256000, /* 256ms */ 128000, /* 128ms */ 64000, /* 64ms */ 32000, /* 32ms */ 16000, /* 16ms */ 8000, /* 8ms */ 4000, /* 4ms */ /* 2000, 2ms */ }; static struct nvi_rr nvi_rr_acc[] = { /* all accelerometer values are in g's fval = NVS_FLOAT_NANO */ { .max_range = { .ival = 19, .fval = 613300000, }, .resolution = { .ival = 0, .fval = 598550, }, }, { .max_range = { .ival = 39, .fval = 226600000, }, .resolution = { .ival = 0, .fval = 1197101, }, }, { .max_range = { .ival = 78, .fval = 453200000, }, .resolution = { .ival = 0, .fval = 2394202, }, }, { .max_range = { .ival = 156, .fval = 906400000, }, .resolution = { .ival = 0, .fval = 4788403, }, }, }; static struct nvi_rr nvi_rr_gyr[] = { /* rad / sec fval = NVS_FLOAT_NANO */ { .max_range = { .ival = 4, .fval = 363323130, }, .resolution = { .ival = 0, .fval = 133231, }, }, { .max_range = { .ival = 8, .fval = 726646260, }, .resolution = { .ival = 0, .fval = 266462, }, }, { .max_range = { .ival = 17, .fval = 453292520, }, .resolution = { .ival = 0, .fval = 532113, }, }, { .max_range = { .ival = 34, .fval = 906585040, }, .resolution = { .ival = 0, .fval = 1064225, }, }, }; static struct nvi_rr nvi_rr_tmp[] = { { .max_range = { .ival = 125, .fval = 0, }, .resolution = { .ival = 1, .fval = 0, }, }, }; static struct nvi_rr nvi_rr_dmp[] = { { .max_range = { .ival = 1, .fval = 0, }, .resolution = { .ival = 1, .fval = 0, }, }, }; static const struct nvi_hal_dev nvi_hal_acc = { .version = 3, .src = SRC_ACC, .rr_0n = ARRAY_SIZE(nvi_rr_acc) - 1, .rr = nvi_rr_acc, .milliamp = { .ival = 0, .fval = 500000000, /* NVS_FLOAT_NANO */ }, .fifo_en_msk = 0x1000, .fifo = 1, .fifo_data_n = 6, }; static const struct nvi_hal_dev nvi_hal_gyr = { .version = 3, .src = SRC_GYR, .rr_0n = ARRAY_SIZE(nvi_rr_gyr) - 1, .rr = nvi_rr_gyr, .milliamp = { .ival = 3, .fval = 700000000, /* NVS_FLOAT_NANO */ }, .fifo_en_msk = 0x0E00, .fifo = 0, .fifo_data_n = 6, }; static const struct nvi_hal_dev nvi_hal_tmp = { .version = 2, .src = -1, .rr_0n = ARRAY_SIZE(nvi_rr_tmp) - 1, .rr = nvi_rr_tmp, .scale = { .ival = 0, .fval = 334082700, /* NVS_FLOAT_NANO */ }, .offset = { .ival = 0, .fval = 137625600, /* NVS_FLOAT_NANO */ }, .milliamp = { .ival = 3, .fval = 700000000, /* NVS_FLOAT_NANO */ }, }; static const struct nvi_hal_dev nvi_hal_aux = { .src = SRC_AUX, .fifo_en_msk = 0x000F, }; static const struct nvi_hal_dev nvi_hal_dmp = { .version = 1, .src = SRC_GYR, .rr_0n = ARRAY_SIZE(nvi_rr_dmp) - 1, .rr = nvi_rr_dmp, .milliamp = { .ival = 0, .fval = 500000, /* NVS_FLOAT_MICRO */ }, }; static const struct nvi_hal_reg nvi_hal_reg_icm = { /* register bank 0 */ .lp_config = { .bank = 0, .reg = 0x05, .dflt = 0x70, }, .i2c_mst_status = { .bank = 0, .reg = 0x17, }, .int_pin_cfg = { .bank = 0, .reg = 0x0F, }, .int_enable = { .bank = 0, .reg = 0x10, .len = 4, }, .int_dmp = { .bank = 0, .reg = 0x18, }, .int_status = { .bank = 0, .reg = 0x19, .len = 4, }, .out_h[DEV_ACC] = { .bank = 0, .reg = 0x2D, }, .out_h[DEV_GYR] = { .bank = 0, .reg = 0x33, }, .out_h[DEV_TMP] = { .bank = 0, .reg = 0x39, }, .ext_sens_data_00 = { .bank = 0, .reg = 0x3B, }, .signal_path_reset = { .bank = 0, .reg = 0x04, }, .user_ctrl = { .bank = 0, .reg = 0x03, }, .pm1 = { .bank = 0, .reg = 0x06, .dflt = 0x01, }, .pm2 = { .bank = 0, .reg = 0x07, .dflt = 0x40, }, .fifo_en = { .bank = 0, .reg = 0x66, .len = 2, }, .fifo_rst = { .bank = 0, .reg = 0x68, }, .fifo_sz = { .bank = 0, .reg = 0x6E, }, .fifo_count_h = { .bank = 0, .reg = 0x70, .len = 2, }, .fifo_rw = { .bank = 0, .reg = 0x72, }, .fifo_cfg = { .bank = 0, .reg = 0x76, }, .who_am_i = { .bank = 0, .reg = 0x00, }, .mem_addr = { .bank = 0, .reg = 0x7C, }, .mem_rw = { .bank = 0, .reg = 0x7D, }, .mem_bank = { .bank = 0, .reg = 0x7E, }, .reg_bank = { .bank = 0, .reg = 0x7F, }, /* register bank 1 */ .self_test_g[AXIS_X] = { .bank = 1, .reg = 0x02, }, .self_test_g[AXIS_Y] = { .bank = 1, .reg = 0x03, }, .self_test_g[AXIS_Z] = { .bank = 1, .reg = 0x04, }, .self_test_a[AXIS_X] = { .bank = 1, .reg = 0x0E, }, .self_test_a[AXIS_Y] = { .bank = 1, .reg = 0x0F, }, .self_test_a[AXIS_Z] = { .bank = 1, .reg = 0x10, }, .a_offset_h[AXIS_X] = { .bank = 1, .reg = 0x14, .len = 2, }, .a_offset_h[AXIS_Y] = { .bank = 1, .reg = 0x17, .len = 2, }, .a_offset_h[AXIS_Z] = { .bank = 1, .reg = 0x1A, .len = 2, }, .tbc_pll = { .bank = 1, .reg = 0x28, }, .tbc_rcosc = { .bank = 1, .reg = 0x29, }, /* register bank 2 */ .smplrt[SRC_GYR] = { .bank = 2, .reg = 0x00, }, .gyro_config1 = { .bank = 2, .reg = 0x01, .dflt = 0x01, }, .gyro_config2 = { .bank = 2, .reg = 0x02, }, .g_offset_h[AXIS_X] = { .bank = 2, .reg = 0x03, .len = 2, }, .g_offset_h[AXIS_Y] = { .bank = 2, .reg = 0x05, .len = 2, }, .g_offset_h[AXIS_Z] = { .bank = 2, .reg = 0x07, .len = 2, }, .smplrt[SRC_ACC] = { .bank = 2, .reg = 0x10, .len = 2, }, .accel_config = { .bank = 2, .reg = 0x14, }, .accel_config2 = { .bank = 2, .reg = 0x15, }, .fw_start = { .bank = 2, .reg = 0x50, .len = 2, }, /* register bank 3 */ .i2c_mst_odr_config = { .bank = 3, .reg = 0x00, }, .i2c_mst_ctrl = { .bank = 3, .reg = 0x01, }, .i2c_mst_delay_ctrl = { .bank = 3, .reg = 0x02, }, .i2c_slv_addr[0] = { .bank = 3, .reg = 0x03, }, .i2c_slv_addr[1] = { .bank = 3, .reg = 0x07, }, .i2c_slv_addr[2] = { .bank = 3, .reg = 0x0B, }, .i2c_slv_addr[3] = { .bank = 3, .reg = 0x0F, }, .i2c_slv_addr[4] = { .bank = 3, .reg = 0x13, }, .i2c_slv_reg[0] = { .bank = 3, .reg = 0x04, }, .i2c_slv_reg[1] = { .bank = 3, .reg = 0x08, }, .i2c_slv_reg[2] = { .bank = 3, .reg = 0x0C, }, .i2c_slv_reg[3] = { .bank = 3, .reg = 0x10, }, .i2c_slv_reg[4] = { .bank = 3, .reg = 0x14, }, .i2c_slv_ctrl[0] = { .bank = 3, .reg = 0x05, }, .i2c_slv_ctrl[1] = { .bank = 3, .reg = 0x09, }, .i2c_slv_ctrl[2] = { .bank = 3, .reg = 0x0D, }, .i2c_slv_ctrl[3] = { .bank = 3, .reg = 0x11, }, .i2c_slv4_ctrl = { .bank = 3, .reg = 0x15, }, .i2c_slv_do[0] = { .bank = 3, .reg = 0x06, }, .i2c_slv_do[1] = { .bank = 3, .reg = 0x0A, }, .i2c_slv_do[2] = { .bank = 3, .reg = 0x0E, }, .i2c_slv_do[3] = { .bank = 3, .reg = 0x12, }, .i2c_slv_do[4] = { .bank = 3, .reg = 0x16, }, .i2c_slv4_di = { .bank = 3, .reg = 0x17, }, }; static const struct nvi_hal_bit nvi_hal_bit_icm = { .dmp_int_sm = 2, .dmp_int_stp = 3, .int_i2c_mst = 0, .int_dmp = 1, .int_pll_rdy = 2, .int_wom = 3, .int_wof = 7, .int_data_rdy_0 = 8, .int_data_rdy_1 = 9, .int_data_rdy_2 = 10, .int_data_rdy_3 = 11, .int_fifo_ovrflw_0 = 16, .int_fifo_ovrflw_1 = 17, .int_fifo_ovrflw_2 = 18, .int_fifo_ovrflw_3 = 19, .int_fifo_wm_0 = 24, .int_fifo_wm_1 = 25, .int_fifo_wm_2 = 26, .int_fifo_wm_3 = 27, .slv_fifo_en[0] = 0, .slv_fifo_en[1] = 1, .slv_fifo_en[2] = 2, .slv_fifo_en[3] = 3, }; const struct nvi_hal nvi_hal_20628 = { .regs_n = 128, .reg_bank_n = 4, .src = src, .src_n = ARRAY_SIZE(src), .fifo_dev = nvi_fifo_devs, .fifo_n = ARRAY_SIZE(nvi_fifo_devs), .lp_tbl = nvi_lp_dly_us_tbl, .lp_tbl_n = ARRAY_SIZE(nvi_lp_dly_us_tbl), .dev[DEV_ACC] = &nvi_hal_acc, .dev[DEV_GYR] = &nvi_hal_gyr, .dev[DEV_TMP] = &nvi_hal_tmp, .dev[DEV_SM] = &nvi_hal_dmp, .dev[DEV_STP] = &nvi_hal_dmp, .dev[DEV_QTN] = &nvi_hal_dmp, .dev[DEV_GMR] = &nvi_hal_dmp, .dev[DEV_GYU] = &nvi_hal_gyr, .dev[DEV_AUX] = &nvi_hal_aux, .reg = &nvi_hal_reg_icm, .bit = &nvi_hal_bit_icm, .fn = &nvi_fn_icm, .dmp = &nvi_dmp_icm, }; EXPORT_SYMBOL(nvi_hal_20628);