diff options
author | Ramakrishna Pallala <ramakrishna.pallala@intel.com> | 2010-12-09 10:37:48 +0000 |
---|---|---|
committer | Alan Cox <alan@linux.intel.com> | 2010-12-09 10:37:48 +0000 |
commit | 1fc57bbd3cd5bdf3e86341432b4b46ad71de72f3 (patch) | |
tree | 2f1f69b8564a9d399c23cc2b6d227d50ee4dec3f /drivers/power/intel_mdf_battery.c | |
parent | ea2d256bbbc11a09f87c2e6033a843e6d29464b7 (diff) | |
download | mrst-s0i3-test-1fc57bbd3cd5bdf3e86341432b4b46ad71de72f3.tar.gz mrst-s0i3-test-1fc57bbd3cd5bdf3e86341432b4b46ad71de72f3.tar.xz mrst-s0i3-test-1fc57bbd3cd5bdf3e86341432b4b46ad71de72f3.zip |
Added Support for SW Charge Termination
Check_charge_full function is added to determine the charge full
condition. Added a function calculate the charge cycles. Temperature
based charging worker is modified according to support SW charge
termination and maintenance charging.
Signed-off-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Diffstat (limited to 'drivers/power/intel_mdf_battery.c')
-rw-r--r-- | drivers/power/intel_mdf_battery.c | 225 |
1 files changed, 189 insertions, 36 deletions
diff --git a/drivers/power/intel_mdf_battery.c b/drivers/power/intel_mdf_battery.c index 5ae23fe5dee..7a24eebcfaa 100644 --- a/drivers/power/intel_mdf_battery.c +++ b/drivers/power/intel_mdf_battery.c @@ -301,6 +301,11 @@ enum { static void *otg_handle; static struct device *msic_dev; +/* Variables for counting charge cycles */ +static unsigned int charge_cycle_ctr; +static unsigned int chr_clmb_ctr; + + /* * This array represents the Battery Pack thermistor * temarature and corresponding ADC value limits @@ -1495,7 +1500,12 @@ static int msic_batt_do_charging(struct msic_power_module_info *mbi, dev_dbg(msic_dev, "Charger Enabled\n"); mutex_lock(&mbi->batt_lock); - mbi->batt_props.status = POWER_SUPPLY_STATUS_CHARGING; + spin_lock(&mbi->event_lock); + if (mbi->charging_mode == BATT_CHARGING_MODE_MAINTAINENCE) + mbi->batt_props.status = POWER_SUPPLY_STATUS_FULL; + else + mbi->batt_props.status = POWER_SUPPLY_STATUS_CHARGING; + spin_unlock(&mbi->event_lock); mbi->batt_props.health = POWER_SUPPLY_HEALTH_GOOD; mutex_unlock(&mbi->batt_lock); @@ -1572,6 +1582,111 @@ static void msic_update_disconn_status(struct msic_power_module_info *mbi) power_supply_changed(&mbi->batt); } +static int check_charge_full(struct msic_power_module_info *mbi, int vref) +{ + static int vbat_prev[HYSTR_SAMPLE_MAX]; + int vflag, vbat, vbat_diff, vocv, i; + int ibatt_avg, is_full = false; + + /* Read battey vbatt */ + vbat = mdf_read_adc_regs(MSIC_ADC_VOL_IDX, mbi); + /* Read battery current */ + ibatt_avg = read_avg_ibatt(mbi); + + /* Check the Vbat is consitant with in the range */ + for (i = 0; i < HYSTR_SAMPLE_MAX; i++) { + vbat_diff = vbat - vbat_prev[i]; + if (vbat_diff >= -20 && vbat_diff <= 20) + continue; + else + break; + } + + if (i >= HYSTR_SAMPLE_MAX) + vflag = true; + else + vflag = false; + + /* + * Rbatt value should be read from SMIP header but as a + * temporary fix we are hardcoding the Rbatt as 180 mOhms + */ + vocv = vbat - (ibatt_avg * MSIC_CHRG_RBATT_VAL)/1000; + dev_dbg(msic_dev, "vocv:%d vbat:%d\n", vocv, vbat); + + /* + * Check if Vbat is equal to max charge voltage and + * charge rate is less than or equal to 0.05 coloumbs + */ + if (vflag && (vocv >= (vref - BATT_ADC_VOLT_ERROR))) { + dev_dbg(msic_dev, "Charge Full Detected\n"); + /* Disable Charging */ + msic_batt_stop_charging(mbi); + is_full = true; + } + + /* Push the array with latest value */ + for (i = HYSTR_SAMPLE_MAX - 1; i > 0; i--) + vbat_prev[i] = vbat_prev[i-1]; + vbat_prev[0] = vbat; + + return is_full; +} + +static bool is_maint_cutoff_vol(int adc_volt) +{ + static int vmaint_prev[HYSTR_SAMPLE_MAX]; + int i; + bool flag; + + /* Check whether the voltage is droping + * consistantly to enable maintenence charging + */ + for (i = 0; i < HYSTR_SAMPLE_MAX; i++) { + if (adc_volt < vmaint_prev[i]) + continue; + else + break; + } + + if (i >= HYSTR_SAMPLE_MAX) + flag = true; + else + flag = false; + + /* Push the array with latest value */ + for (i = HYSTR_SAMPLE_MAX - 1; i > 0; i--) + vmaint_prev[i] = vmaint_prev[i-1]; + vmaint_prev[0] = adc_volt; + + return flag; +} + +static void calculate_charge_cycles(struct msic_power_module_info *mbi, + bool start_bit) +{ + static unsigned int chr_prev; + unsigned int chr_now, chr_now_ctr, chr_prev_ctr = 0; + + if (start_bit) + chr_prev = 0; + + chr_now = msic_read_coloumb_ctr(); + chr_now_ctr = cc_to_coloumbs(chr_now); + + chr_prev_ctr = cc_to_coloumbs(chr_prev); + + /* count inflow charge given by charger */ + if (!chr_prev) + chr_clmb_ctr += chr_now_ctr - chr_prev_ctr; + + if (chr_clmb_ctr >= CHARGE_FULL_IN_MAH) { + charge_cycle_ctr++; + chr_clmb_ctr = 0; + } + chr_prev = chr_now; +} + /** * msic_batt_temp_charging - manages the charging based on temperature * @charge_param: charging parameter @@ -1582,9 +1697,9 @@ static void msic_update_disconn_status(struct msic_power_module_info *mbi) */ static void msic_batt_temp_charging(struct work_struct *work) { - int ret, i; - static int iprev = -1; - short int cv = 0, cc = 0, vinlimit = 0; + int ret, i, charge_now, is_maint_chrg = false; + static int iprev = -1, is_chrg_enbl; + short int cv = 0, cc = 0, vinlimit = 0, cvref; int adc_temp, adc_vol; struct charge_params charge_param; struct msic_power_module_info *mbi = container_of(work, @@ -1600,13 +1715,13 @@ static void msic_batt_temp_charging(struct work_struct *work) POWER_SUPPLY_CHARGE_TYPE_UNKNOWN || mbi->usb_chrg_props.charger_type == POWER_SUPPLY_CHARGE_TYPE_NONE) { - /* * If the the charger type is unknown or None * better start the charging again and compute * the properties again. */ iprev = -1; + is_chrg_enbl = false; } mutex_unlock(&mbi->usb_chrg_lock); @@ -1620,6 +1735,7 @@ static void msic_batt_temp_charging(struct work_struct *work) cv = sfi_table->temp_mon_range[i].full_chrg_vol; cc = sfi_table->temp_mon_range[i].full_chrg_cur; + cvref = cv; /* D7,D6 bits of CHRCNTL will set the VINILMT */ if (charge_param.vinilmt > 950) @@ -1637,48 +1753,71 @@ static void msic_batt_temp_charging(struct work_struct *work) if (i >= sfi_table->temp_mon_ranges) { dev_warn(msic_dev, "TEMP RANGE NOT EXIST\n"); + /* + * If we are in middle of charge cycle is safer to Reset WDT + * Timer Register.Because battery temperature and Changre + * status register are not related. + */ + reset_wdt_timer(mbi); goto lbl_sched_work; } /* + * Check for Charge full condition and set the battery + * properties accordingly. Also check for charging mode + * whether it is normal or maintenence mode. + */ + spin_lock(&mbi->event_lock); + if (mbi->charging_mode == BATT_CHARGING_MODE_MAINTAINENCE) { + cvref = sfi_table->temp_mon_range[i].maint_chrg_vol_ul; + is_maint_chrg = true; + } + ret = check_charge_full(mbi, cvref); + if (ret) { + is_chrg_enbl = false; + if (mbi->charging_mode != BATT_CHARGING_MODE_MAINTAINENCE) { + dev_dbg(msic_dev, "Going to Maintenence CHRG Mode\n"); + mbi->charging_mode = BATT_CHARGING_MODE_MAINTAINENCE; + is_maint_chrg = true; + + mutex_lock(&mbi->batt_lock); + charge_now = msic_read_coloumb_ctr(); + mbi->batt_props.charge_full = + cc_to_coloumbs(charge_now); + mbi->batt_props.status = POWER_SUPPLY_STATUS_FULL; + mutex_unlock(&mbi->batt_lock); + } + } + spin_unlock(&mbi->event_lock); + + /* * If we are in same Temparature range check for check for the * maintainence charging mode and enable the charging depending - * on the adc voltage and lower threshold. - * If Temparature range is changed then anyways we need to set - * charging parameters and enable charging, in that case no need - * to check for Maintainence mode. + * on the voltage.If Temparature range is changed then anyways + * we need to set charging parameters and enable charging. */ if (i == iprev) { - - spin_lock(&mbi->event_lock); - if (mbi->charging_mode == BATT_CHARGING_MODE_MAINTAINENCE) { - - spin_unlock(&mbi->event_lock); + /* + * Check if the voltage falls below lower threshold + * if we are in maintenence mode charging. + */ + if (is_maint_chrg && !is_chrg_enbl) { temp_mon = &sfi_table->temp_mon_range[i]; - /* Read ADC value for battery Voltage */ + /* Read battery Voltage */ adc_vol = mdf_read_adc_regs(MSIC_ADC_VOL_IDX, mbi); - /* - * Check if the voltage falls below lower threshold - * set charge voltage to maintainence voltage upper - * limit and enable charging otherwise just - * schedule the work - */ - if (adc_vol <= temp_mon->maint_chrg_vol_ll) + /* Cosidering ADC error of BATT_ADC_VOLT_ERROR */ + if ((adc_vol + 20) <= temp_mon->maint_chrg_vol_ll && + is_maint_cutoff_vol(adc_vol)) { + dev_dbg(msic_dev, "restart charging\n"); cv = temp_mon->maint_chrg_vol_ul; - else + } else { + dev_dbg(msic_dev, "vbat is more than ll\n"); goto lbl_sched_work; - + } } else { - - spin_unlock(&mbi->event_lock); - - /* - * We are not in normal Mode and no change in temp - * range so just write the WDT timer and - * schedule the wirk again. - */ - dev_dbg(msic_dev, "NoChange in Temp Range\n"); + /* count charge cycles */ + calculate_charge_cycles(mbi, false); /* Reset WDT Timer Register for 60 Sec */ reset_wdt_timer(mbi); goto lbl_sched_work; @@ -1696,9 +1835,6 @@ static void msic_batt_temp_charging(struct work_struct *work) cc = cc << 3; charge_param.ccur = cc; - - /* Enable Charge Termination */ - vinlimit |= 0x08; charge_param.vinilmt = vinlimit; dev_dbg(msic_dev, "params vol: %x cur:%x vinilmt:%x\n", @@ -1726,6 +1862,9 @@ static void msic_batt_temp_charging(struct work_struct *work) dev_warn(msic_dev, "msic_batt_do_charging failed\n"); goto lbl_sched_work; } + /* Start cycle counting */ + calculate_charge_cycles(mbi, true); + is_chrg_enbl = true; power_supply_changed(&mbi->usb); lbl_sched_work: @@ -2353,6 +2492,19 @@ ioremap_failed: return retval; } +static void do_exit_ops(struct msic_power_module_info *mbi) +{ + /* disable MSIC Charger */ + mutex_lock(&mbi->batt_lock); + if (mbi->batt_props.status != POWER_SUPPLY_STATUS_DISCHARGING) + msic_batt_stop_charging(mbi); + mutex_unlock(&mbi->batt_lock); + + /* Check charge Cycles */ + if (chr_clmb_ctr >= (CHARGE_FULL_IN_MAH / 2)) + charge_cycle_ctr++; +} + /** * msic_battery_remove - msic battery finalize * @pdev: msic battery platform device structure @@ -2371,6 +2523,7 @@ static int msic_battery_remove(struct platform_device *pdev) flush_scheduled_work(); free_adc_channels(mbi->adc_index, mbi); free_irq(mbi->irq, mbi); + do_exit_ops(mbi); if (mbi->msic_regs_iomap != NULL) iounmap(mbi->msic_regs_iomap); device_remove_file(&pdev->dev, &dev_attr_emrg_charge_enable); |