/* bit definitions of Measurement Off Time Register */ #define MEAS_OFF_SLEEP_EN (1 << 1)
/* bit definitions of GPADC Bias Current 2 Register */ #define GPBIAS2_GPADC1_SET (2 << 4) /* GPADC1 Bias Current value in uA unit */ #define GPBIAS2_GPADC1_UA ((GPBIAS2_GPADC1_SET >> 4) * 5 + 1)
/* bit definitions of GPADC Misc 1 Register */ #define GPMISC1_GPADC_EN (1 << 0)
/* bit definitions of Charger Control 6 Register */ #define CC6_BAT_DET_GPADC1 1
/* bit definitions of Coulomb Counter Reading Register */ #define CCNT_AVG_SEL (4 << 3)
/* bit definitions of RTC miscellaneous Register1 */ #define RTC_SOC_5LSB (0x1F << 3)
/* bit definitions of RTC Register1 */ #define RTC_SOC_3MSB (0x7)
/* bit definitions of Power up Log register */ #define BAT_WU_LOG (1<<6)
struct power_supply *battery; struct mutex lock; int status; int irq_cc; int irq_batt; int max_capacity; int resistor; /* Battery Internal Resistor */ int last_capacity; int start_soc; unsigned present:1; unsigned temp_type:1; /* TINT or TBAT */
};
staticint calc_ccnt(struct pm860x_battery_info *info, struct ccnt *ccnt)
{ unsignedint sum; int ret; int data;
ret = read_ccnt(info, CCNT_POS1, &data); if (ret) goto out;
sum = data & 0xffff;
ret = read_ccnt(info, CCNT_POS2, &data); if (ret) goto out;
sum |= (data & 0xffff) << 16;
ccnt->pos += sum;
ret = read_ccnt(info, CCNT_NEG1, &data); if (ret) goto out;
sum = data & 0xffff;
ret = read_ccnt(info, CCNT_NEG2, &data); if (ret) goto out;
sum |= (data & 0xffff) << 16;
sum = ~sum + 1; /* since it's negative */
ccnt->neg += sum;
ret = read_ccnt(info, CCNT_SPOS, &data); if (ret) goto out;
ccnt->spos += data;
ret = read_ccnt(info, CCNT_SNEG, &data); if (ret) goto out;
/* Calculate Open Circuit Voltage */ staticint calc_ocv(struct pm860x_battery_info *info, int *ocv)
{ int ret; int i; int data; int vbatt_avg; int vbatt_sum; int ibatt_avg; int ibatt_sum;
if (!ocv) return -EINVAL;
for (i = 0, ibatt_sum = 0, vbatt_sum = 0; i < 10; i++) {
ret = measure_vbatt(info, OCV_MODE_ACTIVE, &data); if (ret) goto out;
vbatt_sum += data;
ret = measure_current(info, &data); if (ret) goto out;
ibatt_sum += data;
}
vbatt_avg = vbatt_sum / 10;
ibatt_avg = ibatt_sum / 10;
/* Calculate State of Charge (percent points) */ staticint calc_soc(struct pm860x_battery_info *info, int state, int *soc)
{ int i; int ocv; int count; int ret = -EINVAL;
if (!soc) return -EINVAL;
switch (state) { case OCV_MODE_ACTIVE:
ret = calc_ocv(info, &ocv); break; case OCV_MODE_SLEEP:
ret = measure_vbatt(info, OCV_MODE_SLEEP, &ocv); break;
} if (ret) return ret;
mutex_lock(&info->lock);
ret = pm860x_reg_read(info->i2c, PM8607_STATUS_2); if (ret & STATUS2_BAT) {
info->present = 1;
info->temp_type = PM860X_TEMP_TBAT;
} else {
info->present = 0;
info->temp_type = PM860X_TEMP_TINT;
}
mutex_unlock(&info->lock); /* clear ccnt since battery is attached or detached */
clear_ccnt(info, &ccnt_data); return IRQ_HANDLED;
}
staticvoid pm860x_init_battery(struct pm860x_battery_info *info)
{ unsignedchar buf[2]; int ret; int data; int bat_remove; int soc = 0;
/* measure enable on GPADC1 */
data = MEAS1_GP1; if (info->temp_type == PM860X_TEMP_TINT)
data |= MEAS1_TINT;
ret = pm860x_set_bits(info->i2c, PM8607_MEAS_EN1, data, data); if (ret) goto out;
/* measure enable on IBAT, BAT_DET, CC. IBAT is depend on CC. */
data = MEAS3_IBAT | MEAS3_BAT_DET | MEAS3_CC;
ret = pm860x_set_bits(info->i2c, PM8607_MEAS_EN3, data, data); if (ret) goto out;
/* measure disable CC in sleep time */
ret = pm860x_reg_write(info->i2c, PM8607_MEAS_OFF_TIME1, 0x82); if (ret) goto out;
ret = pm860x_reg_write(info->i2c, PM8607_MEAS_OFF_TIME2, 0x6c); if (ret) goto out;
/* enable GPADC */
ret = pm860x_set_bits(info->i2c, PM8607_GPADC_MISC1,
GPMISC1_GPADC_EN, GPMISC1_GPADC_EN); if (ret < 0) goto out;
/* detect battery via GPADC1 */
ret = pm860x_set_bits(info->i2c, PM8607_CHG_CTRL6,
CC6_BAT_DET_GPADC1, CC6_BAT_DET_GPADC1); if (ret < 0) goto out;
ret = pm860x_set_bits(info->i2c, PM8607_CCNT, 7 << 3,
CCNT_AVG_SEL); if (ret < 0) goto out;
/* set GPADC1 bias */
ret = pm860x_set_bits(info->i2c, PM8607_GP_BIAS2, 0xF << 4,
GPBIAS2_GPADC1_SET); if (ret < 0) goto out;
staticint calc_resistor(struct pm860x_battery_info *info)
{ int vbatt_sum1; int vbatt_sum2; int chg_current; int ibatt_sum1; int ibatt_sum2; int data; int ret; int i;
ret = measure_current(info, &data); /* make sure that charging is launched by data > 0 */ if (ret || data < 0) goto out;
ret = measure_vbatt(info, OCV_MODE_ACTIVE, &data); if (ret) goto out; /* calculate resistor only in CC charge mode */ if (data < VBATT_RESISTOR_MIN || data > VBATT_RESISTOR_MAX) goto out;
/* current is saved */ if (set_charger_current(info, 500, &chg_current)) goto out;
for (i = 0, vbatt_sum1 = 0, ibatt_sum1 = 0; i < 10; i++) {
ret = measure_vbatt(info, OCV_MODE_ACTIVE, &data); if (ret) goto out_meas;
vbatt_sum1 += data;
ret = measure_current(info, &data); if (ret) goto out_meas;
for (i = 0, vbatt_sum2 = 0, ibatt_sum2 = 0; i < 10; i++) {
ret = measure_vbatt(info, OCV_MODE_ACTIVE, &data); if (ret) goto out_meas;
vbatt_sum2 += data;
ret = measure_current(info, &data); if (ret) goto out_meas;
staticint pm860x_batt_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
{ struct pm860x_battery_info *info = dev_get_drvdata(psy->dev.parent); int data; int ret;
switch (psp) { case POWER_SUPPLY_PROP_PRESENT:
val->intval = info->present; break; case POWER_SUPPLY_PROP_CAPACITY:
ret = calc_capacity(info, &data); if (ret) return ret; if (data < 0)
data = 0; elseif (data > 100)
data = 100; /* return 100 if battery is not attached */ if (!info->present)
data = 100;
val->intval = data; break; case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LION; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: /* return real vbatt Voltage */
ret = measure_vbatt(info, OCV_MODE_ACTIVE, &data); if (ret) return ret;
val->intval = data * 1000; break; case POWER_SUPPLY_PROP_VOLTAGE_AVG: /* return Open Circuit Voltage (not measured voltage) */
ret = calc_ocv(info, &data); if (ret) return ret;
val->intval = data * 1000; break; case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = measure_current(info, &data); if (ret) return ret;
val->intval = data; break; case POWER_SUPPLY_PROP_TEMP: if (info->present) {
ret = measure_temp(info, &data); if (ret) return ret;
data *= 10;
} else { /* Fake Temp 25C Without Battery */
data = 250;
}
val->intval = data; break; default: return -ENODEV;
} return0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.