示例#1
0
int mpu6050_gyro_hw_self_check(struct i2c_client *client,
			 int ratio[3])
{
	int result;
	int gyro_bias_st[THREE_AXIS], gyro_bias_regular[THREE_AXIS];
	int test_times;
	int gyro_result;

	/*backup registers */
	result = mpu6050_backup_register(client);
	if (result) {
		pr_err("register backup error=%d", result);
		goto err_state;
	}

	/*power-up*/
	mpu6050_do_powerup(client);

	/*get regular bias*/
	test_times = DEF_ST_TRY_TIMES;
	while (test_times > 0) {
		result = mpu6050_do_test(client, 0, gyro_bias_regular);
		if (result == -EAGAIN)
			test_times--;
		else
			test_times = 0;
	}
	if (result)
		goto test_fail;

	/*get st bias*/
	test_times = DEF_ST_TRY_TIMES;
	while (test_times > 0) {
		result = mpu6050_do_test(client,
				BITS_SELF_TEST_EN, gyro_bias_st);
		if (result == -EAGAIN)
			test_times--;
		else
			test_times = 0;
	}
	if (result)
		goto test_fail;

	gyro_result = mpu6050_gyro_self_test(client,
		gyro_bias_regular, gyro_bias_st, ratio);

    	pr_info("mpu6050_gyro_self_test : gyro_result=%d\n", gyro_result);        
	result = gyro_result;

err_state:
test_fail:
	/*recover registers */
	if (mpu6050_recover_register(client)) {
		pr_err("register recovering error\n");
		goto err_state;
	}


	return result;
}
int mpu6050_selftest_run(struct i2c_client *client,
			 int packet_cnt[3],
			 int gyro_bias[3],
			 int gyro_rms[3], int gyro_lsb_bias[3])
{
	int ret_val = 0;
	int result;
	int total_count = 0;
	int total_count_axis[3] = { 0, 0, 0 };
	int packet_count;
	long avg[3];
	long rms[3];
	short *x;
	short *y;
	short *z;
	int buf_size = sizeof(short) * DEF_PERIOD_CAL
			* DEF_TESTS_PER_AXIS / 8 * 4;

	int i, j, tmp;
	char tmpStr[200];
	unsigned char regs[7] = { 0, };
	unsigned char dataout[20];
	int perform_full_test = 0;
	int dps_rms[3] = { 0, };
	u32 temp;
	struct mpu6050_selftest_info test_setup = {
		DEF_GYRO_SENS, DEF_GYRO_FULLSCALE, DEF_PACKET_THRESH,
		DEF_TOTAL_TIMING_TOL, (int)DEF_BIAS_THRESH_SELF,
		DEF_RMS_LSB_THRESH_SELF * DEF_RMS_LSB_THRESH_SELF,
		/* now obsolete - has no effect */
		DEF_TESTS_PER_AXIS, DEF_N_ACCEL_SAMPLES
	};

	char a_name[3][2] = { "X", "Y", "Z" };
	x = kzalloc(buf_size, GFP_KERNEL);
	y = kzalloc(buf_size, GFP_KERNEL);
	z = kzalloc(buf_size, GFP_KERNEL);

	/*backup registers */
	result = mpu6050_backup_register(client);
	if (result) {
		pr_err("register backup error=%d", result);
		goto err_state;
	}

	if (mpu6050_selftest.pwm_mgmt[0] & 0x40) {
		result =
		    mpu6050_i2c_write_single_reg(client, MPUREG_PWR_MGMT_1,
						 0x00);
		if (result) {
			pr_err("init PWR_MGMT error=%d", result);
			goto err_state;
		}
	}

	regs[0] =
		mpu6050_selftest.pwm_mgmt[1] &
			~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
	result =
		mpu6050_i2c_write_single_reg(client,
			MPUREG_PWR_MGMT_2, regs[0]);

	/* make sure the DMP is disabled first */
	result = mpu6050_i2c_write_single_reg(client, MPUREG_USER_CTRL, 0x00);
	if (result) {
		pr_info("DMP disable error=%d", result);
		goto err_state;
	}

	/* reset the gyro offset values */
	regs[0] = MPUREG_XG_OFFS_USRH;
	result = mpu6050_i2c_write(client, 6, regs);
	if (result)
		goto err_state;

	/* sample rate */
	if (perform_full_test) {

		/* = 8ms */
		result =
		    mpu6050_i2c_write_single_reg(client, MPUREG_SMPLRT_DIV,
						 0x07);
		test_setup.bias_thresh = DEF_BIAS_LSB_THRESH_CAL;
	} else {

		/* = 1ms */
		result =
		    mpu6050_i2c_write_single_reg(client, MPUREG_SMPLRT_DIV,
						 0x00);
		test_setup.bias_thresh = DEF_BIAS_LSB_THRESH_SELF;
	}
	if (result)
		goto err_state;

	regs[0] = 0x03;		/* filter = 42Hz, analog_sample rate = 1 KHz */
	switch (test_setup.gyro_fs) {
	case 2000:
		regs[0] |= 0x18;
		break;
	case 1000:
		regs[0] |= 0x10;
		break;
	case 500:
		regs[0] |= 0x08;
		break;
	case 250:
	default:
		regs[0] |= 0x00;
		break;
	}
	result = mpu6050_i2c_write_single_reg(client, MPUREG_CONFIG, regs[0]);
	if (result)
		goto err_state;

	switch (test_setup.gyro_fs) {
	case 2000:
		regs[0] = 0x03;
		break;
	case 1000:
		regs[0] = 0x02;
		break;
	case 500:
		regs[0] = 0x01;
		break;
	case 250:
	default:
		regs[0] = 0x00;
		break;
	}
	result =
	    mpu6050_i2c_write_single_reg(client, MPUREG_GYRO_CONFIG,
					 regs[0] << 3);
	if (result)
		goto err_state;
	result = mpu6050_i2c_write_single_reg(client, MPUREG_INT_ENABLE, 0x00);
	if (result)
		goto err_state;

	/* 1st, timing test */
	for (j = 0; j < 3; j++) {
		pr_info("Collecting gyro data from %s gyro PLL\n", a_name[j]);

		/* turn on all gyros, use gyro X for clocking
		   Set to Y and Z for 2nd and 3rd iteration */
		result =
		    mpu6050_i2c_write_single_reg(client, MPUREG_PWR_MGMT_1,
						 j + 1);
		if (result)
			goto err_state;

		/* wait for 50 ms after switching clock source */
		msleep(50);
		/* enable & reset FIFO */
		result =
		    mpu6050_i2c_write_single_reg(client, MPUREG_USER_CTRL,
						 BIT_FIFO_EN | BIT_FIFO_RST);
		if (result)
			goto err_state;

		tmp = test_setup.tests_per_axis;
		while (tmp-- > 0) {
			const unsigned char fifo_en_reg = MPUREG_FIFO_EN;

			/* enable XYZ gyro in FIFO and nothing else */
			result =
			    mpu6050_i2c_write_single_reg(client, fifo_en_reg,
							 BIT_GYRO_XOUT |
							 BIT_GYRO_YOUT |
							 BIT_GYRO_ZOUT);
			if (result)
				goto err_state;

			pr_info("%s : before sampling ...\n", __func__);
			/* wait one period for data */
			if (perform_full_test)
				msleep(DEF_PERIOD_CAL);

			else
				msleep(DEF_PERIOD_SELF);
			pr_info("%s : after sampling ...\n", __func__);

			/* stop storing gyro in the FIFO */
			result =
			    mpu6050_i2c_write_single_reg(client,
							 fifo_en_reg, 0x00);
			if (result)
				goto err_state;

			/* Getting number of bytes in FIFO */
			result =
			    mpu6050_i2c_read_reg(client, MPUREG_FIFO_COUNTH,
						 2, dataout);
			if (result)
				goto err_state;

			/* number of 6 B packets in the FIFO */
			packet_count = mpu6050_big8_to_int16(dataout) / 6;
			pr_info("%s : sampling result packet_count =%d\n",
				__func__, packet_count);
			sprintf(tmpStr, "Packet Count: %d -", packet_count);
			if (packet_count - (test_setup.packet_thresh - 3)
			    > 0) {
				for (i = 0; i < packet_count; i++) {

					/* getting FIFO data */
					result =
					    mpu6050_i2c_read_fifo(client, 6,
								  dataout);
					if (result)
						goto err_state;

					x[total_count + i] =
					    mpu6050_big8_to_int16(&dataout[0]);
					y[total_count + i] =
					    mpu6050_big8_to_int16(&dataout[2]);
					z[total_count + i] =
					    mpu6050_big8_to_int16(&dataout[4]);
				}
				total_count += packet_count;
				total_count_axis[j] += packet_count;
				packet_cnt[j] = packet_count;
				sprintf(tmpStr, "%sOK success", tmpStr);
			} else {
				ret_val |= 1 << j;
				sprintf(tmpStr, "%sNOK - samples ignored ...",
					tmpStr);
			}
			pr_info("%s\n", tmpStr);
		}

		/* remove gyros from FIFO */
		result =
		    mpu6050_i2c_write_single_reg(client, MPUREG_FIFO_EN, 0x00);
		if (result)
			goto err_state;
	}
	pr_info("\nTotal %d samples\n", total_count);

	/* 2nd, check bias from X, Y, and Z PLL clock source */
	tmp = total_count != 0 ? total_count : 1;
	for (i = 0, avg[0] = 0, avg[1] = 0, avg[2] = 0; i < total_count; i++) {
		avg[0] += x[i];
		avg[1] += y[i];
		avg[2] += z[i];
	}
	avg[0] /= tmp;
	avg[1] /= tmp;
	avg[2] /= tmp;

	pr_info("bias : %+8ld %+8ld %+8ld (LSB)\n", avg[0], avg[1], avg[2]);

	gyro_bias[0] = (avg[0] * DEF_SCALE_FOR_FLOAT) / DEF_GYRO_SENS;
	gyro_bias[1] = (avg[1] * DEF_SCALE_FOR_FLOAT) / DEF_GYRO_SENS;
	gyro_bias[2] = (avg[2] * DEF_SCALE_FOR_FLOAT) / DEF_GYRO_SENS;
	gyro_lsb_bias[0] = avg[0];
	gyro_lsb_bias[1] = avg[1];
	gyro_lsb_bias[2] = avg[2];

	if (VERBOSE_OUT) {
		pr_info("abs bias : %+8d.%03d   %+8d.%03d  %+8d.%03d (dps)\n",
			(int)abs(gyro_bias[0]) / DEF_SCALE_FOR_FLOAT,
			(int)abs(gyro_bias[0]) % DEF_SCALE_FOR_FLOAT,
			(int)abs(gyro_bias[1]) / DEF_SCALE_FOR_FLOAT,
			(int)abs(gyro_bias[1]) % DEF_SCALE_FOR_FLOAT,
			(int)abs(gyro_bias[2]) / DEF_SCALE_FOR_FLOAT,
			(int)abs(gyro_bias[2]) % DEF_SCALE_FOR_FLOAT);
	}

	for (j = 0; j < 3; j++) {
		if (abs(avg[j]) > test_setup.bias_thresh) {
			pr_info("%s-Gyro bias (%ld) exceeded threshold "
				"(threshold = %d LSB)\n", a_name[j],
				avg[j], test_setup.bias_thresh);
			ret_val |= 1 << (3 + j);
		}
	}

	/* 3rd, check RMS for dead gyros
	   If any of the RMS noise value returns zero,
	   then we might have dead gyro or FIFO/register failure,
	   the part is sleeping, or the part is not responsive */
	for (i = 0, rms[0] = 0, rms[1] = 0, rms[2] = 0; i < total_count; i++) {
		rms[0] += (long)(x[i] - avg[0]) * (x[i] - avg[0]);
		rms[1] += (long)(y[i] - avg[1]) * (y[i] - avg[1]);
		rms[2] += (long)(z[i] - avg[2]) * (z[i] - avg[2]);
	}

	if (rms[0] == 0 || rms[1] == 0 || rms[2] == 0)
		ret_val |= 1 << 6;

	if (VERBOSE_OUT) {
		pr_info("RMS ^ 2 : %+8ld %+8ld %+8ld\n",
			(long)rms[0] / total_count,
			(long)rms[1] / total_count, (long)rms[2] / total_count);
	}

	for (j = 0; j < 3; j++) {
		if (rms[j] / total_count > test_setup.rms_thresh) {
			pr_info("%s-Gyro rms (%ld) exceeded threshold "
				"(threshold = %d LSB)\n", a_name[j],
				rms[j] / total_count, test_setup.rms_thresh);
			ret_val |= 1 << (7 + j);
		}
	}

	for (i = 0; i < 3; i++) {
		if (rms[i] > 10000) {
			temp =
			    ((u32) (rms[i] / total_count)) *
			    DEF_RMS_SCALE_FOR_RMS;
		} else {
			temp =
			    ((u32) (rms[i] * DEF_RMS_SCALE_FOR_RMS)) /
			    total_count;
		}
		if (rms[i] < 0)
			temp = 1 << 31;

		dps_rms[i] = mpu6050_selftest_sqrt(temp) / DEF_GYRO_SENS;

		gyro_rms[i] =
		    dps_rms[i] * DEF_SCALE_FOR_FLOAT / DEF_SQRT_SCALE_FOR_RMS;
	}

	pr_info("RMS : %+8d.%03d	 %+8d.%03d  %+8d.%03d (dps)\n",
		(int)abs(gyro_rms[0]) / DEF_SCALE_FOR_FLOAT,
		(int)abs(gyro_rms[0]) % DEF_SCALE_FOR_FLOAT,
		(int)abs(gyro_rms[1]) / DEF_SCALE_FOR_FLOAT,
		(int)abs(gyro_rms[1]) % DEF_SCALE_FOR_FLOAT,
		(int)abs(gyro_rms[2]) / DEF_SCALE_FOR_FLOAT,
		(int)abs(gyro_rms[2]) % DEF_SCALE_FOR_FLOAT);

	/*recover registers */
	result = mpu6050_recover_register(client);
	if (result) {
		pr_err("register recovering error=%d", result);
		goto err_state;
	}
	result = ret_val;
err_state:
	kfree(x);
	kfree(y);
	kfree(z);
	return result;
}