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; }