static int s3c_bat_get_charging_status(void) { charger_type_t charger = CHARGER_BATTERY; int ret = 0; charger = s3c_bat_info.bat_info.charging_source; switch (charger) { case CHARGER_BATTERY: ret = POWER_SUPPLY_STATUS_NOT_CHARGING; break; case CHARGER_USB: case CHARGER_AC: if (s3c_get_bat_health() != POWER_SUPPLY_HEALTH_GOOD) ret = POWER_SUPPLY_STATUS_DISCHARGING; else { if (s3c_bat_info.bat_info.batt_is_full) ret = POWER_SUPPLY_STATUS_FULL; else ret = POWER_SUPPLY_STATUS_CHARGING; } break; case CHARGER_DISCHARGE: ret = POWER_SUPPLY_STATUS_DISCHARGING; break; default: ret = POWER_SUPPLY_STATUS_UNKNOWN; } dev_dbg(dev, "%s: %s\n", __func__, status_text[ret]); return ret; }
static int s3c_bat_get_property(struct power_supply *bat_ps, enum power_supply_property psp, union power_supply_propval *val) { dev_dbg(bat_ps->dev, "%s : psp = %d\n", __func__, psp); switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = s3c_bat_get_charging_status(); break; case POWER_SUPPLY_PROP_HEALTH: val->intval = s3c_get_bat_health(); break; case POWER_SUPPLY_PROP_PRESENT: val->intval = s3c_bat_info.present; break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; break; case POWER_SUPPLY_PROP_CAPACITY: val->intval = s3c_bat_info.bat_info.level; dev_dbg(dev, "%s : level = %d\n", __func__, val->intval); break; case POWER_SUPPLY_PROP_TEMP: val->intval = s3c_bat_info.bat_info.batt_temp; dev_dbg(bat_ps->dev, "%s : temp = %d\n", __func__, val->intval); break; default: return -EINVAL; } return 0; }
static irqreturn_t s3c_cable_charging_isr(int irq, void *power_supply) { int chg_ing = gpio_get_value(gpio_chg_ing); dev_dbg(dev, "%s: irq=0x%x, gpio_chg_ing=%d\n", __func__, irq, chg_ing); if (!s3c_battery_initial) return IRQ_HANDLED; #ifndef __DISABLE_CHG_ING_INTR__ if (chg_ing && !gpio_get_value(gpio_ta_connected) && s3c_bat_info.bat_info.charging_enabled && s3c_get_bat_health() == POWER_SUPPLY_HEALTH_GOOD) { s3c_set_chg_en(DISABLE); s3c_bat_info.bat_info.batt_is_full = 1; force_update = 1; full_charge_flag = 1; } schedule_work(&bat_work); /* * Wait a bit before reading ac/usb line status and setting charger, * because ac/usb status readings may lag from irq. */ if (s3c_bat_info.polling) mod_timer(&polling_timer, jiffies + msecs_to_jiffies(s3c_bat_info.polling_interval)); #endif /* __DISABLE_CHG_ING_INTR__ */ return IRQ_HANDLED; }
static void s3c_cable_check_status(void) { charger_type_t ostatus=b_status; mutex_lock(&work_lock); if (!gpio_get_value(gpio_ta_connected)) { if (get_usb_power_state()) b_status = CHARGER_USB; else b_status = CHARGER_AC; if (s3c_get_bat_health() != POWER_SUPPLY_HEALTH_GOOD) { dev_info(dev, "%s: Unhealth battery state!\n", __func__); s3c_set_chg_en(DISABLE); } else s3c_set_chg_en(ENABLE); dev_dbg(dev, "%s: status : %s\n", __func__, (b_status == CHARGER_USB) ? "USB" : "AC"); } else { u32 health = s3c_get_bat_health(); b_status = CHARGER_BATTERY; s3c_set_chg_en(DISABLE); if (health == POWER_SUPPLY_HEALTH_OVERHEAT || health == POWER_SUPPLY_HEALTH_COLD) { s3c_set_bat_health(POWER_SUPPLY_HEALTH_GOOD); } } dev_dbg(dev, "%s: gpio_chg_en %s\n", __func__, gpio_get_value_ex(gpio_chg_en)?"disabled":"enabled"); if (ostatus!=b_status) s3c_cable_status_update(b_status); mutex_unlock(&work_lock); }
static unsigned int s3c_bat_check_v_f(void) { unsigned int rc = 0; int adc = 0; adc = s3c_bat_get_adc_data(S3C_ADC_V_F); dev_info(dev, "%s: V_F ADC = %d\n", __func__, adc); if (adc <= BATT_VF_MAX && adc >= BATT_VF_MIN) { if (s3c_get_bat_health() == POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) { s3c_set_bat_health(POWER_SUPPLY_HEALTH_GOOD); s3c_set_chg_en(ENABLE); b_status=0; } rc = 1; } else { dev_info(dev, "%s: Unauthorized battery!\n", __func__); s3c_set_bat_health(POWER_SUPPLY_HEALTH_UNSPEC_FAILURE); rc = 0; } return rc; }
static void check_recharging_bat(int fg_vcell) { static int cnt = 0; if (s3c_get_bat_health() != POWER_SUPPLY_HEALTH_GOOD) { cnt = 0; return; } if (s3c_bat_info.bat_info.batt_is_full && !s3c_bat_info.bat_info.charging_enabled && (fg_vcell <= RECHARGE_COND_VOLTAGE || fg_vcell <= FULL_CHARGE_COND_VOLTAGE)) { if (++cnt >= 10) { dev_info(dev, "%s: recharging(vcell:%d)\n", __func__, fg_vcell); s3c_bat_info.bat_info.batt_is_recharging = 1; s3c_set_chg_en(ENABLE); cnt = 0; } } else { cnt = 0; } }
static int s3c_get_bat_temp(struct power_supply *bat_ps) { int temp = 0; int array_size = 0; int i = 0; int temp_adc = s3c_read_temp(bat_ps); int health = s3c_get_bat_health(); #ifdef __TEST_MODE_INTERFACE__ s3c_bat_info.bat_info.batt_temp_adc_aver = temp_adc; #endif /* __TEST_MODE_INTERFACE__ */ #ifndef __REVERSE_TEMPER_ADC__ if (temp_adc <= TEMP_HIGH_BLOCK) { if (health != POWER_SUPPLY_HEALTH_OVERHEAT && health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) s3c_temp_control(POWER_SUPPLY_HEALTH_OVERHEAT); } else if (temp_adc >= TEMP_HIGH_RECOVER && temp_adc <= TEMP_LOW_RECOVER) { if (health == POWER_SUPPLY_HEALTH_OVERHEAT || health == POWER_SUPPLY_HEALTH_COLD) s3c_temp_control(POWER_SUPPLY_HEALTH_GOOD); } else if (temp_adc >= TEMP_LOW_BLOCK) { if (health != POWER_SUPPLY_HEALTH_COLD && health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) s3c_temp_control(POWER_SUPPLY_HEALTH_COLD); } array_size = ARRAY_SIZE(temper_table); for (i = 0; i < (array_size - 1); i++) { if (i == 0) { if (temp_adc >= temper_table[0][0]) { temp = temper_table[0][1]; break; } else if (temp_adc <= temper_table[array_size-1][0]) { temp = temper_table[array_size-1][1]; break; } } if (temper_table[i][0] > temp_adc && temper_table[i+1][0] <= temp_adc) { temp = temper_table[i+1][1]; } } #else /* __REVERSE_TEMPER_ADC__ */ if (temp_adc >= TEMP_HIGH_BLOCK) { if (health != POWER_SUPPLY_HEALTH_OVERHEAT && health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) s3c_temp_control(POWER_SUPPLY_HEALTH_OVERHEAT); } else if (temp_adc <= TEMP_HIGH_RECOVER && temp_adc >= TEMP_LOW_RECOVER) { if (health == POWER_SUPPLY_HEALTH_OVERHEAT || health == POWER_SUPPLY_HEALTH_COLD) s3c_temp_control(POWER_SUPPLY_HEALTH_GOOD); } else if (temp_adc <= TEMP_LOW_BLOCK) { if (health != POWER_SUPPLY_HEALTH_COLD && health != POWER_SUPPLY_HEALTH_UNSPEC_FAILURE) s3c_temp_control(POWER_SUPPLY_HEALTH_COLD); } array_size = ARRAY_SIZE(temper_table); for (i = 0; i < (array_size - 1); i++) { if (i == 0) { if (temp_adc <= temper_table[0][0]) { temp = temper_table[0][1]; break; } else if (temp_adc >= temper_table[array_size-1][0]) { temp = temper_table[array_size-1][1]; break; } } if (temper_table[i][0] < temp_adc && temper_table[i+1][0] >= temp_adc) { temp = temper_table[i+1][1]; } } #endif /* __REVERSE_TEMPER_ADC__ */ dev_dbg(dev, "%s: temp = %d, adc = %d\n", __func__, temp, temp_adc); #ifdef __TEST_MODE_INTERFACE__ s3c_bat_info.bat_info.batt_temp_aver = temp; #endif /* __TEST_MODE_INTERFACE__ */ return temp; }