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;
}
static ssize_t mpu6500_gyro_selftest(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	char chTempBuf[36] = { 0,};
	u8 initialized = 0;
	s8 hw_result = 0;
	int i = 0, j = 0, total_count = 0, ret_val = 0;
	long avg[3] = {0,}, rms[3] = {0,};
	int gyro_bias[3] = {0,}, gyro_rms[3] = {0,};
	s16 shift_ratio[3] = {0,};
	s16 iCalData[3] = {0,};
	char a_name[3][2] = { "X", "Y", "Z" };
	int iRet = 0;
	int dps_rms[3] = { 0, };
	u32 temp = 0;
	int bias_thresh = DEF_BIAS_LSB_THRESH_SELF_6500;
	struct ssp_data *data = dev_get_drvdata(dev);

	struct ssp_msg *msg = kzalloc(sizeof(*msg), GFP_KERNEL);
	if (msg == NULL) {
		pr_err("[SSP] %s, failed to alloc memory for ssp_msg\n", __func__);
		goto exit;
	}
	msg->cmd = GYROSCOPE_FACTORY;
	msg->length = 36;
	msg->options = AP2HUB_READ;
	msg->buffer = chTempBuf;
	msg->free_buffer = 0;

	iRet = ssp_spi_sync(data, msg, 7000);

	if (iRet != SUCCESS) {
		pr_err("[SSP]: %s - Gyro Selftest Timeout!!\n", __func__);
		ret_val = 1;
		goto exit;
	}

	data->uTimeOutCnt = 0;

	pr_err("[SSP]%d %d %d %d %d %d %d %d %d %d %d %d", chTempBuf[0],
		chTempBuf[1], chTempBuf[2], chTempBuf[3], chTempBuf[4],
		chTempBuf[5], chTempBuf[6], chTempBuf[7], chTempBuf[8],
		chTempBuf[9], chTempBuf[10], chTempBuf[11]);

	initialized = chTempBuf[0];
	shift_ratio[0] = (s16)((chTempBuf[2] << 8) +
				chTempBuf[1]);
	shift_ratio[1] = (s16)((chTempBuf[4] << 8) +
				chTempBuf[3]);
	shift_ratio[2] = (s16)((chTempBuf[6] << 8) +
				chTempBuf[5]);
	hw_result = (s8)chTempBuf[7];
	total_count = (int)((chTempBuf[11] << 24) +
				(chTempBuf[10] << 16) +
				(chTempBuf[9] << 8) +
				chTempBuf[8]);
	avg[0] = (long)((chTempBuf[15] << 24) +
				(chTempBuf[14] << 16) +
				(chTempBuf[13] << 8) +
				chTempBuf[12]);
	avg[1] = (long)((chTempBuf[19] << 24) +
				(chTempBuf[18] << 16) +
				(chTempBuf[17] << 8) +
				chTempBuf[16]);
	avg[2] = (long)((chTempBuf[23] << 24) +
				(chTempBuf[22] << 16) +
				(chTempBuf[21] << 8) +
				chTempBuf[20]);
	rms[0] = (long)((chTempBuf[27] << 24) +
				(chTempBuf[26] << 16) +
				(chTempBuf[25] << 8) +
				chTempBuf[24]);
	rms[1] = (long)((chTempBuf[31] << 24) +
				(chTempBuf[30] << 16) +
				(chTempBuf[29] << 8) +
				chTempBuf[28]);
	rms[2] = (long)((chTempBuf[35] << 24) +
				(chTempBuf[34] << 16) +
				(chTempBuf[33] << 8) +
				chTempBuf[32]);
	pr_info("[SSP] init: %d, total cnt: %d\n", initialized, total_count);
	pr_info("[SSP] hw_result: %d, %d, %d, %d\n", hw_result,
		shift_ratio[0], shift_ratio[1],	shift_ratio[2]);
	pr_info("[SSP] avg %+8ld %+8ld %+8ld (LSB)\n", avg[0], avg[1], avg[2]);
	pr_info("[SSP] rms %+8ld %+8ld %+8ld (LSB)\n", rms[0], rms[1], rms[2]);

	if (total_count == 0) {
		pr_err("[SSP] %s, total_count is 0. goto exit\n", __func__);
		ret_val = 2;
		goto exit;
	}

	if (hw_result < 0) {
		pr_err("[SSP] %s - hw selftest fail(%d), sw selftest skip\n",
			__func__, hw_result);
		return sprintf(buf, "-1,0,0,0,0,0,0,%d.%d,%d.%d,%d.%d,0,0,0\n",
			shift_ratio[0] / 10, shift_ratio[0] % 10,
			shift_ratio[1] / 10, shift_ratio[1] % 10,
			shift_ratio[2] / 10, shift_ratio[2] % 10);
	}
	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;
	iCalData[0] = (s16)avg[0];
	iCalData[1] = (s16)avg[1];
	iCalData[2] = (s16)avg[2];

	if (VERBOSE_OUT) {
		pr_info("[SSP] 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 (unlikely(abs(avg[j]) > bias_thresh)) {
			pr_err("[SSP] %s-Gyro bias (%ld) exceeded threshold "
				"(threshold = %d LSB)\n", a_name[j],
				avg[j], 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 */
	if (rms[0] == 0 || rms[1] == 0 || rms[2] == 0)
		ret_val |= 1 << 6;

	if (VERBOSE_OUT) {
		pr_info("[SSP] 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 (unlikely(rms[j] / total_count > DEF_RMS_THRESH)) {
			pr_err("[SSP] %s-Gyro rms (%ld) exceeded threshold "
				"(threshold = %d LSB)\n", a_name[j],
				rms[j] / total_count, DEF_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("[SSP] 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);

	if (likely(!ret_val)) {
		save_gyro_caldata(data, iCalData);
	} else {
		pr_err("[SSP] ret_val != 0, gyrocal is 0 at all axis\n");
		data->gyrocal.x = 0;
		data->gyrocal.y = 0;
		data->gyrocal.z = 0;
	}

exit:
	ssp_dbg("[SSP]: %s - %d,"
		"%d.%03d,%d.%03d,%d.%03d,"
		"%d.%03d,%d.%03d,%d.%03d,"
		"%d.%d,%d.%d,%d.%d,"
		"%d,%d,%d\n",
		__func__, ret_val,
		(int)abs(gyro_bias[0]/1000),
		(int)abs(gyro_bias[0])%1000,
		(int)abs(gyro_bias[1]/1000),
		(int)abs(gyro_bias[1])%1000,
		(int)abs(gyro_bias[2]/1000),
		(int)abs(gyro_bias[2])%1000,
		gyro_rms[0]/1000,
		(int)abs(gyro_rms[0])%1000,
		gyro_rms[1]/1000,
		(int)abs(gyro_rms[1])%1000,
		gyro_rms[2]/1000,
		(int)abs(gyro_rms[2])%1000,
		shift_ratio[0] / 10, shift_ratio[0] % 10,
		shift_ratio[1] / 10, shift_ratio[1] % 10,
		shift_ratio[2] / 10, shift_ratio[2] % 10,
		(int)(total_count/3),
		(int)(total_count/3),
		(int)(total_count/3));

	return sprintf(buf, "%d,"
		"%d.%03d,%d.%03d,%d.%03d,"
		"%d.%03d,%d.%03d,%d.%03d,"
		"%d.%d,%d.%d,%d.%d,"
		"%d,%d,%d\n",
		ret_val,
		(int)abs(gyro_bias[0]/1000),
		(int)abs(gyro_bias[0])%1000,
		(int)abs(gyro_bias[1]/1000),
		(int)abs(gyro_bias[1])%1000,
		(int)abs(gyro_bias[2]/1000),
		(int)abs(gyro_bias[2])%1000,
		gyro_rms[0]/1000,
		(int)abs(gyro_rms[0])%1000,
		gyro_rms[1]/1000,
		(int)abs(gyro_rms[1])%1000,
		gyro_rms[2]/1000,
		(int)abs(gyro_rms[2])%1000,
		shift_ratio[0] / 10, shift_ratio[0] % 10,
		shift_ratio[1] / 10, shift_ratio[1] % 10,
		shift_ratio[2] / 10, shift_ratio[2] % 10,
		(int)(total_count/3),
		(int)(total_count/3),
		(int)(total_count/3));
}
ssize_t mpu6500_gyro_selftest(char *buf, struct ssp_data *data)
{
    char chTempBuf[2] = { 3, 200};
    u8 initialized = 0;
    s8 hw_result = 0;
    int i = 0, j = 0, total_count = 0, ret_val = 0;
    long avg[3] = {0,}, rms[3] = {0,};
    int gyro_bias[3] = {0,}, gyro_rms[3] = {0,};
    s16 shift_ratio[3] = {0,};
    s16 iCalData[3] = {0,};
    char a_name[3][2] = { "X", "Y", "Z" };
    int iDelayCnt = 0, iRet = 0;
    int dps_rms[3] = { 0, };
    u32 temp = 0;
    int bias_thresh = DEF_BIAS_LSB_THRESH_SELF_6500;

    data->uFactorydataReady = 0;
    memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX);

    iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_FACTORY,
                            chTempBuf, 2);

    while (!(data->uFactorydataReady & (1 << GYROSCOPE_FACTORY))
            && (iDelayCnt++ < 150)
            && (iRet == SUCCESS))
        msleep(20);

    if ((iDelayCnt >= 150) || (iRet != SUCCESS)) {
        pr_err("[SSP]: %s - Gyro Selftest Timeout!!\n", __func__);
        goto exit;
    }

    initialized = data->uFactorydata[0];
    shift_ratio[0] = (s16)((data->uFactorydata[2] << 8) +
                           data->uFactorydata[1]);
    shift_ratio[1] = (s16)((data->uFactorydata[4] << 8) +
                           data->uFactorydata[3]);
    shift_ratio[2] = (s16)((data->uFactorydata[6] << 8) +
                           data->uFactorydata[5]);
    hw_result = (s8)data->uFactorydata[7];
    total_count = (int)((data->uFactorydata[11] << 24) +
                        (data->uFactorydata[10] << 16) +
                        (data->uFactorydata[9] << 8) +
                        data->uFactorydata[8]);
    avg[0] = (long)((data->uFactorydata[15] << 24) +
                    (data->uFactorydata[14] << 16) +
                    (data->uFactorydata[13] << 8) +
                    data->uFactorydata[12]);
    avg[1] = (long)((data->uFactorydata[19] << 24) +
                    (data->uFactorydata[18] << 16) +
                    (data->uFactorydata[17] << 8) +
                    data->uFactorydata[16]);
    avg[2] = (long)((data->uFactorydata[23] << 24) +
                    (data->uFactorydata[22] << 16) +
                    (data->uFactorydata[21] << 8) +
                    data->uFactorydata[20]);
    rms[0] = (long)((data->uFactorydata[27] << 24) +
                    (data->uFactorydata[26] << 16) +
                    (data->uFactorydata[25] << 8) +
                    data->uFactorydata[24]);
    rms[1] = (long)((data->uFactorydata[31] << 24) +
                    (data->uFactorydata[30] << 16) +
                    (data->uFactorydata[29] << 8) +
                    data->uFactorydata[28]);
    rms[2] = (long)((data->uFactorydata[35] << 24) +
                    (data->uFactorydata[34] << 16) +
                    (data->uFactorydata[33] << 8) +
                    data->uFactorydata[32]);
    pr_info("[SSP] init: %d, total cnt: %d\n", initialized, total_count);
    pr_info("[SSP] hw_result: %d, %d, %d, %d\n", hw_result,
            shift_ratio[0], shift_ratio[1],	shift_ratio[2]);
    pr_info("[SSP] avg %+8ld %+8ld %+8ld (LSB)\n", avg[0], avg[1], avg[2]);
    pr_info("[SSP] rms %+8ld %+8ld %+8ld (LSB)\n", rms[0], rms[1], rms[2]);

    if (hw_result < 0) {
        pr_err("[SSP] %s - hw selftest fail(%d), sw selftest skip\n",
               __func__, hw_result);
        return sprintf(buf, "-1,0,0,0,0,0,0,%d.%d,%d.%d,%d.%d,0,0,0\n",
                       shift_ratio[0] / 10, shift_ratio[0] % 10,
                       shift_ratio[1] / 10, shift_ratio[1] % 10,
                       shift_ratio[2] / 10, shift_ratio[2] % 10);
    }
    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;
    iCalData[0] = (s16)avg[0];
    iCalData[1] = (s16)avg[1];
    iCalData[2] = (s16)avg[2];

    if (VERBOSE_OUT) {
        pr_info("[SSP] 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);
    }
    if (data->ap_rev < 3)
        bias_thresh = DEF_BIAS_LSB_THRESH_SELF;

    for (j = 0; j < 3; j++) {
        if (unlikely(abs(avg[j]) > bias_thresh)) {
            pr_err("[SSP] %s-Gyro bias (%ld) exceeded threshold "
                   "(threshold = %d LSB)\n", a_name[j],
                   avg[j], 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 */
    if (rms[0] == 0 || rms[1] == 0 || rms[2] == 0)
        ret_val |= 1 << 6;

    if (VERBOSE_OUT) {
        pr_info("[SSP] 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 (unlikely(rms[j] / total_count > DEF_RMS_THRESH)) {
            pr_err("[SSP] %s-Gyro rms (%ld) exceeded threshold "
                   "(threshold = %d LSB)\n", a_name[j],
                   rms[j] / total_count, DEF_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("[SSP] 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);

    if (likely(!ret_val)) {
        save_gyro_caldata(data, iCalData);
    } else {
        pr_err("[SSP] ret_val != 0, gyrocal is 0 at all axis\n");
        data->gyrocal.x = 0;
        data->gyrocal.y = 0;
        data->gyrocal.z = 0;
    }

exit:
    ssp_dbg("[SSP]: %s - %d,"
            "%d.%03d,%d.%03d,%d.%03d,"
            "%d.%03d,%d.%03d,%d.%03d,"
            "%d.%d,%d.%d,%d.%d,"
            "%d,%d,%d\n",
            __func__, ret_val,
            (int)abs(gyro_bias[0]/1000),
            (int)abs(gyro_bias[0])%1000,
            (int)abs(gyro_bias[1]/1000),
            (int)abs(gyro_bias[1])%1000,
            (int)abs(gyro_bias[2]/1000),
            (int)abs(gyro_bias[2])%1000,
            gyro_rms[0]/1000,
            (int)abs(gyro_rms[0])%1000,
            gyro_rms[1]/1000,
            (int)abs(gyro_rms[1])%1000,
            gyro_rms[2]/1000,
            (int)abs(gyro_rms[2])%1000,
            shift_ratio[0] / 10, shift_ratio[0] % 10,
            shift_ratio[1] / 10, shift_ratio[1] % 10,
            shift_ratio[2] / 10, shift_ratio[2] % 10,
            (int)(total_count/3),
            (int)(total_count/3),
            (int)(total_count/3));

    return sprintf(buf, "%d,"
                   "%d.%03d,%d.%03d,%d.%03d,"
                   "%d.%03d,%d.%03d,%d.%03d,"
                   "%d.%d,%d.%d,%d.%d,"
                   "%d,%d,%d\n",
                   ret_val,
                   (int)abs(gyro_bias[0]/1000),
                   (int)abs(gyro_bias[0])%1000,
                   (int)abs(gyro_bias[1]/1000),
                   (int)abs(gyro_bias[1])%1000,
                   (int)abs(gyro_bias[2]/1000),
                   (int)abs(gyro_bias[2])%1000,
                   gyro_rms[0]/1000,
                   (int)abs(gyro_rms[0])%1000,
                   gyro_rms[1]/1000,
                   (int)abs(gyro_rms[1])%1000,
                   gyro_rms[2]/1000,
                   (int)abs(gyro_rms[2])%1000,
                   shift_ratio[0] / 10, shift_ratio[0] % 10,
                   shift_ratio[1] / 10, shift_ratio[1] % 10,
                   shift_ratio[2] / 10, shift_ratio[2] % 10,
                   (int)(total_count/3),
                   (int)(total_count/3),
                   (int)(total_count/3));
}
static ssize_t gyro_selftest_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	char chTempBuf[2] = { 3, 200};
	u8 initialized = 0;
	int i = 0, j = 0, total_count = 0, ret_val = 0;
	long avg[3] = {0,}, rms[3] = {0,};
	int gyro_bias[3] = {0,}, gyro_rms[3] = {0,};
	s16 iCalData[3] = {0,};
	char a_name[3][2] = { "X", "Y", "Z" };
	int iDelayCnt = 0, iRet = 0;
	int dps_rms[3] = { 0, };
	u32 temp = 0;
	struct ssp_data *data = dev_get_drvdata(dev);

	data->uFactorydataReady = 0;
	memset(data->uFactorydata, 0, sizeof(char) * FACTORY_DATA_MAX);

	iRet = send_instruction(data, FACTORY_MODE, GYROSCOPE_FACTORY,
		chTempBuf, 2);

	while (!(data->uFactorydataReady & (1 << GYROSCOPE_FACTORY))
		&& (iDelayCnt++ < 150)
		&& (iRet == SUCCESS))
		msleep(20);

	if ((iDelayCnt >= 150) || (iRet != SUCCESS)) {
		pr_err("[SSP]: %s - Gyro Selftest Timeout!!\n", __func__);
		goto exit;
	}
	for (i = 0; i < 29; i++)
		pr_err("[SSP]: %s - uFactorydata[%d] = 0x%x\n", __func__, i,
				data->uFactorydata[i]);

	initialized = data->uFactorydata[0];
	total_count = (int)((data->uFactorydata[4] << 24) +
				(data->uFactorydata[3] << 16) +
				(data->uFactorydata[2] << 8) +
				data->uFactorydata[1]);
	avg[0] = (long)((data->uFactorydata[8] << 24) +
				(data->uFactorydata[7] << 16) +
				(data->uFactorydata[6] << 8) +
				data->uFactorydata[5]);
	avg[1] = (long)((data->uFactorydata[12] << 24) +
				(data->uFactorydata[11] << 16) +
				(data->uFactorydata[10] << 8) +
				data->uFactorydata[9]);
	avg[2] = (long)((data->uFactorydata[16] << 24) +
				(data->uFactorydata[15] << 16) +
				(data->uFactorydata[14] << 8) +
				data->uFactorydata[13]);
	rms[0] = (long)((data->uFactorydata[20] << 24) +
				(data->uFactorydata[19] << 16) +
				(data->uFactorydata[18] << 8) +
				data->uFactorydata[17]);
	rms[1] = (long)((data->uFactorydata[24] << 24) +
				(data->uFactorydata[23] << 16) +
				(data->uFactorydata[22] << 8) +
				data->uFactorydata[21]);
	rms[2] = (long)((data->uFactorydata[28] << 24) +
				(data->uFactorydata[27] << 16) +
				(data->uFactorydata[26] << 8) +
				data->uFactorydata[25]);
	pr_err("[SSP] init: %d, total cnt: %d", initialized, total_count);
	pr_err("[SSP] avg %+8ld %+8ld %+8ld (LSB)\n", avg[0], avg[1], avg[2]);
	pr_err("[SSP] rms %+8ld %+8ld %+8ld (LSB)\n", rms[0], rms[1], rms[2]);
/*
	avg[0] /= total_count;
	avg[1] /= total_count;
	avg[2] /= total_count;
*/
	pr_info("[SSP] 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;
	iCalData[0] = (s16)avg[0];
	iCalData[1] = (s16)avg[1];
	iCalData[2] = (s16)avg[2];

	if (VERBOSE_OUT) {
		pr_info("[SSP] 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]) > DEF_BIAS_LSB_THRESH_SELF) {
			pr_info("[SSP] %s-Gyro bias (%ld) exceeded threshold "
				"(threshold = %d LSB)\n", a_name[j],
				avg[j], DEF_BIAS_LSB_THRESH_SELF);
			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 */
	if (rms[0] == 0 || rms[1] == 0 || rms[2] == 0)
		ret_val |= 1 << 6;

	if (VERBOSE_OUT) {
		pr_info("[SSP] 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 > DEF_RMS_THRESH) {
			pr_info("[SSP] %s-Gyro rms (%ld) exceeded threshold "
				"(threshold = %d LSB)\n", a_name[j],
				rms[j] / total_count, DEF_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("[SSP] 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);

	if (!ret_val) {
		pr_err("[SSP] ret_val == 0\n");
		save_gyro_caldata(data, iCalData);
	} else {
		pr_err("[SSP] ret_val != 0\n");
		data->gyrocal.x = 0;
		data->gyrocal.y = 0;
		data->gyrocal.z = 0;
		/*initialized = -1;*/
	}

exit:
	ssp_dbg("[SSP]: Gyro Selftest - %d,"
		"%d.%03d,%d.%03d,%d.%03d,"
		"%d.%03d,%d.%03d,%d.%03d,"
		"%d,%d,%d\n",
		ret_val,
		(int)abs(gyro_bias[0]/1000),
		(int)abs(gyro_bias[0])%1000,
		(int)abs(gyro_bias[1]/1000),
		(int)abs(gyro_bias[1])%1000,
		(int)abs(gyro_bias[2]/1000),
		(int)abs(gyro_bias[2])%1000,
		gyro_rms[0]/1000,
		(int)abs(gyro_rms[0])%1000,
		gyro_rms[1]/1000,
		(int)abs(gyro_rms[1])%1000,
		gyro_rms[2]/1000,
		(int)abs(gyro_rms[2])%1000,
		(int)(total_count/3),
		(int)(total_count/3),
		(int)(total_count/3));

	return sprintf(buf, "%d,"
		"%d.%03d,%d.%03d,%d.%03d,"
		"%d.%03d,%d.%03d,%d.%03d,"
		"%d,%d,%d\n",
		ret_val,
		(int)abs(gyro_bias[0]/1000),
		(int)abs(gyro_bias[0])%1000,
		(int)abs(gyro_bias[1]/1000),
		(int)abs(gyro_bias[1])%1000,
		(int)abs(gyro_bias[2]/1000),
		(int)abs(gyro_bias[2])%1000,
		gyro_rms[0]/1000,
		(int)abs(gyro_rms[0])%1000,
		gyro_rms[1]/1000,
		(int)abs(gyro_rms[1])%1000,
		gyro_rms[2]/1000,
		(int)abs(gyro_rms[2])%1000,
		(int)(total_count/3),
		(int)(total_count/3),
		(int)(total_count/3));
}