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 | ea2d256bbbc11a09f87c2e6033a843e6d29464b7 (patch) | |
tree | fe9525a32d8a85af75a14bcc0a32b62df626f1dd /drivers | |
parent | 08a442e6134ed287308a5ec9c864b27fa01f3e24 (diff) | |
download | mrst-s0i3-test-ea2d256bbbc11a09f87c2e6033a843e6d29464b7.tar.gz mrst-s0i3-test-ea2d256bbbc11a09f87c2e6033a843e6d29464b7.tar.xz mrst-s0i3-test-ea2d256bbbc11a09f87c2e6033a843e6d29464b7.zip |
Added Support for Fuel Gauging
To support fuel gauging Energy now, Energy full, charge counter and capacity
level Sysfs Interfaces are added to driver.
A table is added to look up voltage against charge.
Signed-off-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/power/intel_mdf_battery.c | 196 |
1 files changed, 190 insertions, 6 deletions
diff --git a/drivers/power/intel_mdf_battery.c b/drivers/power/intel_mdf_battery.c index 6385be842a1..5ae23fe5dee 100644 --- a/drivers/power/intel_mdf_battery.c +++ b/drivers/power/intel_mdf_battery.c @@ -244,6 +244,37 @@ #define BATT_STRING_MAX 8 #define HYSTR_SAMPLE_MAX 4 +#define DISCHRG_CURVE_MAX_SAMPLES 17 +#define DISCHRG_CURVE_MAX_COLOMNS 2 + + +/* + * This array represents the Discharge curve of the battery + * Colomn 0 represnts Voltage in mV and colomn 1 represent + * charge in mColoumbs. + */ +static uint32_t const dischargeCurve[DISCHRG_CURVE_MAX_SAMPLES] + [DISCHRG_CURVE_MAX_COLOMNS] = { + /* in mV , in mC */ + {4200, 56603000}, + {4150, 55754000}, + {4100, 54905000}, + {4050, 52385000}, + {4000, 49811000}, + {3950, 46697000}, + {3900, 43584000}, + {3850, 39339000}, + {3800, 35094000}, + {3750, 27452000}, + {3700, 19811000}, + {3650, 12735000}, + {3600, 5660000}, + {3550, 3963000}, + {3500, 2264000}, + {3450, 1132000}, + {3400, 0} +}; + /* Valid msic exceptional events */ enum msic_event { @@ -356,9 +387,13 @@ struct msic_batt_props { unsigned int vol_max_des; unsigned int vol_now; unsigned int cur_now; - unsigned int charge_full; /* in mAS */ - unsigned int charge_now; /* in mAS */ - unsigned int charge_avg; /* in units per second */ + unsigned int charge_full; /* in mAh */ + unsigned int charge_now; /* in mAh */ + unsigned int charge_ctr; /* Coloumb counter raw value */ + unsigned int charge_avg; /* moving avg of charge now */ + unsigned int energy_full; /* in mWh */ + unsigned int energy_now; /* in mWh */ + unsigned int capacity_level; /* enumerated values */ unsigned int capacity; /* in units persentage */ unsigned int temperature; /* in milli Centigrade*/ char model[BATT_STRING_MAX]; @@ -471,14 +506,19 @@ static enum power_supply_property msic_battery_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_AVG, - POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ + POWER_SUPPLY_PROP_ENERGY_FULL, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MANUFACTURER, }; + static int enable_adc(struct msic_power_module_info *mbi) { int ret; @@ -931,6 +971,128 @@ static unsigned int mdf_cal_avg(unsigned int avg) return avg / 2; } +static unsigned int chrg_to_vol_lookup(unsigned int chrg) +{ + int ch_diff, ch_total_diff, volt_total_diff, i; + unsigned int volt; + + /* Find the index of most nearest charge value */ + for (i = 0; i < DISCHRG_CURVE_MAX_SAMPLES; i++) { + if (chrg < dischargeCurve[i][1]) + continue; + else + break; + } + + if (i >= DISCHRG_CURVE_MAX_SAMPLES) { + dev_dbg(msic_dev, "charge out of range\n"); + return 0; + } + + if (chrg == dischargeCurve[i][1]) + return dischargeCurve[i][0]; + + /* Linear approximation of the charge to voltage */ + ch_diff = chrg - dischargeCurve[i][1]; + ch_total_diff = dischargeCurve[i-1][1] - dischargeCurve[i][1]; + volt_total_diff = dischargeCurve[i-1][0] - dischargeCurve[i][0]; + + volt = dischargeCurve[i][0] + + (ch_diff * volt_total_diff) / ch_total_diff; + + return volt; +} + +static unsigned int msic_read_energy_now(struct msic_power_module_info *mbi) +{ + unsigned int vltg, chrg; + + /* Read CC register value */ + chrg = msic_read_coloumb_ctr(); + /* Covert to milli coloumbs */ + chrg = cc_to_coloumbs(chrg); + + /* get voltage form lookup table */ + vltg = chrg_to_vol_lookup(chrg); + + /* Convert from mColoumbs to mAh */ + chrg = chrg / COLMB_TO_MAHRS_CONV_FCTR; + + return (vltg * chrg) / 1000; +} + +static int read_avg_ibatt(struct msic_power_module_info *mbi) +{ + int i, ibatt[HYSTR_SAMPLE_MAX], ibatt_avg = 0; + + /* Measure battey average current */ + for (i = 0; i < HYSTR_SAMPLE_MAX; i++) { + ibatt[i] = mdf_read_adc_regs(MSIC_ADC_CUR_IDX, mbi); + ibatt_avg += ibatt[i]; + } + ibatt_avg = ibatt_avg / HYSTR_SAMPLE_MAX; + + return ibatt_avg; +} + +static unsigned int calculate_batt_capacity(struct msic_power_module_info *mbi) +{ + int vocv, vbatt, ibatt; + unsigned int cap_perc; + + vbatt = mdf_read_adc_regs(MSIC_ADC_VOL_IDX, mbi); + ibatt = read_avg_ibatt(mbi); + + vocv = vbatt - (ibatt * MSIC_CHRG_RBATT_VAL) / 1000; + + /* Temporary fix for calculating capacity. + * will be modified once Coloumb Counter + * works correctly. + */ + vocv = vocv - BATT_DEAD_CUTOFF_VOLT; + if (vocv < 0) + vocv = 0; + + cap_perc = (vocv * 100) / (mbi->batt_props.vol_max_des - + BATT_DEAD_CUTOFF_VOLT); + + /* vocv can be slighlty more than voltage + * max value if the ibatt is -ve and vbatt + * has reached a maximum value. + */ + if (cap_perc > 100) + cap_perc = 100; + + return cap_perc; +} + +static int msic_read_capacity_level(struct msic_power_module_info *mbi) +{ + int cap_perc, cap_level; + + /* Calculate % of charge left */ + cap_perc = calculate_batt_capacity(mbi); + + /* + * 0, 15, 40, 85 threshold cut-offs are temporary + * actuall thresholds will be read from SMIP header + */ + if (cap_perc >= 0 && cap_perc < 15) + cap_level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; + else if (cap_perc >= 15 && cap_perc < 40) + cap_level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; + else if (cap_perc >= 40 && cap_perc < 85) + cap_level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; + else if (cap_perc >= 85 && cap_perc < 100) + cap_level = POWER_SUPPLY_CAPACITY_LEVEL_HIGH; + else if (cap_perc == 100) + cap_level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; + else + cap_level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; + + return cap_level; +} + /** * msic_battery_get_property - battery power source get property * @psy: battery power supply context @@ -987,6 +1149,10 @@ static int msic_battery_get_property(struct power_supply *psy, mbi->batt_props.charge_now = msic_get_charge_now(); val->intval = mbi->batt_props.charge_now * 1000; break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + mbi->batt_props.charge_ctr = msic_read_coloumb_ctr(); + val->intval = mbi->batt_props.charge_ctr; + break; case POWER_SUPPLY_PROP_CHARGE_FULL: val->intval = mbi->batt_props.charge_full * 1000; break; @@ -995,7 +1161,19 @@ static int msic_battery_get_property(struct power_supply *psy, mdf_cal_avg(mbi->batt_props.charge_avg); val->intval = mbi->batt_props.charge_avg * 1000; break; + case POWER_SUPPLY_PROP_ENERGY_FULL: + val->intval = mbi->batt_props.energy_full * 1000; + break; + case POWER_SUPPLY_PROP_ENERGY_NOW: + mbi->batt_props.energy_now = msic_read_energy_now(mbi); + val->intval = mbi->batt_props.energy_now * 1000; + break; + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: + mbi->batt_props.capacity_level = msic_read_capacity_level(mbi); + val->intval = mbi->batt_props.capacity_level; + break; case POWER_SUPPLY_PROP_CAPACITY: + mbi->batt_props.capacity = calculate_batt_capacity(mbi); val->intval = mbi->batt_props.capacity; break; case POWER_SUPPLY_PROP_TEMP: @@ -1931,9 +2109,15 @@ static void init_batt_props(struct msic_power_module_info *mbi) mbi->batt_props.cur_now = 0x0; mbi->batt_props.charge_full = CHARGE_FULL_IN_MAH; mbi->batt_props.charge_now = 0x0; + mbi->batt_props.charge_ctr = 0x0; mbi->batt_props.charge_avg = 0x0; - mbi->batt_props.capacity = 0; - mbi->batt_props.temperature = 0; + mbi->batt_props.capacity = 0x0; + mbi->batt_props.capacity_level = POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN; + mbi->batt_props.temperature = 0x0; + + mbi->batt_props.energy_now = 0x0; + mbi->batt_props.energy_full = (mbi->batt_props.vol_max_des * + mbi->batt_props.charge_full) / 1000; memcpy(mbi->batt_props.vender, sfi_table->batt_id.manufac, sizeof(sfi_table->batt_id.manufac)); |