power: pm8921-bms: support wireless charger bms
Since WLC(wireless charger) supply power to battery without PM8921 charger,
the SoC value is not accurate. This patch adjust OCV(open circuit voltage)
and max CV(constant voltage) value to compensate difference between
WLC and pm8921-charger.
Change-Id: I8fa368f706866d93451c2f663da69c010f9b2a35
diff --git a/drivers/power/bq51051b_charger.c b/drivers/power/bq51051b_charger.c
index 4e0cf41..b6dbe2f 100644
--- a/drivers/power/bq51051b_charger.c
+++ b/drivers/power/bq51051b_charger.c
@@ -33,6 +33,7 @@
struct work_struct wireless_interrupt_work;
struct wake_lock wireless_chip_wake_lock;
unsigned int active_n_gpio;
+ int (*wlc_is_plugged)(void);
};
static const struct platform_device_id bq51051b_id[] = {
@@ -81,21 +82,6 @@
return 0;
}
-static int wireless_is_plugged(struct bq51051b_wlc_chip *chip)
-{
- return !(gpio_get_value(chip->active_n_gpio));
-}
-
-int bq51051b_wireless_plugged_in(void)
-{
- if (!the_chip) {
- pr_err("wlc: called before init\n");
- return -EINVAL;
- }
- return wireless_is_plugged(the_chip);
-}
-EXPORT_SYMBOL(bq51051b_wireless_plugged_in);
-
static void wireless_set(struct bq51051b_wlc_chip *chip)
{
WLC_DBG_INFO("wireless_set\n");
@@ -132,7 +118,7 @@
container_of(work, struct bq51051b_wlc_chip,
wireless_interrupt_work);
- if (wireless_is_plugged(chip))
+ if (chip->wlc_is_plugged())
wireless_set(chip);
else
wireless_reset(chip);
@@ -143,7 +129,7 @@
int chg_state;
struct bq51051b_wlc_chip *chip = data;
- chg_state = wireless_is_plugged(chip);
+ chg_state = chip->wlc_is_plugged();
WLC_DBG_INFO("\nwireless is plugged state = %d\n\n", chg_state);
schedule_work(&chip->wireless_interrupt_work);
return IRQ_HANDLED;
@@ -154,13 +140,6 @@
int ret;
WLC_DBG_INFO("hw_init");
- /* active_n pin is the bq51051b status, High = no charging, Low = charging */
- ret = gpio_request_one(chip->active_n_gpio, GPIOF_DIR_IN, "active_n_gpio");
- if (ret < 0) {
- pr_err("wlc: active_n gpio request failed\n");
- goto active_n_error;
- }
-
/* active_n pin must be monitoring the bq51051b status */
ret = request_irq(gpio_to_irq(chip->active_n_gpio),
wireless_interrupt_handler,
@@ -168,16 +147,11 @@
"wireless_charger", chip);
if (ret < 0) {
pr_err("wlc: wireless_charger request irq failed\n");
- goto active_n_irq_error;
+ return ret;
}
enable_irq_wake(gpio_to_irq(chip->active_n_gpio));
return 0;
-
-active_n_irq_error:
- gpio_free(chip->active_n_gpio);
-active_n_error:
- return ret;
}
static int bq51051b_wlc_resume(struct device *dev)
@@ -213,6 +187,7 @@
chip->dev = &pdev->dev;
chip->active_n_gpio = pdata->active_n_gpio;
+ chip->wlc_is_plugged = pdata->wlc_is_plugged;
rc = bq51051b_wlc_hw_init(chip);
if (rc) {
@@ -243,7 +218,7 @@
"bq51051b_wireless_chip");
/* For Booting Wireless_charging and For Power Charging Logo In Wireless Charging */
- if (wireless_is_plugged(chip))
+ if (chip->wlc_is_plugged())
wireless_set(chip);
return 0;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 98fa37c..c6cc845 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -151,6 +151,11 @@
int last_reported_soc;
int eoc_check_soc;
int soc_adjusted;
+ int bms_support_wlc;
+ int wlc_term_ua;
+ int wlc_max_voltage_uv;
+ int (*wlc_is_plugged)(void);
+ int vbat_at_cv;
};
/*
@@ -363,16 +368,8 @@
val = 0;
}
- return val;
-}
-
-static int wireless_chg_plugged_in(void)
-{
- int val = bq51051b_wireless_plugged_in();
-
- /* treat as if usb is not present in case of error */
- if (val == -EINVAL)
- val = 0;
+ if (chip->bms_support_wlc)
+ val |= chip->wlc_is_plugged();
return val;
}
@@ -965,7 +962,6 @@
mutex_unlock(&the_chip->bms_output_lock);
usb_chg = usb_chg_plugged_in(the_chip);
- usb_chg |= wireless_chg_plugged_in();
convert_vbatt_raw_to_uv(the_chip, usb_chg, vbat_raw, vbat_uv);
convert_vsense_to_uv(the_chip, vsense_raw, &vsense_uv);
@@ -991,6 +987,27 @@
raw->last_good_ocv_raw -= MBG_TRANSIENT_ERROR_RAW;
}
+#define SEL_ALT_OREG_BIT BIT(2)
+static int ocv_ir_compensation(struct pm8921_bms_chip *chip, int ocv)
+{
+ int compensated_ocv;
+ int ibatt_ua;
+ int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
+
+ pm_bms_masked_write(chip, BMS_TEST1,
+ SEL_ALT_OREG_BIT, SEL_ALT_OREG_BIT);
+
+ /* since the SEL_ALT_OREG_BIT is set this will give us VSENSE_OCV */
+ pm8921_bms_get_battery_current(&ibatt_ua);
+ compensated_ocv = ocv + div_s64((s64)ibatt_ua * rbatt_mohm, 1000);
+ pr_info("comp ocv = %d, ocv = %d, ibatt_ua = %d, rbatt_mohm = %d\n",
+ compensated_ocv, ocv, ibatt_ua, rbatt_mohm);
+
+ pm_bms_masked_write(chip, BMS_TEST1, SEL_ALT_OREG_BIT, 0);
+ return compensated_ocv;
+}
+
+
static int read_soc_params_raw(struct pm8921_bms_chip *chip,
struct pm8921_soc_params *raw)
{
@@ -1007,13 +1024,14 @@
mutex_unlock(&chip->bms_output_lock);
usb_chg = usb_chg_plugged_in(chip);
- usb_chg |= wireless_chg_plugged_in();
if (chip->prev_last_good_ocv_raw == 0) {
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
adjust_pon_ocv_raw(chip, raw);
convert_vbatt_raw_to_uv(chip, usb_chg,
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
+ raw->last_good_ocv_uv = ocv_ir_compensation(chip,
+ raw->last_good_ocv_uv);
chip->last_ocv_uv = raw->last_good_ocv_uv;
pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
@@ -1610,20 +1628,40 @@
int fcc_uah, int cc_uah, int uuc_uah)
{
int chg_soc;
+ int max_vol;
+ int eoc_current;
+
+ max_vol = chip->max_voltage_uv;
+ eoc_current = -chip->chg_term_ua;
+
+ if (chip->bms_support_wlc && chip->wlc_is_plugged()) {
+ max_vol = chip->wlc_max_voltage_uv;
+ eoc_current = -chip->wlc_term_ua;
+ }
if (chip->soc_at_cv == -EINVAL) {
/* In constant current charging return the calc soc */
- if (vbat_uv <= chip->max_voltage_uv)
+ if (vbat_uv <= max_vol)
pr_debug("CC CHG SOC %d\n", soc);
/* Note the CC to CV point */
- if (vbat_uv >= chip->max_voltage_uv) {
+ if (vbat_uv >= max_vol) {
chip->soc_at_cv = soc;
chip->prev_chg_soc = soc;
chip->ibat_at_cv_ua = ibat_ua;
+ chip->vbat_at_cv = vbat_uv;
pr_debug("CC_TO_CV ibat_ua = %d CHG SOC %d\n",
ibat_ua, soc);
}
+ else if(soc >= 95)
+ {
+ chip->soc_at_cv = soc;
+ chip->prev_chg_soc = soc;
+ chip->ibat_at_cv_ua = ibat_ua;
+ chip->vbat_at_cv = vbat_uv;
+ pr_debug("Force CC_TO_CV ibat_ua = %d CHG SOC %d\n",
+ ibat_ua, soc);
+ }
return soc;
}
@@ -1636,15 +1674,25 @@
* if voltage lessened (possibly because of a system load)
* keep reporting the prev chg soc
*/
- if (vbat_uv <= chip->max_voltage_uv) {
+ if (vbat_uv <= chip->vbat_at_cv) {
pr_debug("vbat %d < max = %d CC CHG SOC %d\n",
- vbat_uv, chip->max_voltage_uv, chip->prev_chg_soc);
+ vbat_uv, chip->vbat_at_cv, chip->prev_chg_soc);
+ return chip->prev_chg_soc;
+ }
+
+ if (chip->bms_support_wlc
+ && chip->wlc_is_plugged()
+ && chip->prev_chg_soc < 99
+ && ibat_ua > eoc_current) {
+ pr_info("ibat < eco_current ! soc = %d \n", chip->prev_chg_soc);
return chip->prev_chg_soc;
}
chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua,
- 100, -100000,
+ 100, eoc_current,
ibat_ua);
+ if (chg_soc > 100)
+ chg_soc = 100;
/* always report a higher soc */
if (chg_soc > chip->prev_chg_soc) {
@@ -2325,7 +2373,7 @@
voltage = xoadc_reading_to_microvolt(result.adc_code);
usb_chg = usb_chg_plugged_in(chip);
- usb_chg |= wireless_chg_plugged_in();
+
pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld "
"usb_chg = %d\n",
result.adc_code, voltage, result.measurement,
@@ -2813,7 +2861,7 @@
ocv_uv = 0;
pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &ocv_raw);
usb_chg = usb_chg_plugged_in(chip);
- usb_chg |= wireless_chg_plugged_in();
+
rc = convert_vbatt_raw_to_uv(chip, usb_chg, ocv_raw, &ocv_uv);
if (rc || ocv_uv == 0) {
rc = adc_based_ocv(chip, &ocv_uv);
@@ -3288,6 +3336,13 @@
chip->last_reported_soc = -EINVAL;
chip->eoc_check_soc = pdata->eoc_check_soc;
chip->soc_adjusted = 0;
+ chip->bms_support_wlc = pdata->bms_support_wlc;
+ if (chip->bms_support_wlc) {
+ chip->wlc_term_ua = pdata->wlc_term_ua;
+ chip->wlc_max_voltage_uv = pdata->wlc_max_voltage_uv;
+ chip->wlc_is_plugged = pdata->wlc_is_plugged;
+ }
+ chip->vbat_at_cv = -EINVAL;
mutex_init(&chip->calib_mutex);
INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);