enum battery_disconnect_state battery_get_disconnect_state(void) { uint8_t data[6]; int rv; /* * Take note if we find that the battery isn't in disconnect state, * and always return NOT_DISCONNECTED without probing the battery. * This assumes the battery will not go to disconnect state during * runtime. */ static int not_disconnected; if (not_disconnected) return BATTERY_NOT_DISCONNECTED; if (extpower_is_present()) { /* Check if battery charging + discharging is disabled. */ rv = sb_write(SB_MANUFACTURER_ACCESS, PARAM_OPERATION_STATUS); if (rv) return BATTERY_DISCONNECT_ERROR; rv = sb_read_string(I2C_PORT_BATTERY, BATTERY_ADDR, SB_ALT_MANUFACTURER_ACCESS, data, 6); if (rv || (~data[3] & (BATTERY_DISCHARGING_DISABLED | BATTERY_CHARGING_DISABLED))) { not_disconnected = 1; return BATTERY_NOT_DISCONNECTED; } /* * Battery is neither charging nor discharging. Verify that * we didn't enter this state due to a safety fault. */ rv = sb_write(SB_MANUFACTURER_ACCESS, PARAM_SAFETY_STATUS); if (rv) return BATTERY_DISCONNECT_ERROR; rv = sb_read_string(I2C_PORT_BATTERY, BATTERY_ADDR, SB_ALT_MANUFACTURER_ACCESS, data, 6); if (rv || data[2] || data[3] || data[4] || data[5]) return BATTERY_DISCONNECT_ERROR; /* * Battery is present and also the status is initialized and * no safety fault, battery is disconnected. */ if (battery_is_present() == BP_YES) return BATTERY_DISCONNECTED; } not_disconnected = 1; return BATTERY_NOT_DISCONNECTED; }
//Get the specified battery's current charge in percent. int get_battery_percentage(unsigned int battery_index) { unsigned int percentage; struct battery_status * status; struct battery_info * info; unsigned long capacity; if (battery_index >= num_battery_structs_allocd) return 0; if (battery_is_present(battery_index) == NO) return 0; status = &last_status[battery_index]; info = &last_info[battery_index]; //If last_full_capacity isn't available, use design_capacity. if (info->last_full_capacity != 0) { capacity = info->last_full_capacity; } else { capacity = info->design_capacity; } //Avoid dividing by zero if (capacity == 0) { percentage = 0; } else { percentage = status->remaining_capacity * 100 / capacity; } //Don't report greater than 100% charge. if (percentage > 100) { percentage = 100; } return (int)percentage; }
void battery_read_status(nyx_battery_status_t *state) { if (state) { memset(state,0,sizeof(nyx_battery_status_t)); state->present = battery_is_present(); if (state->present) { state->percentage = battery_percent(); state->temperature = battery_temperature(); state->current = battery_current(); state->voltage = battery_voltage(); state->avg_current = battery_current(); state->capacity = battery_coulomb(); state->capacity_raw = battery_rawcoulomb(); state->capacity_full40 = battery_full40(); state->age=battery_age(); if (state->avg_current > 0) state->charging = true; } else state->charging = false; } }
/** * In certain cases we need to override the default behavior of not charging * from non-dedicated chargers. If the system is in RO and locked, we have no * way of determining the actual dualrole capability of the charger because * PD communication is not allowed, so we must assume that it is dedicated. * Also, if no battery is present, the charger may be our only source of power, * so again we must assume that the charger is dedicated. */ static int charge_manager_spoof_dualrole_capability(void) { return (system_get_image_copy() == SYSTEM_IMAGE_RO && system_is_locked()) || (battery_is_present() != BP_YES); }
/** * Common handler for charging states. * * This handler gets battery charging parameters, charger state, ac state, and * timestamp. It also fills memory map and issues power events on state change. */ static int state_common(struct charge_state_context *ctx) { int rv, d; struct charge_state_data *curr = &ctx->curr; struct charge_state_data *prev = &ctx->prev; struct batt_params *batt = &ctx->curr.batt; uint8_t *batt_flags = ctx->memmap_batt_flags; /* Copy previous state and init new state */ ctx->prev = ctx->curr; curr->ts = get_time(); curr->error = 0; /* Detect AC change */ curr->ac = charge_get_flags() & CHARGE_FLAG_EXTERNAL_POWER; if (curr->ac != prev->ac) { if (curr->ac) { /* AC on * Initialize charger to power on reset mode */ rv = charger_post_init(); if (rv) curr->error |= F_CHARGER_INIT; } } if (curr->ac) { *batt_flags |= EC_BATT_FLAG_AC_PRESENT; if (charger_get_voltage(&curr->charging_voltage)) { charge_request(0, 0); curr->error |= F_CHARGER_VOLTAGE; } if (charger_get_current(&curr->charging_current)) { charge_request(0, 0); curr->error |= F_CHARGER_CURRENT; } #ifdef CONFIG_CHARGER_EN_GPIO if (!charge_get_charger_en_gpio()) { curr->charging_voltage = 0; curr->charging_current = 0; } #endif } else { *batt_flags &= ~EC_BATT_FLAG_AC_PRESENT; /* AC disconnected should get us out of force idle mode. */ state_machine_force_idle = 0; } #if defined(CONFIG_BATTERY_PRESENT_CUSTOM) || \ defined(CONFIG_BATTERY_PRESENT_GPIO) if (battery_is_present() == BP_NO) { curr->error |= F_BATTERY_NOT_CONNECTED; return curr->error; } #endif /* Read params and see if battery is responsive */ battery_get_params(batt); if (!(batt->flags & BATT_FLAG_RESPONSIVE)) { /* Check low battery condition and retry */ if (curr->ac && ctx->battery_responsive && !(curr->error & F_CHARGER_MASK)) { ctx->battery_responsive = 0; /* * Try to revive ultra low voltage pack. Charge * battery pack with minimum current and maximum * voltage for 30 seconds. */ charge_request(ctx->battery->voltage_max, ctx->battery->precharge_current); for (d = 0; d < PRECHARGE_TIMEOUT; d++) { sleep(1); battery_get_params(batt); if (batt->flags & BATT_FLAG_RESPONSIVE) { ctx->battery_responsive = 1; break; } } } /* Set error if battery is still unresponsive */ if (!(batt->flags & BATT_FLAG_RESPONSIVE)) { curr->error |= F_BATTERY_UNRESPONSIVE; return curr->error; } } else { ctx->battery_responsive = 1; } /* Translate flags */ if (batt->flags & BATT_FLAG_BAD_ANY) curr->error |= F_BATTERY_GET_PARAMS; if (batt->flags & BATT_FLAG_BAD_VOLTAGE) curr->error |= F_BATTERY_VOLTAGE; if (batt->flags & BATT_FLAG_BAD_STATE_OF_CHARGE) curr->error |= F_BATTERY_STATE_OF_CHARGE; *ctx->memmap_batt_volt = batt->voltage; /* Memory mapped value: discharge rate */ *ctx->memmap_batt_rate = batt->current < 0 ? -batt->current : batt->current; /* Fake state of charge if necessary */ if (fake_state_of_charge >= 0) { batt->state_of_charge = fake_state_of_charge; curr->error &= ~F_BATTERY_STATE_OF_CHARGE; } if (batt->state_of_charge != prev->batt.state_of_charge) { rv = battery_full_charge_capacity(&d); if (!rv && d != *(int *)host_get_memmap(EC_MEMMAP_BATT_LFCC)) { *(int *)host_get_memmap(EC_MEMMAP_BATT_LFCC) = d; /* Notify host to re-read battery information */ host_set_single_event(EC_HOST_EVENT_BATTERY); } } /* Prevent deep discharging */ if (!curr->ac) { if ((batt->state_of_charge < BATTERY_LEVEL_SHUTDOWN && !(curr->error & F_BATTERY_STATE_OF_CHARGE)) || (batt->voltage <= ctx->battery->voltage_min && !(curr->error & F_BATTERY_VOLTAGE))) low_battery_shutdown(ctx); } /* Check battery presence */ if (curr->error & F_BATTERY_MASK) { *ctx->memmap_batt_flags &= ~EC_BATT_FLAG_BATT_PRESENT; return curr->error; } *ctx->memmap_batt_flags |= EC_BATT_FLAG_BATT_PRESENT; /* Battery charge level low */ if (batt->state_of_charge <= BATTERY_LEVEL_LOW && prev->batt.state_of_charge > BATTERY_LEVEL_LOW) host_set_single_event(EC_HOST_EVENT_BATTERY_LOW); /* Battery charge level critical */ if (batt->state_of_charge <= BATTERY_LEVEL_CRITICAL) { *ctx->memmap_batt_flags |= EC_BATT_FLAG_LEVEL_CRITICAL; /* Send battery critical host event */ if (prev->batt.state_of_charge > BATTERY_LEVEL_CRITICAL) host_set_single_event(EC_HOST_EVENT_BATTERY_CRITICAL); } else { *ctx->memmap_batt_flags &= ~EC_BATT_FLAG_LEVEL_CRITICAL; } #ifdef CONFIG_BATTERY_OVERRIDE_PARAMS /* Apply battery pack vendor charging method */ battery_override_params(batt); #endif #ifdef CONFIG_CHARGER_CURRENT_LIMIT if (batt->desired_current > CONFIG_CHARGER_CURRENT_LIMIT) batt->desired_current = CONFIG_CHARGER_CURRENT_LIMIT; #endif if (batt->desired_current > user_current_limit) batt->desired_current = user_current_limit; if (fake_state_of_charge >= 0) *ctx->memmap_batt_cap = fake_state_of_charge * *(int *)host_get_memmap(EC_MEMMAP_BATT_LFCC) / 100; else if (battery_remaining_capacity(&d)) ctx->curr.error |= F_BATTERY_CAPACITY; else *ctx->memmap_batt_cap = d; return ctx->curr.error; }