static void rk29_adc_battery_lowpower_check(struct rk29_adc_battery_data *bat) { int i; int level, oldlevel; struct rk29_adc_battery_platform_data *pdata = bat->pdata; printk("%s--%d:\n", __FUNCTION__, __LINE__); old_charge_level = -1; pSamples = bat->adc_samples; adc_sync_read(bat->client); //start adc sample level = oldlevel = rk29_adc_battery_status_samples(bat); //init charge status /* Fill sample buffer with values */ bat->full_times = 0; for (i = 0; i < NUM_VOLTAGE_SAMPLE; i++) //0.3 s { mdelay(1); rk29_adc_battery_voltage_samples(bat); //get voltage //level = rk29_adc_battery_status_samples(bat); //check charge status level = rk29_adc_battery_get_charge_level(bat); if (oldlevel != level) { oldlevel = level; //if charge status changed, reset sample i = 0; } } bat->bat_capacity = rk29_adc_battery_voltage_to_capacity(bat, bat->bat_voltageAvg); bat->bat_status = POWER_SUPPLY_STATUS_NOT_CHARGING; if (rk29_adc_battery_get_charge_level(bat)) { bat->bat_status = POWER_SUPPLY_STATUS_CHARGING; if (pdata->charge_ok_pin != INVALID_GPIO) { if (gpio_get_value(pdata->charge_ok_pin) == pdata->charge_ok_level) { bat->bat_status = POWER_SUPPLY_STATUS_FULL; bat->bat_capacity = 100; } } } #if 0 rk29_adc_battery_poweron_capacity_check(); #else poweron_check = 1; #endif /* Immediate power off for battery protection */ if (bat->bat_voltageAvg <= (pdata->adc_bat_levels[BATT_ZERO_VOL_IDX] + 50)) { printk("%umV -> low battery: powerdown (%u)\n", bat->bat_voltageAvg, pdata->adc_bat_levels[BATT_ZERO_VOL_IDX]+50); system_state = SYSTEM_POWER_OFF; pm_power_off(); } }
static int rk29_adc_battery_get_ac_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { int ret = 0; charger_type_t charger; charger = CHARGER_USB; switch (psp) { case POWER_SUPPLY_PROP_ONLINE: if (psy->type == POWER_SUPPLY_TYPE_MAINS) { if (rk29_adc_battery_get_charge_level(gBatteryData)) { val->intval = 1; } else { val->intval = 0; } } DBG("%s:%d\n",__FUNCTION__,val->intval); break; default: ret = -EINVAL; break; } return ret; }
static void rk29_adc_battery_capacity_samples(struct rk29_adc_battery_data *bat) { int capacity = 0; /* First collect minimum number of samples needed for * calculation of mean value */ if (bat->bat_status_cnt < NUM_VOLTAGE_SAMPLE) { gBatCapacityDisChargeCnt = 0; gBatCapacityChargeCnt = 0; return; } /* calculate capacity currently available in battery. */ capacity = rk29_adc_battery_voltage_to_capacity(bat, bat->bat_voltageAvg); if (rk29_adc_battery_get_charge_level(bat)) { /* This is executed if the battery is charging... */ rk29_adc_bat_capacity_charge(bat, capacity); } else { /* Battery is discharging */ rk29_adc_bat_capacity_discharge(bat, capacity); } /* save current capacity for comparisions in next run */ capacitytmp = capacity; }
static int rk29_adc_battery_voltage_to_capacity(struct rk29_adc_battery_data *bat, int BatVoltage) { int i = 0; int capacity = 0; struct batt_vol_cal *p; p = batt_table; if (rk29_adc_battery_get_charge_level(bat)){ //charge if(BatVoltage >= (p[BATT_NUM - 1].charge_vol)){ capacity = 100; } else{ if(BatVoltage <= (p[0].charge_vol)){ capacity = 0; } else{ for(i = 0; i < BATT_NUM - 1; i++){ if(((p[i].charge_vol) <= BatVoltage) && (BatVoltage < (p[i+1].charge_vol))){ capacity = i * 10 + ((BatVoltage - p[i].charge_vol) * 10) / (p[i+1].charge_vol- p[i].charge_vol); break; } } } } } else{ //discharge if(BatVoltage >= (p[BATT_NUM - 1].dis_charge_vol)){ capacity = 100; } else{ if(BatVoltage <= (p[0].dis_charge_vol)){ capacity = 0; } else{ for(i = 0; i < BATT_NUM - 1; i++){ if(((p[i].dis_charge_vol) <= BatVoltage) && (BatVoltage < (p[i+1].dis_charge_vol))){ capacity = i * 10 + ((BatVoltage - p[i].dis_charge_vol) * 10) / (p[i+1].dis_charge_vol- p[i].dis_charge_vol); ; break; } } } } } return capacity; }
/* Get capacity from voltage value. * This function uses the adc_raw_table_bat[] table to retreive * the capacity in 0..100% from the current battery voltage mV value. * * \param *bat pointer to battery struct. * \param BatWoltage Battery voltage in mV. * \return capacity in 0..100% */ static int rk29_adc_battery_voltage_to_capacity( struct rk29_adc_battery_data *bat, int BatVoltage) { struct rk29_adc_battery_platform_data *pdata = bat->pdata; int i = 0; int capacity = 0; int *p = pdata->adc_raw_table_bat; DBG("Bat=%u ", BatVoltage); /* discharge table is preset, check if we're charging */ if (rk29_adc_battery_get_charge_level(bat)) { DBG("AC "); p = pdata->adc_raw_table_ac; } if (BatVoltage >= p[BAT_ADC_TABLE_LEN - 1]) { /* if more or equal than last table entry: 100% */ DBG("F100%%\n"); capacity = 100; goto out; } if (BatVoltage <= p[0]) { /* if less than first table entry: 0% */ DBG("F0%%\n"); capacity = 0; goto out; } /* calculate average between to table entries for 1% steps. */ for (i = 0; i < BAT_ADC_TABLE_LEN - 1; i++) { if ((p[i] <= BatVoltage) && (BatVoltage < p[i + 1])) { capacity = i * 10 + ((BatVoltage - p[i]) * 10) / (p[i + 1] - p[i]); break; } } DBG("i=%u %u %u %u\n", i, p[i], p[i+1], capacity); out: return capacity; }
static void rk29_adc_battery_voltage_samples(struct rk29_adc_battery_data *bat) { int value; int i,*pStart = bat->adc_samples, num = 0; int level = rk29_adc_battery_get_charge_level(bat); value = bat->adc_val; adc_async_read(bat->client); *pSamples++ = adc_to_voltage(value); bat->bat_status_cnt++; if (bat->bat_status_cnt > NUM_VOLTAGE_SAMPLE) bat->bat_status_cnt = NUM_VOLTAGE_SAMPLE + 1; num = pSamples - pStart; if (num >= NUM_VOLTAGE_SAMPLE){ pSamples = pStart; num = NUM_VOLTAGE_SAMPLE; } value = 0; for (i = 0; i < num; i++){ value += bat->adc_samples[i]; } bat->bat_voltage = value / num; /*消除毛刺电压*/ if(1 == level){ if(bat->bat_voltage >= batt_table[BATT_NUM-1].charge_vol+ 10) bat->bat_voltage = batt_table[BATT_NUM-1].charge_vol + 10; else if(bat->bat_voltage <= batt_table[0].charge_vol - 10) bat->bat_voltage = batt_table[0].charge_vol - 10; } else{ if(bat->bat_voltage >= batt_table[BATT_NUM-1].dis_charge_vol+ 10) bat->bat_voltage = batt_table[BATT_NUM-1].dis_charge_vol + 10; else if(bat->bat_voltage <= batt_table[0].dis_charge_vol - 10) bat->bat_voltage = batt_table[0].dis_charge_vol - 10; } }
static int rk29_adc_battery_voltage_to_capacity(struct rk29_adc_battery_data *bat, int BatVoltage) { int i = 0; int capacity = 0; int *p = adc_raw_table_bat; if (rk29_adc_battery_get_charge_level(bat)) { p = adc_raw_table_ac; } if(BatVoltage >= p[BAT_ADC_TABLE_LEN - 1]) { //当电压超过最大值 capacity = 100; } else if(BatVoltage <= p[0]) { //当电压低于最小值 capacity = 0; } else { //计算容量 for(i = 0; i < BAT_ADC_TABLE_LEN - 1; i++) { if((p[i] <= BatVoltage) && (BatVoltage < p[i+1])) { capacity = i * 10 + ((BatVoltage - p[i]) * 10) / (p[i+1] - p[i]); break; } } } return capacity; }
static int rk29_adc_battery_status_samples(struct rk29_adc_battery_data *bat) { int charge_level; struct rk29_adc_battery_platform_data *pdata = bat->pdata; /* Read supply input state */ charge_level = rk29_adc_battery_get_charge_level(bat); /* If changed, control charger logic adequately */ if (charge_level != old_charge_level) { old_charge_level = charge_level; bat->bat_change = 1; if (charge_level) { rk29_adc_battery_charge_enable(bat); } else { rk29_adc_battery_charge_disable(bat); } /* Debounce change detection */ bat->bat_status_cnt = 0; } if (charge_level == 0) { /* Not charging */ bat->full_times = 0; bat->bat_status = POWER_SUPPLY_STATUS_NOT_CHARGING; goto out; } /* If there is no charge-full hardware pin... */ if (pdata->charge_ok_pin == INVALID_GPIO) { /* simulate charge full detection by capacity */ if (bat->bat_capacity == 100) { if (bat->bat_status != POWER_SUPPLY_STATUS_FULL) { bat->bat_status = POWER_SUPPLY_STATUS_FULL; bat->bat_change = 1; } } else { bat->bat_status = POWER_SUPPLY_STATUS_CHARGING; } goto out; } /* Read GPIO stating fully-charged */ if (gpio_get_value(pdata->charge_ok_pin) != pdata->charge_ok_level) { /* Hardware logic still charging */ bat->full_times = 0; bat->bat_status = POWER_SUPPLY_STATUS_CHARGING; } else { /* Hardware finished charging. */ if (bat->full_times < NUM_CHARGE_FULL_DELAY_TIMES) { bat->full_times++; } if ((bat->full_times >= NUM_CHARGE_FULL_DELAY_TIMES) && (bat->bat_status != POWER_SUPPLY_STATUS_FULL)) { bat->bat_status = POWER_SUPPLY_STATUS_FULL; bat->bat_capacity = 100; bat->bat_change = 1; } } out: return charge_level; }
//static int rk29_adc_battery_get_capacity_ext(int BatVoltage) static void rk29_adc_battery_capacity_samples(struct rk29_adc_battery_data *bat) { int capacity = 0; struct rk29_adc_battery_platform_data *pdata = bat->pdata; //充放电状态变化后,Buffer填满之前,不更新 if (bat->bat_status_cnt < NUM_VOLTAGE_SAMPLE) { gBatCapacityDisChargeCnt = 0; gBatCapacityChargeCnt = 0; return; } capacity = rk29_adc_battery_voltage_to_capacity(bat, bat->bat_voltage); if (rk29_adc_battery_get_charge_level(bat)) { if (capacity > bat->bat_capacity) { //实际采样到的电压比显示的电压大,逐级上升 if (++gBatCapacityDisChargeCnt >= NUM_CHARGE_MIN_SAMPLE) { gBatCapacityDisChargeCnt = 0; if (bat->bat_capacity < 99) { bat->bat_capacity++; bat->bat_change = 1; } } gBatCapacityChargeCnt = 0; } else { gBatCapacityDisChargeCnt = 0; gBatCapacityChargeCnt++; if (pdata->charge_ok_pin != INVALID_GPIO) { if (gpio_get_value(pdata->charge_ok_pin) == pdata->charge_ok_level) { //检测到电池充满标志,同时长时间内充电电压无变化,开始启动计时充电,快速上升容量 if (gBatCapacityChargeCnt >= NUM_CHARGE_MIN_SAMPLE) { gBatCapacityChargeCnt = 0; if (bat->bat_capacity < 99) { bat->bat_capacity++; bat->bat_change = 1; } } } else { if (capacity > capacitytmp) { //过程中如果电压有增长,定时器复位,防止定时器模拟充电比实际充电快 gBatCapacityChargeCnt = 0; } if (/*(bat->bat_capacity >= 80) && */(gBatCapacityChargeCnt > NUM_CHARGE_MAX_SAMPLE)) { gBatCapacityChargeCnt = (NUM_CHARGE_MAX_SAMPLE - NUM_CHARGE_MID_SAMPLE); if (bat->bat_capacity < 99) { bat->bat_capacity++; bat->bat_change = 1; } } } } else { //没有充电满检测脚,长时间内电压无变化,定时器模拟充电 if (capacity > capacitytmp) { //过程中如果电压有增长,定时器复位,防止定时器模拟充电比实际充电快 gBatCapacityChargeCnt = 0; } if (gBatCapacityChargeCnt > NUM_CHARGE_MAX_SAMPLE) { gBatCapacityChargeCnt = (NUM_CHARGE_MAX_SAMPLE - NUM_CHARGE_MID_SAMPLE); if (bat->bat_capacity < 100) { bat->bat_capacity++; bat->bat_change = 1; } } } } } else { //放电时,只允许电压下降 if (capacity < bat->bat_capacity) { if (++gBatCapacityDisChargeCnt >= NUM_DISCHARGE_MIN_SAMPLE) { gBatCapacityDisChargeCnt = 0; if (bat->bat_capacity > 0) { bat->bat_capacity-- ; bat->bat_change = 1; } } } else { gBatCapacityDisChargeCnt = 0; } gBatCapacityChargeCnt = 0; } capacitytmp = capacity; }
static int rk29_adc_battery_status_samples(struct rk29_adc_battery_data *bat) { int charge_level; struct rk29_adc_battery_platform_data *pdata = bat->pdata; charge_level = rk29_adc_battery_get_charge_level(bat); //检测充电状态变化情况 if (charge_level != old_charge_level) { old_charge_level = charge_level; bat->bat_change = 1; if(charge_level) { rk29_adc_battery_charge_enable(bat); } else { rk29_adc_battery_charge_disable(bat); } bat->bat_status_cnt = 0; //状态变化开始计数 } //获取稳定的充电状态 if(charge_level == 0) { //未充电 bat->full_times = 0; bat->bat_status = POWER_SUPPLY_STATUS_NOT_CHARGING; } else { //充电 if (pdata->charge_ok_pin == INVALID_GPIO) { //没有charge_ok_pin,检测容量 if (bat->bat_capacity == 100) { if (bat->bat_status != POWER_SUPPLY_STATUS_FULL) { bat->bat_status = POWER_SUPPLY_STATUS_FULL; bat->bat_change = 1; } } else { bat->bat_status = POWER_SUPPLY_STATUS_CHARGING; } } else { //有充电检测教 if (gpio_get_value(pdata->charge_ok_pin) != pdata->charge_ok_level) { //没有检测到充电满电平标志 bat->full_times = 0; bat->bat_status = POWER_SUPPLY_STATUS_CHARGING; } else { //检测到充电满电平标志 bat->full_times++; if (bat->full_times >= NUM_CHARGE_FULL_DELAY_TIMES) { bat->full_times = NUM_CHARGE_FULL_DELAY_TIMES + 1; } if ((bat->full_times >= NUM_CHARGE_FULL_DELAY_TIMES) && (bat->bat_capacity >= 99)) { if (bat->bat_status != POWER_SUPPLY_STATUS_FULL) { bat->bat_status = POWER_SUPPLY_STATUS_FULL; bat->bat_capacity = 100; bat->bat_change = 1; } } else { bat->bat_status = POWER_SUPPLY_STATUS_CHARGING; } } } } return charge_level; }