Exemplo n.º 1
0
static void glados_led_set_battery(void)
{
	static int battery_ticks;
	uint32_t chflags = charge_get_flags();

	battery_ticks++;

	/* BAT LED behavior:
	 * Same as the chromeos spec
	 * Green/Amber for CHARGE_FLAG_FORCE_IDLE
	 */
	switch (charge_get_state()) {
	case PWR_STATE_CHARGE:
		glados_led_set_color_battery(LED_AMBER);
		break;
	case PWR_STATE_DISCHARGE:
		/* Less than 3%, blink one second every two second */
		if (charge_get_percent() < CRITICAL_LOW_BATTERY_PERCENTAGE)
			glados_led_set_color_battery(
				(battery_ticks % LED_TOTAL_2SECS_TICKS <
				 LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF);
		/* Less than 10%, blink one second every four seconds */
		else if (charge_get_percent() < LOW_BATTERY_PERCENTAGE)
			glados_led_set_color_battery(
				(battery_ticks % LED_TOTAL_4SECS_TICKS <
				 LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF);
		else
			glados_led_set_color_battery(LED_OFF);
		break;
	case PWR_STATE_ERROR:
		glados_led_set_color_battery(
			(battery_ticks % LED_TOTAL_2SECS_TICKS <
			 LED_ON_1SEC_TICKS) ? LED_RED : LED_OFF);
		break;
	case PWR_STATE_CHARGE_NEAR_FULL:
		glados_led_set_color_battery(LED_GREEN);
		break;
	case PWR_STATE_IDLE: /* External power connected in IDLE */
		if (chflags & CHARGE_FLAG_FORCE_IDLE)
			glados_led_set_color_battery(
				(battery_ticks % LED_TOTAL_4SECS_TICKS <
				 LED_ON_2SECS_TICKS) ? LED_GREEN : LED_AMBER);
		else
			glados_led_set_color_battery(LED_GREEN);
		break;
	default:
		/* Other states don't alter LED behavior */
		break;
	}
}
Exemplo n.º 2
0
static void big_led_set_battery(void)
{
	static int battery_second;
	uint32_t chflags = charge_get_flags();

	battery_second++;

	/* BAT LED behavior:
	 * Fully charged / idle: Blue
	 * Force idle (for factory): 2 secs of blue, 2 secs of yellow
	 * Under charging: Orange
	 * Battery low (10%): Orange in breeze mode (1 sec on, 3 sec off)
	 * Battery critical low (less than 3%) or abnormal battery
	 *     situation: Orange in blinking mode (1 sec on, 1 sec off)
	 * Using battery or not connected to AC power: OFF
	 */
	switch (charge_get_state()) {
	case PWR_STATE_CHARGE:
		bat_led_set_color(LED_ORANGE);
		break;
	case PWR_STATE_DISCHARGE:
		if (charge_get_percent() < 3)
			bat_led_set_color((battery_second & 1)
					? LED_OFF : LED_ORANGE);
		else if (charge_get_percent() < 10)
			bat_led_set_color((battery_second & 3)
					? LED_OFF : LED_ORANGE);
		else
			bat_led_set_color(LED_OFF);
		break;
	case PWR_STATE_ERROR:
		bat_led_set_color((battery_second & 1) ? LED_OFF : LED_ORANGE);
		break;
	case PWR_STATE_CHARGE_NEAR_FULL:
		bat_led_set_color(LED_BLUE);
		break;
	case PWR_STATE_IDLE: /* External power connected in IDLE. */
		if (chflags & CHARGE_FLAG_FORCE_IDLE)
			bat_led_set_color(
				(battery_second & 0x2) ? LED_BLUE : LED_ORANGE);
		else
			bat_led_set_color(LED_BLUE);
		break;
	default:
		/* Other states don't alter LED behavior */
		break;
	}
}
Exemplo n.º 3
0
static void std_led_set_battery(void)
{
	static int battery_second;
	uint32_t chflags = charge_get_flags();

	battery_second++;

	/* BAT LED behavior:
	 * Same as the chromeos spec
	 * Green/Amber for CHARGE_FLAG_FORCE_IDLE
	 */
	switch (charge_get_state()) {
	case PWR_STATE_CHARGE:
		bat_led_set_color(LED_AMBER);
		break;
	case PWR_STATE_DISCHARGE:
		if (charge_get_percent() < 3)
			bat_led_set_color((battery_second & 1)
					? LED_OFF : LED_AMBER);
		else if (charge_get_percent() < 10)
			bat_led_set_color((battery_second & 3)
					? LED_OFF : LED_AMBER);
		else
			bat_led_set_color(LED_OFF);
		break;
	case PWR_STATE_ERROR:
		bat_led_set_color((battery_second & 1) ? LED_OFF : LED_RED);
		break;
	case PWR_STATE_CHARGE_NEAR_FULL:
		bat_led_set_color(LED_GREEN);
		break;
	case PWR_STATE_IDLE: /* External power connected in IDLE. */
		if (chflags & CHARGE_FLAG_FORCE_IDLE)
			bat_led_set_color(
				(battery_second & 0x2) ? LED_GREEN : LED_AMBER);
		else
			bat_led_set_color(LED_GREEN);
		break;
	default:
		/* Other states don't alter LED behavior */
		break;
	}
}
Exemplo n.º 4
0
static void pd_exchange_update_ec_status(struct ec_params_pd_status *ec_status)
{
	/* Send PD charge state and battery state of charge */
#ifdef CONFIG_HOSTCMD_PD_CHG_CTRL
	ec_status->charge_state = charge_state;
#endif
	if (charge_get_flags() & CHARGE_FLAG_BATT_RESPONSIVE)
		ec_status->batt_soc = charge_get_percent();
	else
		ec_status->batt_soc = -1;
}
Exemplo n.º 5
0
Arquivo: led.c Projeto: longsleep/ec
static void jerry_led_set_battery(void)
{
	static int battery_second;

	battery_second++;

	/* BAT LED behavior:
	 * Fully charged / idle: Off
	 * Under charging: Orange
	 * Battery low (10%): Orange in breeze mode (1 sec on, 3 sec off)
	 * Battery critical low (less than 3%) or abnormal battery
	 *     situation: Orange in blinking mode (1 sec on, 1 sec off)
	 * Using battery or not connected to AC power: OFF
	 */
	switch (charge_get_state()) {
	case PWR_STATE_CHARGE:
		bat_led_set(LED_ORANGE, 1);
		break;
	case PWR_STATE_CHARGE_NEAR_FULL:
		bat_led_set(LED_ORANGE, 1);
		break;
	case PWR_STATE_DISCHARGE:
		if (charge_get_percent() < 3)
			bat_led_set(LED_ORANGE, (battery_second & 1) ? 0 : 1);
		else if (charge_get_percent() < 10)
			bat_led_set(LED_ORANGE, (battery_second & 3) ? 0 : 1);
		else
			bat_led_set(LED_ORANGE, 0);
		break;
	case PWR_STATE_ERROR:
		bat_led_set(LED_ORANGE, (battery_second & 1) ? 0 : 1);
		break;
	case PWR_STATE_IDLE: /* External power connected in IDLE. */
		bat_led_set(LED_ORANGE, 0);
		break;
	default:
		/* Other states don't alter LED behavior */
		break;
	}
}
Exemplo n.º 6
0
/**
 * Set active charge port -- only one port can be active at a time.
 *
 * @param charge_port   Charge port to enable.
 *
 * Returns EC_SUCCESS if charge port is accepted and made active,
 * EC_ERROR_* otherwise.
 */
int board_set_active_charge_port(int charge_port)
{
	enum bd9995x_charge_port bd9995x_port;
	int bd9995x_port_select = 1;
	static int initialized;

	/*
	 * Reject charge port disable if our battery is critical and we
	 * have yet to initialize a charge port - continue to charge using
	 * charger ROM / POR settings.
	 */
	if (!initialized &&
	    charge_port == CHARGE_PORT_NONE &&
	    charge_get_percent() < 2)
		return -1;

	switch (charge_port) {
	case 0:
	case 1:
		/* Don't charge from a source port */
		if (board_vbus_source_enabled(charge_port))
			return -1;

		bd9995x_port = bd9995x_pd_port_to_chg_port(charge_port);
		break;
	case CHARGE_PORT_NONE:
		bd9995x_port_select = 0;
		bd9995x_port = BD9995X_CHARGE_PORT_BOTH;
		break;
	default:
		panic("Invalid charge port\n");
		break;
	}

	CPRINTS("New chg p%d", charge_port);
	initialized = 1;

	return bd9995x_select_input_port(bd9995x_port, bd9995x_port_select);
}
static int test_external_funcs(void)
{
	int rv, temp;
	uint32_t flags;
	int state;

	/* Connect the AC */
	test_setup(1);

	flags = charge_get_flags();
	TEST_ASSERT(flags & CHARGE_FLAG_EXTERNAL_POWER);
	TEST_ASSERT(!(flags & CHARGE_FLAG_FORCE_IDLE));

	/* Invalid or do-nothing commands first */
	UART_INJECT("chg\n");
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_CHARGE);
	flags = charge_get_flags();
	TEST_ASSERT(flags & CHARGE_FLAG_EXTERNAL_POWER);
	TEST_ASSERT(!(flags & CHARGE_FLAG_FORCE_IDLE));

	UART_INJECT("chg blahblah\n");
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_CHARGE);
	flags = charge_get_flags();
	TEST_ASSERT(flags & CHARGE_FLAG_EXTERNAL_POWER);
	TEST_ASSERT(!(flags & CHARGE_FLAG_FORCE_IDLE));

	UART_INJECT("chg idle\n");
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_CHARGE);
	flags = charge_get_flags();
	TEST_ASSERT(flags & CHARGE_FLAG_EXTERNAL_POWER);
	TEST_ASSERT(!(flags & CHARGE_FLAG_FORCE_IDLE));

	UART_INJECT("chg idle blargh\n");
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_CHARGE);
	flags = charge_get_flags();
	TEST_ASSERT(flags & CHARGE_FLAG_EXTERNAL_POWER);
	TEST_ASSERT(!(flags & CHARGE_FLAG_FORCE_IDLE));

	/* Now let's force idle on and off */
	UART_INJECT("chg idle on\n");
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_IDLE);
	flags = charge_get_flags();
	TEST_ASSERT(flags & CHARGE_FLAG_EXTERNAL_POWER);
	TEST_ASSERT(flags & CHARGE_FLAG_FORCE_IDLE);

	UART_INJECT("chg idle off\n");
	wait_charging_state();
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_CHARGE);
	flags = charge_get_flags();
	TEST_ASSERT(flags & CHARGE_FLAG_EXTERNAL_POWER);
	TEST_ASSERT(!(flags & CHARGE_FLAG_FORCE_IDLE));

	/* and the rest */
	TEST_ASSERT(charge_get_state() == PWR_STATE_CHARGE);
	TEST_ASSERT(!charge_want_shutdown());
	TEST_ASSERT(charge_get_percent() == 50);
	temp = 0;
	rv = charge_temp_sensor_get_val(0, &temp);
	TEST_ASSERT(rv == EC_SUCCESS);
	TEST_ASSERT(K_TO_C(temp) == 25);

	return EC_SUCCESS;
}
Exemplo n.º 8
0
static void oak_led_set_battery(int board_version)
{
	static int battery_second;

	battery_second++;

	switch(board_version) {
	case OAK_REV3:
	case OAK_REV4:
		/*
		 * For Rev3 and Rev4 revision:
		 * BAT LED behavior:
		 * - Fully charged / idle: Green ON
		 * - Charging: Amber ON (BAT_LED_RED && BAT_LED_GREEN)
		 * - Battery discharging capacity<10%, red blink
		 * - Battery error: Red ON
		 */
		switch (charge_get_state()) {
		case PWR_STATE_CHARGE:
			bat_led_set(BAT_LED_AMBER, 1);
			break;
		case PWR_STATE_CHARGE_NEAR_FULL:
			bat_led_set(BAT_LED_GREEN, 1);
			bat_led_set(BAT_LED_RED, 0);
			break;
		case PWR_STATE_DISCHARGE:
			bat_led_set(BAT_LED_GREEN, 0);
			if (charge_get_percent() < 3)
				bat_led_set(BAT_LED_RED,
					  (battery_second & 1) ? 0 : 1);
			else if (charge_get_percent() < 10)
				bat_led_set(BAT_LED_RED,
					  (battery_second & 3) ? 0 : 1);
			else
				bat_led_set(BAT_LED_RED, 0);
			break;
		case PWR_STATE_ERROR:
			bat_led_set(BAT_LED_RED, 1);
			break;
		case PWR_STATE_IDLE: /* Ext. power connected in IDLE. */
			bat_led_set(BAT_LED_GREEN, 1);
			bat_led_set(BAT_LED_RED, 0);
			break;
		default:
			/* Other states don't alter LED behavior */
			break;
		}
		break; /* End of case OAK_REV3 & OAK_REV4 */
	default:
		/*
		 * Put power control here since we are using the "battery" LED.
		 * This allows LED autocontrol to be turned off by cmd during factory test.
		 *
		 * PWR LED behavior:
		 * Power on: Green
		 * Suspend: Green in breeze mode ( 1 sec on/ 3 sec off)
		 * Power off: OFF
		 */
		if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
			bat_led_set(BAT_LED_GREEN, 0);
		else if (chipset_in_state(CHIPSET_STATE_ON))
			bat_led_set(BAT_LED_GREEN, 1);
		else if (chipset_in_state(CHIPSET_STATE_SUSPEND)) {
			int cycle_time = 4;
			/* Oak rev5 with GlaDOS ID has a extremely power
			 * comsuming LED. Increase LED blink cycle time to reduce
			 * S3 power comsuption. */
			if (board_version >= OAK_REV5)
				cycle_time = 10;
			bat_led_set(BAT_LED_GREEN,
				    (battery_second % cycle_time) ? 0 : 1);
		}

		/* BAT LED behavior:
		 * Fully charged / idle: Off
		 * Under charging: Orange
		 * Bat. low (10%): Orange in breeze mode (1s on, 3s off)
		 * Bat. critical low (less than 3%) or abnormal battery
		 *   situation: Orange in blinking mode (1s on, 1s off)
		 * Using battery or not connected to AC power: OFF
		 */
		switch (charge_get_state()) {
		case PWR_STATE_CHARGE:
			bat_led_set(BAT_LED_ORANGE, 1);
			break;
		case PWR_STATE_CHARGE_NEAR_FULL:
			bat_led_set(BAT_LED_ORANGE, 1);
			break;
		case PWR_STATE_DISCHARGE:
			if (charge_get_percent() < 3)
				bat_led_set(BAT_LED_ORANGE,
					  (battery_second & 1) ? 0 : 1);
			else if (charge_get_percent() < 10)
				bat_led_set(BAT_LED_ORANGE,
					  (battery_second & 3) ? 0 : 1);
			else
				bat_led_set(BAT_LED_ORANGE, 0);
			break;
		case PWR_STATE_ERROR:
			bat_led_set(BAT_LED_ORANGE,
				    (battery_second & 1) ? 0 : 1);
			break;
		case PWR_STATE_IDLE: /* Ext. power connected in IDLE. */
			bat_led_set(BAT_LED_ORANGE, 0);
			break;
		default:
			/* Other states don't alter LED behavior */
			break;
		}
		break; /* End of default */
	}
}
Exemplo n.º 9
0
/**
 * Common handler for steady states
 *
 * @param state		Current power state
 * @return Updated power state
 */
static enum power_state power_common_state(enum power_state state)
{
	switch (state) {
	case POWER_G3:
		if (want_g3_exit) {
			want_g3_exit = 0;
			return POWER_G3S5;
		}

		in_want = 0;
#ifdef CONFIG_HIBERNATE
		if (extpower_is_present())
			task_wait_event(-1);
		else {
			uint64_t target_time;
			uint64_t time_now = get_time().val;
			uint32_t delay = hibernate_delay;
#ifdef CONFIG_HIBERNATE_BATT_PCT
			if (charge_get_percent() <= CONFIG_HIBERNATE_BATT_PCT
			    && CONFIG_HIBERNATE_BATT_SEC < delay)
				delay = CONFIG_HIBERNATE_BATT_SEC;
#endif
			target_time = last_shutdown_time + delay * 1000000ull;
			if (time_now > target_time) {
				/*
				 * Time's up.  Hibernate until wake pin
				 * asserted.
				 */
#ifdef CONFIG_LOW_POWER_PSEUDO_G3
				enter_pseudo_g3();
#else
				CPRINTS("hibernating");
				system_hibernate(0, 0);
#endif
			} else {
				uint64_t wait = target_time - time_now;
				if (wait > TASK_MAX_WAIT_US)
					wait = TASK_MAX_WAIT_US;

				/* Wait for a message */
				task_wait_event(wait);
			}
		}
#else /* !CONFIG_HIBERNATE */
		task_wait_event(-1);
#endif
		break;

	case POWER_S5:
		/*
		 * If the power button is pressed before S5 inactivity timer
		 * expires, the timer will be cancelled and the task of the
		 * power state machine will be back here again. Since we are
		 * here, which means the system has been waiting for CPU
		 * starting up, we don't need want_g3_exit flag to be set
		 * anymore. Therefore, we can reset the flag here to prevent
		 * the situation that the flag is still set after S5 inactivity
		 * timer expires, which can cause the system to exit G3 again.
		 */
		want_g3_exit = 0;

		/* Wait for inactivity timeout */
		power_wait_signals(0);
		if (task_wait_event(S5_INACTIVITY_TIMEOUT) ==
		    TASK_EVENT_TIMER) {
			/* Prepare to drop to G3; wake not requested yet */
			return POWER_S5G3;
		}
		break;

	case POWER_S3:
		/* Wait for a message */
		power_wait_signals(0);
		task_wait_event(-1);
		break;

	case POWER_S0:
		/* Wait for a message */
		power_wait_signals(0);
		task_wait_event(-1);
		break;

	default:
		/* No common functionality for transition states */
		break;
	}

	return state;
}
Exemplo n.º 10
0
int charge_want_shutdown(void)
{
	return (charge_get_state() == PWR_STATE_DISCHARGE) &&
		charge_get_percent() < BATTERY_LEVEL_SHUTDOWN;
}
Exemplo n.º 11
0
/**
 * Common handler for steady states
 *
 * @param state		Current power state
 * @return Updated power state
 */
static enum power_state power_common_state(enum power_state state)
{
    switch (state) {
    case POWER_G3:
                if (want_g3_exit) {
                want_g3_exit = 0;
                return POWER_G3S5;
            }

        in_want = 0;
#ifdef CONFIG_HIBERNATE
        if (extpower_is_present())
            task_wait_event(-1);
        else {
            uint64_t target_time;
            uint64_t time_now = get_time().val;
            uint32_t delay = hibernate_delay;
#ifdef CONFIG_HIBERNATE_BATT_PCT
            if (charge_get_percent() <= CONFIG_HIBERNATE_BATT_PCT
                    && CONFIG_HIBERNATE_BATT_SEC < delay)
                delay = CONFIG_HIBERNATE_BATT_SEC;
#endif
            target_time = last_shutdown_time + delay * 1000000ull;
            if (time_now > target_time) {
                /*
                 * Time's up.  Hibernate until wake pin
                 * asserted.
                 */
#ifdef CONFIG_LOW_POWER_PSEUDO_G3
                enter_pseudo_g3();
#else
                CPRINTS("hibernating");
                system_hibernate(0, 0);
#endif
            } else {
                uint64_t wait = target_time - time_now;
                if (wait > TASK_MAX_WAIT_US)
                    wait = TASK_MAX_WAIT_US;

                /* Wait for a message */
                task_wait_event(wait);
            }
        }
#else /* !CONFIG_HIBERNATE */
        task_wait_event(-1);
#endif
        break;

    case POWER_S5:
        /* Wait for inactivity timeout */
        power_wait_signals(0);
        if (task_wait_event(S5_INACTIVITY_TIMEOUT) ==
                TASK_EVENT_TIMER) {
            /* Drop to G3; wake not requested yet */
            want_g3_exit = 0;
            return POWER_S5G3;
        }
        break;

    case POWER_S3:
        /* Wait for a message */
        power_wait_signals(0);
        task_wait_event(-1);
        break;

    case POWER_S0:
        /* Wait for a message */
        power_wait_signals(0);
        task_wait_event(-1);
        break;

    default:
        /* No common functionality for transition states */
        break;
    }

    return state;
}
Exemplo n.º 12
0
/**
 * Return if board is consuming full amount of input current
 */
int board_is_consuming_full_charge(void)
{
	int chg_perc = charge_get_percent();

	return chg_perc > 2 && chg_perc < 95;
}
Exemplo n.º 13
0
static void pd_exchange_status(void)
{
	struct ec_params_pd_status ec_status;
	struct ec_response_pd_status pd_status;
	int rv = 0;
#ifdef CONFIG_HOSTCMD_PD_PANIC
	static int pd_in_rw;
#endif

	/* Send PD charge state and battery state of charge */
	ec_status.charge_state = charge_state;
	if (charge_get_flags() & CHARGE_FLAG_BATT_RESPONSIVE)
		ec_status.batt_soc = charge_get_percent();
	else
		ec_status.batt_soc = -1;

	rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 1, &ec_status,
			     sizeof(struct ec_params_pd_status), &pd_status,
			     sizeof(struct ec_response_pd_status));

	/* If PD doesn't support new command version, try old version */
	if (rv == -EC_RES_INVALID_VERSION)
		rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 0, &ec_status,
			     sizeof(struct ec_params_pd_status), &pd_status,
			     sizeof(struct ec_response_pd_status));

	if (rv < 0) {
		CPRINTS("Host command to PD MCU failed");
		return;
	}

#ifdef CONFIG_HOSTCMD_PD_PANIC
	/*
	 * Check if PD MCU is in RW. If PD MCU was in RW and is now in RO
	 * AND it did not sysjump to RO, then it must have crashed, and
	 * therefore we should panic as well.
	 */
	if (pd_status.status & PD_STATUS_IN_RW) {
		pd_in_rw = 1;
	} else if (pd_in_rw &&
		   !(pd_status.status & PD_STATUS_JUMPED_TO_IMAGE)) {
		panic_printf("PD crash");
		software_panic(PANIC_SW_PD_CRASH, 0);
	}
#endif

#ifdef HAS_TASK_LIGHTBAR
	/*
	 * If charge port has changed, and it was initialized, then show
	 * battery status on lightbar.
	 */
	if (pd_status.active_charge_port != charge_port) {
		if (charge_port != CHARGE_PORT_UNINITIALIZED) {
			charge_port = pd_status.active_charge_port;
			lightbar_sequence(LIGHTBAR_TAP);
		} else {
			charge_port = pd_status.active_charge_port;
		}
	}
#else
	/* Store the active charge port */
	charge_port = pd_status.active_charge_port;
#endif

	/* Set input current limit */
	rv = charge_set_input_current_limit(MAX(pd_status.curr_lim_ma,
					CONFIG_CHARGER_INPUT_CURRENT));
	if (rv < 0)
		CPRINTS("Failed to set input current limit from PD MCU");

	/* If PD is signalling host event, then pass it up to AP */
	if (pd_status.status & PD_STATUS_HOST_EVENT)
		host_set_single_event(EC_HOST_EVENT_PD_MCU);
}
Exemplo n.º 14
0
static void led_set_battery(void)
{
	static int battery_ticks;
	static int suspend_ticks;
	static int previous_state_suspend;
	uint32_t chflags = charge_get_flags();

	battery_ticks++;
	suspend_ticks++;
	switch (charge_get_state()) {
	case PWR_STATE_CHARGE:
		led_set_color_battery(LED_AMBER);
		break;
	case PWR_STATE_DISCHARGE:
		/* Less than 3%, blink one second every two second */
		if (!chipset_in_state(CHIPSET_STATE_ANY_OFF) &&
			charge_get_percent() < CRITICAL_LOW_BATTERY_PERCENTAGE)
			led_set_color_battery(
				(battery_ticks % LED_TOTAL_2SECS_TICKS <
				 LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF);
		/* Less than 10%, blink one second every four seconds */
		else if (!chipset_in_state(CHIPSET_STATE_ANY_OFF) &&
			charge_get_percent() < LOW_BATTERY_PERCENTAGE)
			led_set_color_battery(
				(battery_ticks % LED_TOTAL_4SECS_TICKS <
				 LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF);
		else {
			if (chipset_in_state(CHIPSET_STATE_SUSPEND
				| CHIPSET_STATE_STANDBY)) {
				if (!previous_state_suspend)
					suspend_ticks = 0;
				/* Blink once every four seconds. */
				led_set_color_battery(
					(suspend_ticks % LED_TOTAL_4SECS_TICKS)
					< LED_ON_1SEC_TICKS ?
					LED_AMBER : LED_OFF);
				previous_state_suspend = 1;
				return;
			}

			if (chipset_in_state(CHIPSET_STATE_ON))
				led_set_color_battery(LED_BLUE);
			else
				led_set_color_battery(LED_OFF);
		}
		break;
	case PWR_STATE_ERROR:
		led_set_color_battery(
			(battery_ticks % LED_TOTAL_2SECS_TICKS <
			 LED_ON_1SEC_TICKS) ? LED_AMBER : LED_OFF);
		break;
	case PWR_STATE_CHARGE_NEAR_FULL:
		led_set_color_battery(LED_BLUE);
		break;
	case PWR_STATE_IDLE: /* External power connected in IDLE */
		if (chflags & CHARGE_FLAG_FORCE_IDLE)
			led_set_color_battery(
				(battery_ticks % LED_TOTAL_4SECS_TICKS <
				 LED_ON_2SECS_TICKS) ? LED_AMBER : LED_BLUE);
		else
			led_set_color_battery(LED_BLUE);
		break;
	default:
		/* Other states don't alter LED behavior */
		break;
	}
	previous_state_suspend = 0;
}