Example #1
0
static void onewire_led_tick(void)
{
	static enum led_color current_color = LED_COLOR_COUNT;
	static int tick_count;

	enum led_color new_color = LED_OFF;
	uint32_t chflags = charge_get_flags();

	tick_count++;

	if (!(chflags & CHARGE_FLAG_EXTERNAL_POWER)) {
		/* AC isn't present, so the power LED on the AC plug is off */
		current_color = LED_OFF;
		return;
	}

	/* Translate charge state to LED color */
	switch (charge_get_state()) {
	case PWR_STATE_IDLE:
		if (chflags & CHARGE_FLAG_FORCE_IDLE)
			new_color = (tick_count & 1) ? LED_GREEN : LED_OFF;
		else
			new_color = LED_GREEN;
		break;
	case PWR_STATE_CHARGE:
		new_color = LED_YELLOW;
		break;
	case PWR_STATE_CHARGE_NEAR_FULL:
		new_color = LED_GREEN;
		break;
	case PWR_STATE_ERROR:
		new_color = LED_RED;
		break;
	default:
		/* Other states don't change LED color */
		break;
	}

	/*
	 * The power adapter on link can partially unplug and lose its LED
	 * state.  There's no way to detect this, so just assume it forgets its
	 * state every 10 seconds.
	 */
	if (!(tick_count % 10))
		current_color = LED_COLOR_COUNT;

	/* If current color is still correct, leave now */
	if (new_color == current_color)
		return;

	/* Update LED */
	if (!led_set(new_color))
		current_color = new_color;
}
Example #2
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;
}
Example #3
0
static int charge_force_idle(int enable)
{
	if (enable) {
		/*
		 * Force-idle state is only meaningful if external power is
		 * present. If it's not present we can't charge anyway...
		 */
		if (!(charge_get_flags() & CHARGE_FLAG_EXTERNAL_POWER))
			return EC_ERROR_UNKNOWN;
		charger_post_init();
	}
	state_machine_force_idle = enable;
	return EC_SUCCESS;
}
Example #4
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;
	}
}
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;
	}
}
Example #6
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;
	}
}
Example #7
0
/**
 * Called by hook task every 250 ms
 */
static void led_tick(void)
{
	static unsigned ticks;
	int chstate = charge_get_state();

	ticks++;

	/* If we don't control the LED, nothing to do */
	if (!led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED))
		return;

	/* If charging error, blink orange, 25% duty cycle, 4 sec period */
	if (chstate == PWR_STATE_ERROR) {
		set_color((ticks % 16) < 4 ? LED_ORANGE : LED_OFF);
		return;
	}

	/* If charge-force-idle, blink green, 50% duty cycle, 2 sec period */
	if (chstate == PWR_STATE_IDLE &&
	    (charge_get_flags() & CHARGE_FLAG_FORCE_IDLE)) {
		set_color((ticks & 0x4) ? LED_GREEN : LED_OFF);
		return;
	}

	/* If the system is charging, solid orange */
	if (chstate == PWR_STATE_CHARGE) {
		set_color(LED_ORANGE);
		return;
	}

	/* If AC connected and fully charged (or close to it), solid green */
	if (chstate == PWR_STATE_CHARGE_NEAR_FULL ||
	    chstate == PWR_STATE_IDLE) {
		set_color(LED_GREEN);
		return;
	}

	/* Otherwise, system is off and AC not connected, LED off */
	set_color(LED_OFF);
}
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;
}
static int test_charge_state(void)
{
	enum charge_state state;
	uint32_t flags;

	/* On AC */
	test_setup(1);

	ccprintf("[CHARGING TEST] AC on\n");

	/* Detach battery, charging error */
	ccprintf("[CHARGING TEST] Detach battery\n");
	TEST_ASSERT(test_detach_i2c(I2C_PORT_BATTERY, BATTERY_ADDR) ==
		    EC_SUCCESS);
	msleep(BATTERY_DETACH_DELAY);
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_ERROR);

	/* Attach battery again, charging */
	ccprintf("[CHARGING TEST] Attach battery\n");
	test_attach_i2c(I2C_PORT_BATTERY, BATTERY_ADDR);
	/* And changing full capacity should trigger a host event */
	ev_clear(EC_HOST_EVENT_BATTERY);
	sb_write(SB_FULL_CHARGE_CAPACITY, 0xeff0);
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_CHARGE);
	TEST_ASSERT(ev_is_set(EC_HOST_EVENT_BATTERY));

	/* Unplug AC, discharging at 1000mAh */
	ccprintf("[CHARGING TEST] AC off\n");
	gpio_set_level(GPIO_AC_PRESENT, 0);
	sb_write(SB_CURRENT, -1000);
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_DISCHARGE);
	flags = charge_get_flags();
	TEST_ASSERT(!(flags & CHARGE_FLAG_EXTERNAL_POWER));
	TEST_ASSERT(!(flags & CHARGE_FLAG_FORCE_IDLE));

	/* Discharging waaaay overtemp is ignored */
	ccprintf("[CHARGING TEST] AC off, batt temp = 0xffff\n");
	gpio_set_level(GPIO_AC_PRESENT, 0);
	sb_write(SB_CURRENT, -1000);
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_DISCHARGE);
	sb_write(SB_TEMPERATURE, 0xffff);
	state = wait_charging_state();
	TEST_ASSERT(!is_shutdown);
	TEST_ASSERT(state == PWR_STATE_DISCHARGE);
	sb_write(SB_TEMPERATURE, CELSIUS_TO_DECI_KELVIN(40));

	/* Discharging overtemp */
	ccprintf("[CHARGING TEST] AC off, batt temp = 90 C\n");
	gpio_set_level(GPIO_AC_PRESENT, 0);
	sb_write(SB_CURRENT, -1000);

	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_DISCHARGE);
	sb_write(SB_TEMPERATURE, CELSIUS_TO_DECI_KELVIN(90));
	state = wait_charging_state();
	TEST_ASSERT(is_shutdown);
	TEST_ASSERT(state == PWR_STATE_DISCHARGE);
	sb_write(SB_TEMPERATURE, CELSIUS_TO_DECI_KELVIN(40));

	/* Force idle */
	ccprintf("[CHARGING TEST] AC on, force idle\n");
	gpio_set_level(GPIO_AC_PRESENT, 1);
	sb_write(SB_CURRENT, 1000);
	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));
	charge_control(CHARGE_CONTROL_IDLE);
	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);
	charge_control(CHARGE_CONTROL_NORMAL);
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_CHARGE);

	/* Force discharge */
	ccprintf("[CHARGING TEST] AC on, force discharge\n");
	gpio_set_level(GPIO_AC_PRESENT, 1);
	sb_write(SB_CURRENT, 1000);
	charge_control(CHARGE_CONTROL_DISCHARGE);
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_IDLE);
	TEST_ASSERT(is_force_discharge);
	charge_control(CHARGE_CONTROL_NORMAL);
	state = wait_charging_state();
	TEST_ASSERT(state == PWR_STATE_CHARGE);
	TEST_ASSERT(!is_force_discharge);

	return EC_SUCCESS;
}
Example #10
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;
}
Example #11
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);
}
Example #12
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;
}