static int pmic_fg_program_rdc_vals(struct pmic_fg_info *info)
{
	int ret;
	int rdc1, rdc0;
	u8 buf[2];

	ret = pmic_fg_reg_readmul(info, DC_FG_RDC1_REG, 2, buf);
	if (ret < 0) {
		dev_warn(&info->pdev->dev, "RDC reg read error\n");
		return ret;
	}

	if (buf[0] == info->cfg->rdc1 && buf[1] == info->cfg->rdc0) {
		dev_dbg(&info->pdev->dev, "RDC is already initialized\n");
		return 0;
	} else {
		dev_dbg(&info->pdev->dev, "RDC need to be initialized\n");
	}

	ret = pmic_fg_reg_writeb(info, DC_FG_RDC1_REG, info->cfg->rdc1);
	ret = pmic_fg_reg_writeb(info, DC_FG_RDC0_REG, info->cfg->rdc0);
	ret = pmic_fg_reg_clearb(info, DC_FG_TUNING_CNTL4, (1<<3));
	ret = pmic_fg_reg_setb(info, DC_FG_TUNING_CNTL4, (1<<4));

	return ret;
}
static int pmic_fg_program_design_cap(struct pmic_fg_info *info)
{
	int ret;
	int cap1, cap0;
	u8 buf[2];

	ret = pmic_fg_reg_readmul(info, DC_FG_DES_CAP1_REG, 2, buf);
	if (ret < 0) {
		dev_warn(&info->pdev->dev, "CAP reg read error\n");
		return ret;
	}

	if (buf[0] == info->cfg->cap1 && buf[1] == info->cfg->cap0) {
		dev_dbg(&info->pdev->dev, "design cap is already initialized\n");
		return 0;
	} else {
		dev_dbg(&info->pdev->dev, "design cap need to be initialized\n");
	}

	//Disable coulomb meter
	ret = pmic_fg_reg_clearb(info, DC_FG_CNTL_REG, FG_CNTL_CC_EN);
	ret = pmic_fg_reg_writeb(info, DC_FG_DES_CAP1_REG, info->cfg->cap1);
	ret = pmic_fg_reg_writeb(info, DC_FG_DES_CAP0_REG, info->cfg->cap0);
	ret = pmic_fg_reg_setb(info, DC_FG_CNTL_REG, FG_CNTL_CC_EN);

	return 0;
}
static int pmic_fg_program_rdc_vals(struct pmic_fg_info *info)
{
	int ret;
	int rdc1, rdc0;


       rdc1 = pmic_fg_reg_readb(info, DC_FG_RDC1_REG);
       if (rdc1 < 0) {
				dev_warn(&info->pdev->dev, "RDC1 reg read err!!\n");
				return ret;
       }
       rdc0 = pmic_fg_reg_readb(info, DC_FG_RDC1_REG);

       if (rdc1 == info->cfg->rdc1 && rdc0 == info->cfg->rdc0) {
				dev_info(&info->pdev->dev, "RDC is already initialized\n");
				return 0;
       } else {
				dev_info(&info->pdev->dev, "RDC need to be initialized\n");
       }

       ret = pmic_fg_reg_writeb(info, DC_FG_RDC1_REG, info->cfg->rdc1);

	ret = pmic_fg_reg_writeb(info, DC_FG_RDC0_REG, info->cfg->rdc0);


	ret = pmic_fg_reg_clearb(info, DC_FG_TUNING_CNTL4, (1<<3));
	ret = pmic_fg_reg_setb(info, DC_FG_TUNING_CNTL4, (1<<4));

	return ret;
}
static int pmic_fg_program_design_cap(struct pmic_fg_info *info)
{
	int ret;
	int cap1, cap0;
/*
	ret = pmic_fg_reg_writeb(info, DC_FG_DES_CAP1_REG, info->pdata->cap1);
	if (ret < 0)
		goto fg_prog_descap_fail;
*/
       cap1 = pmic_fg_reg_readb(info, DC_FG_DES_CAP1_REG);
       if (cap1 < 0) {
				dev_warn(&info->pdev->dev, "CAP1 reg read err!!\n");
				return ret;
      }
       cap0 = pmic_fg_reg_readb(info, DC_FG_DES_CAP0_REG);

       if (cap1 == info->cfg->cap1 && cap0 == info->cfg->cap0) {
				dev_info(&info->pdev->dev, "FG data is already initialized\n");
				return 0;
       } else {
				dev_info(&info->pdev->dev, "FG data need to be initialized\n");
       }

       /*Disable coulomb meter*/
       ret = pmic_fg_reg_clearb(info, DC_FG_CNTL_REG, FG_CNTL_CC_EN);

       ret = pmic_fg_reg_writeb(info, DC_FG_DES_CAP1_REG, info->cfg->cap1);


		ret = pmic_fg_reg_writeb(info, DC_FG_DES_CAP0_REG, info->cfg->cap0);

	ret = pmic_fg_reg_setb(info, DC_FG_CNTL_REG, FG_CNTL_CC_EN);

	return 0;
}
static int pmic_fg_set_lowbatt_thresholds(struct pmic_fg_info *info)
{
	int ret;
	u8 reg_val, reg_thr;

	ret = pmic_fg_reg_readb(info, DC_FG_REP_CAP_REG);
	if (ret < 0) {
		dev_err(&info->pdev->dev, "%s:read err:%d\n", __func__, ret);
		return ret;
	}
	ret = (ret & FG_REP_CAP_VAL_MASK);

	if (ret > FG_LOW_CAP_WARN1_THR)
		reg_val = FG_LOW_CAP_WARN1_THR;
	else if (ret > FG_LOW_CAP_WARN2_THR)
		reg_val = FG_LOW_CAP_WARN2_THR;
	else if (ret > FG_LOW_CAP_CRIT_THR)
		reg_val = FG_LOW_CAP_CRIT_THR;
	/*set low battery alert, which is 14% for the first level,
	 * 4% and 0% for the sencond level, the value will impact PMIC auto calibration
	 * this default value is recommended by PMIC vendor*/
	if (ret > FG_LOW_CAP_CRIT_THR) {
		ret = pmic_fg_reg_readb(info, DC_FG_TUNING_CNTL4);
		if (ret < 0) {
			dev_err(&info->pdev->dev, "%s:read err:%d\n", __func__, ret);
			return ret;
		}
		reg_thr = ret & 0xF8;
		reg_thr |= 0x04;
		ret = pmic_fg_reg_writeb(info, DC_FG_TUNING_CNTL4, reg_thr);
		if (ret < 0) {
			dev_err(&info->pdev->dev, "%s:write err:%d\n", __func__, ret);
			return ret;
		}
	} else {
		reg_val = FG_LOW_CAP_SHDN_THR;
		ret = pmic_fg_reg_readb(info, DC_FG_TUNING_CNTL4);
		if (ret < 0) {
			dev_err(&info->pdev->dev, "%s:read err:%d\n", __func__, ret);
			return ret;
		}
		reg_thr = ret & 0xF8;
		ret = pmic_fg_reg_writeb(info, DC_FG_TUNING_CNTL4, reg_thr);
		if (ret < 0) {
			dev_err(&info->pdev->dev, "%s:write err:%d\n", __func__, ret);
			return ret;
		}
	}

	reg_val |= 0x90;
	ret = pmic_fg_reg_writeb(info, DC_FG_LOW_CAP_REG, reg_val);
	if (ret < 0)
		dev_err(&info->pdev->dev, "%s:write err:%d\n", __func__, ret);

	return ret;
}
static int pmic_fg_program_vbatt_full(struct pmic_fg_info *info)
{
	int ret;
	u8 val;

	ret = pmic_fg_reg_readb(info, DC_CHRG_CCCV_REG);
	if (ret < 0)
		goto fg_prog_ocv_fail;
	else
		val = (ret & ~CHRG_CCCV_CV_MASK);

	switch (info->pdata->design_max_volt) {
	case CV_4100:
		val |= (CHRG_CCCV_CV_4100MV << CHRG_CCCV_CV_BIT_POS);
		break;
	case CV_4150:
		val |= (CHRG_CCCV_CV_4150MV << CHRG_CCCV_CV_BIT_POS);
		break;
	case CV_4200:
		val |= (CHRG_CCCV_CV_4200MV << CHRG_CCCV_CV_BIT_POS);
		break;
	case CV_4350:
		val |= (CHRG_CCCV_CV_4350MV << CHRG_CCCV_CV_BIT_POS);
		break;
	default:
		val |= (CHRG_CCCV_CV_4200MV << CHRG_CCCV_CV_BIT_POS);
		break;
	}

	ret = pmic_fg_reg_writeb(info, DC_CHRG_CCCV_REG, val);
fg_prog_ocv_fail:
	return ret;
}
static void pmic_fg_init_config_regs(struct pmic_fg_info *info)
{
	int ret;


	/*
	 * check if the config data is already
	 * programmed and if so just return.
	 */
	ret = pmic_fg_reg_readb(info, DC_FG_CNTL_REG);
	if (ret < 0) {
		dev_warn(&info->pdev->dev, "FG CNTL reg read err!!\n");
	} else if ((ret & FG_CNTL_OCV_ADJ_EN) && (ret & FG_CNTL_CAP_ADJ_EN)) {
		dev_info(&info->pdev->dev,
			"FG data except the OCV curve is initialized\n");
		/*
		 * ocv curve will be set to default values
		 * at every boot, so it is needed to explicitly write
		 * the ocv curve data for each boot
		 */
		ret = pmic_fg_program_ocv_curve(info);
		if (ret < 0)
			dev_err(&info->pdev->dev,
				"set ocv curve fail:%d\n", ret);
		/* comment the following for FW may have touched the regsiters */
		/*info->fg_init_done = true;*/
		/*pmic_fg_dump_init_regs(info);*/
		/*return;*/
	} else {
		dev_info(&info->pdev->dev, "FG data need to be initialized\n");
	}


	ret = pmic_fg_program_ocv_curve(info);
	if (ret < 0)
		dev_err(&info->pdev->dev, "set ocv curve fail:%d\n", ret);

	ret = pmic_fg_program_rdc_vals(info);
	if (ret < 0)
		dev_err(&info->pdev->dev, "set rdc fail:%d\n", ret);

	ret = pmic_fg_program_design_cap(info);
	if (ret < 0)
		dev_err(&info->pdev->dev, "set design cap fail:%d\n", ret);

	ret = pmic_fg_program_vbatt_full(info);
	if (ret < 0)
		dev_err(&info->pdev->dev, "set vbatt full fail:%d\n", ret);

	ret = pmic_fg_set_lowbatt_thresholds(info);
	if (ret < 0)
		dev_err(&info->pdev->dev, "lowbatt thr set fail:%d\n", ret);

	ret = pmic_fg_reg_writeb(info, DC_FG_CNTL_REG, 0xff);
	if (ret < 0)
		dev_err(&info->pdev->dev, "gauge cntl set fail:%d\n", ret);

	info->fg_init_done = true;
	pmic_fg_dump_init_regs(info);
}
static void pmic_fg_init_config_regs(struct pmic_fg_info *info)
{
	int ret;


	/*
	 * check if the config data is already
	 * programmed and if so just return.
	 */
	ret = pmic_fg_reg_readb(info, DC_FG_CNTL_REG);
	if (ret < 0) {
		dev_warn(&info->pdev->dev, "FG CNTL reg read err!!\n");
	} else if ((ret & FG_CNTL_OCV_ADJ_EN) && (ret & FG_CNTL_CAP_ADJ_EN)) {
		dev_dbg(&info->pdev->dev, "FG data is already initialized\n");
		/* comment the following for FW may have touched the regsiters */
		/* info->fg_init_done = true; */
		/* pmic_fg_dump_init_regs(info); */
		/* return; */
	} else {
		dev_dbg(&info->pdev->dev, "FG data need to be initialized\n");
	}


	ret = pmic_fg_program_ocv_curve(info);
	if (ret < 0)
		dev_err(&info->pdev->dev, "set ocv curve fail:%d\n", ret);

	ret = pmic_fg_program_rdc_vals(info);
	if (ret < 0)
		dev_err(&info->pdev->dev, "set rdc fail:%d\n", ret);

	ret = pmic_fg_program_design_cap(info);
	if (ret < 0)
		dev_err(&info->pdev->dev, "set design cap fail:%d\n", ret);

	ret = pmic_fg_program_vbatt_full(info);
	if (ret < 0)
		dev_err(&info->pdev->dev, "set vbatt full fail:%d\n", ret);

	ret = pmic_fg_set_lowbatt_thresholds(info);
	if (ret < 0)
		dev_err(&info->pdev->dev, "lowbatt thr set fail:%d\n", ret);

	ret = pmic_fg_reg_writeb(info, DC_FG_CNTL_REG, 0xf7);
	if (ret < 0)
		dev_err(&info->pdev->dev, "gauge cntl set fail:%d\n", ret);

	info->fg_init_done = true;
	/* no need to dump registers except in debug cases
	pmic_fg_dump_init_regs(info); */
}
static int pmic_fg_program_ocv_curve(struct pmic_fg_info *info)
{
	int ret, i;

	for (i = 0; i < BAT_CURVE_SIZE; i++) {
		ret = pmic_fg_reg_writeb(info,
			DC_FG_OCV_CURVE_REG + i, info->cfg->bat_curve[i]);
		if (ret < 0)
			goto fg_prog_ocv_fail;
	}

fg_prog_ocv_fail:
	return ret;
}