int charge_keep_power_off(void)
{
	int charge;

	if (BATTERY_AP_OFF_LEVEL == 0)
		return 0;

	if (battery_remaining_capacity(&charge))
		return current_state != ST_CHARGING_ERROR;

	return charge <= BATTERY_AP_OFF_LEVEL;
}
Esempio n. 2
0
int charge_keep_power_off(void)
{
	int charge;

	if (BATTERY_AP_OFF_LEVEL == 0)
		return 0;

	if (battery_remaining_capacity(&charge))
		return charge_get_state() != PWR_STATE_ERROR;

	return charge <= BATTERY_AP_OFF_LEVEL;
}
Esempio n. 3
0
/**
 * 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;
}