コード例 #1
0
ファイル: rockchip.c プロジェクト: coreboot/chrome-ec
static int command_power(int argc, char **argv)
{
	int v;

	if (argc < 2) {
		enum power_state_t state;

		state = PSTATE_UNKNOWN;
		if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
			state = PSTATE_OFF;
		if (chipset_in_state(CHIPSET_STATE_SUSPEND))
			state = PSTATE_SUSPEND;
		if (chipset_in_state(CHIPSET_STATE_ON))
			state = PSTATE_ON;
		ccprintf("%s\n", state_name[state]);

		return EC_SUCCESS;
	}

	if (!parse_bool(argv[1], &v))
		return EC_ERROR_PARAM1;

	power_request = v ? POWER_REQ_ON : POWER_REQ_OFF;
	ccprintf("Requesting power %s\n", power_req_name[power_request]);
	task_wake(TASK_ID_CHIPSET);

	return EC_SUCCESS;
}
コード例 #2
0
ファイル: led.c プロジェクト: coreboot/chrome-ec
static void oak_led_set_power(int board_version)
{
	static int power_second;

	power_second++;

	switch(board_version) {
	case OAK_REV3:
	case OAK_REV4:
		/*
		 * For Rev3 and Rev4 revision.
		 * PWR LED behavior:
		 * Power on: Green ON
		 * Suspend: Orange in breeze mode ( 1 sec on/ 3 sec off)
		 * Power off: OFF
		 */
		if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
			bat_led_set(PWR_LED_GREEN, 0);
			bat_led_set(PWR_LED_ORANGE, 0);
		} else if (chipset_in_state(CHIPSET_STATE_ON)) {
			bat_led_set(PWR_LED_GREEN, 1);
			bat_led_set(PWR_LED_ORANGE, 0);
		} else if (chipset_in_state(CHIPSET_STATE_SUSPEND)) {
			bat_led_set(PWR_LED_GREEN, 0);
			bat_led_set(PWR_LED_ORANGE,
				    (power_second & 3) ? 0 : 1);
		}
		break;
	default:
		break;
	}
}
コード例 #3
0
ファイル: lpc.c プロジェクト: fishbaoz/chrome-ec
/*
 * In AP S0ix & S3 -> S0 transitions,
 * the chipset_resume hook is called.
 *
 * During S0ix exit, the wake mask for lid open is disabled.
 * All pending events are cleared
 *
 */
void lpc_disable_wake_mask_for_lid_open(void)
{
	if ((chipset_in_state(CHIPSET_STATE_STANDBY | CHIPSET_STATE_ON)) ||
				chipset_in_state(CHIPSET_STATE_ON)) {
		lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, 0);
		lpc_clear_host_events();
	}
}
コード例 #4
0
ファイル: lpc.c プロジェクト: fishbaoz/chrome-ec
/*
 * In AP S0 -> S3 & S0ix transitions,
 * the chipset_suspend is called.
 *
 * The chipset_in_state(CHIPSET_STATE_STANDBY | CHIPSET_STATE_ON)
 * is used to detect the S0ix transiton.
 *
 * During S0ix entry, the wake mask for lid open is enabled.
 *
 */
void lpc_enable_wake_mask_for_lid_open(void)
{
	if ((chipset_in_state(CHIPSET_STATE_STANDBY | CHIPSET_STATE_ON)) ||
				chipset_in_state(CHIPSET_STATE_STANDBY)) {
		uint32_t mask = 0;

		mask = ((lpc_get_host_event_mask(LPC_HOST_EVENT_WAKE)) |
			EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN));

		lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, mask);
}	}
コード例 #5
0
ファイル: charge_state_v2.c プロジェクト: coreboot/chrome-ec
/*
 * Send host event to the AP if the battery is temperature or charge level
 * is critical. Force-shutdown if the problem isn't corrected after timeout.
 */
static void shutdown_on_critical_battery(void)
{
	int batt_temp_c;
	int battery_critical = 0;

	/*
	 * TODO(crosbug.com/p/27642): The thermal loop should watch the battery
	 * temp, so it can turn fans on.
	 */
	batt_temp_c = DECI_KELVIN_TO_CELSIUS(curr.batt.temperature);
	if (battery_too_hot(batt_temp_c)) {
		CPRINTS("Batt temp out of range: %dC", batt_temp_c);
		battery_critical = 1;
	}

	if (battery_too_low() && !curr.batt_is_charging) {
		CPRINTS("Low battery: %d%%, %dmV",
			curr.batt.state_of_charge, curr.batt.voltage);
		battery_critical = 1;
	}

	if (!battery_critical) {
		/* Reset shutdown warning time */
		shutdown_warning_time.val = 0;
		return;
	}

	if (!shutdown_warning_time.val) {
		CPRINTS("charge warn shutdown due to critical battery");
		shutdown_warning_time = get_time();
		if (!chipset_in_state(CHIPSET_STATE_ANY_OFF))
			host_set_single_event(EC_HOST_EVENT_BATTERY_SHUTDOWN);
	} else if (get_time().val > shutdown_warning_time.val +
		   CRITICAL_BATTERY_SHUTDOWN_TIMEOUT_US) {
		if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
#ifdef CONFIG_HIBERNATE
			/* Timeout waiting for charger to provide more power */
			CPRINTS(
			  "charge force EC hibernate due to critical battery");
			system_hibernate(0, 0);
#elif defined(CONFIG_BATTERY_CRITICAL_SHUTDOWN_CUT_OFF)
			CPRINTS(
			  "charge force battery cut-off due to critical level");
			board_cut_off_battery();
#endif
		} else {
			/* Timeout waiting for AP to shut down, so kill it */
			CPRINTS(
			  "charge force shutdown due to critical battery");
			chipset_force_shutdown();
		}
	}
}
コード例 #6
0
ファイル: led_policy_std.c プロジェクト: fishbaoz/chrome-ec
static void std_led_set_power(void)
{
	static int power_second;

	power_second++;

	if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
		pwr_led_set_color(LED_OFF);
	else if (chipset_in_state(CHIPSET_STATE_ON))
		pwr_led_set_color(LED_WHITE);
	else if (chipset_in_state(CHIPSET_STATE_SUSPEND))
		pwr_led_set_color((power_second & 3) ? LED_OFF : LED_WHITE);
}
コード例 #7
0
ファイル: spi.c プロジェクト: longsleep/ec
static void spi_init(void)
{
	stm32_spi_regs_t *spi = STM32_SPI1_REGS;

	/* Reset the SPI Peripheral to clear any existing weird states. */
	/* Fix for bug chrome-os-partner:31390 */
	enabled = 0;
	state = SPI_STATE_DISABLED;
	STM32_RCC_APB2RSTR |= (1 << 12);
	STM32_RCC_APB2RSTR &= ~(1 << 12);

	/* 40 MHz pin speed */
	STM32_GPIO_OSPEEDR(GPIO_A) |= 0xff00;

	/* Enable clocks to SPI1 module */
	STM32_RCC_APB2ENR |= STM32_RCC_PB2_SPI1;

	/*
	 * Enable rx/tx DMA and get ready to receive our first transaction and
	 * "disable" FIFO by setting event to happen after only 1 byte
	 */
	spi->cr2 = STM32_SPI_CR2_RXDMAEN | STM32_SPI_CR2_TXDMAEN |
		STM32_SPI_CR2_FRXTH;

	/* Enable the SPI peripheral */
	spi->cr1 |= STM32_SPI_CR1_SPE;

	gpio_enable_interrupt(GPIO_SPI1_NSS);

	/* If chipset is already on, prepare for transactions */
	if (chipset_in_state(CHIPSET_STATE_ON))
		spi_chipset_startup();
}
コード例 #8
0
ファイル: peci.c プロジェクト: coreboot/chrome-ec
int peci_temp_sensor_get_val(int idx, int *temp_ptr)
{
	int sum = 0;
	int success_cnt = 0;
	int i;

	if (!chipset_in_state(CHIPSET_STATE_ON))
		return EC_ERROR_NOT_POWERED;

	for (i = 0; i < TEMP_AVG_LENGTH; ++i) {
		if (temp_vals[i] >= 0) {
			success_cnt++;
			sum += temp_vals[i];
		}
	}

	/*
	 * Require at least two valid samples. When the AP transitions into S0,
	 * it is possible, depending on the timing of the PECI sample, to read
	 * an invalid temperature. This is very rare, but when it does happen
	 * the temperature returned is CONFIG_PECI_TJMAX. Requiring two valid
	 * samples here assures us that one bad maximum temperature reading
	 * when entering S0 won't cause us to trigger an over temperature.
	 */
	if (success_cnt < 2)
		return EC_ERROR_UNKNOWN;

	*temp_ptr = sum / success_cnt;
	return EC_SUCCESS;
}
コード例 #9
0
ファイル: led_kevin.c プロジェクト: fishbaoz/chrome-ec
static void kevin_led_set_power_battery(void)
{
	static int power_ticks;

	if (chipset_in_state(CHIPSET_STATE_ON)) {
		set_color(LED_BLUE);
		return;
	}

	/* CHIPSET_STATE_OFF */
	switch (charge_get_state()) {
	case PWR_STATE_DISCHARGE:
		set_color(LED_OFF);
		break;
	case PWR_STATE_CHARGE:
		set_color(LED_RED);
		break;
	case PWR_STATE_ERROR:
		power_ticks++;
		set_color(((power_ticks % LED_TOTAL_TICKS)
			  < LED_ON_TICKS) ? LED_RED : LED_GREEN);
		break;
	case PWR_STATE_CHARGE_NEAR_FULL:
	case PWR_STATE_IDLE: /* External power connected in IDLE. */
		set_color(LED_GREEN);
		break;
	default:
		set_color(LED_RED);
		break;
	}
	if ((charge_get_state()) != PWR_STATE_ERROR)
		power_ticks = 0;
}
コード例 #10
0
static void big_led_set_power(void)
{
	static int power_second;

	power_second++;

	/* PWR LED behavior:
	 * Power on: Blue
	 * Suspend: Orange in breeze mode ( 1 sec on/ 3 sec off)
	 * Power off: OFF
	 */
	if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
		pwr_led_set_color(LED_OFF);
	else if (chipset_in_state(CHIPSET_STATE_ON))
		pwr_led_set_color(LED_BLUE);
	else if (chipset_in_state(CHIPSET_STATE_SUSPEND))
		pwr_led_set_color((power_second & 3) ? LED_OFF : LED_ORANGE);
}
コード例 #11
0
ファイル: led.c プロジェクト: longsleep/ec
static void jerry_led_set_power(void)
{
	static int power_second;

	power_second++;

	/* 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))
		pwr_led_set(0);
	else if (chipset_in_state(CHIPSET_STATE_ON))
		pwr_led_set(1);
	else if (chipset_in_state(CHIPSET_STATE_SUSPEND))
		pwr_led_set((power_second & 3) ? 0 : 1);
}
コード例 #12
0
/**
 * Turn off the AP
 */
static int system_off(void)
{
	if (chipset_in_state(CHIPSET_STATE_ON)) {
		CPRINTS("pmu turning system off");
		chipset_force_shutdown();
	}

	return ST_IDLE0;
}
コード例 #13
0
ファイル: motion_sense.c プロジェクト: fourier49/BIZ_EC
static void motion_sense_startup(void)
{
	int i;
	struct motion_sensor_t *sensor;

	sensor_active = SENSOR_ACTIVE_S5;
	for (i = 0; i < motion_sensor_count; ++i) {
		sensor = &motion_sensors[i];
		sensor->state = SENSOR_NOT_INITIALIZED;
	}

	/* If the AP is already in S0, call the resume hook now.
	 * We may initialize the sensor 2 times (once in RO, anoter time in RW),
	 * but it may be necessary if the init sequence has changed.
	 */
	if (chipset_in_state(SENSOR_ACTIVE_S0_S3))
		motion_sense_suspend();
	if (chipset_in_state(SENSOR_ACTIVE_S0))
		motion_sense_resume();
}
コード例 #14
0
ファイル: lpc.c プロジェクト: coreboot/chrome-ec
/*
 * In AP S0ix & S3 -> S0 transitions,
 * the chipset_resume hook is called.
 *
 * During S0ix exit, the wake mask for lid open is disabled.
 * All pending events are cleared
 */
void lpc_disable_wake_mask_for_lid_open(void)
{
	if (chipset_in_state(CHIPSET_STATE_STANDBY | CHIPSET_STATE_ON)) {
		uint32_t mask;

		mask = lpc_get_host_event_mask(LPC_HOST_EVENT_WAKE) &
			~EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN);

		lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, mask);
		lpc_clear_host_events();
	}
}
コード例 #15
0
ファイル: lpc.c プロジェクト: fishbaoz/chrome-ec
static void lpc_resume(void)
{
#ifdef CONFIG_POWER_S0IX
	if (chipset_in_state(CHIPSET_STATE_SUSPEND | CHIPSET_STATE_ON))
#endif
	{
		/* Mask all host events until the host unmasks them itself.  */
		lpc_set_host_event_mask(LPC_HOST_EVENT_SMI, 0);
		lpc_set_host_event_mask(LPC_HOST_EVENT_SCI, 0);
		lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, 0);
	}
	/* Store port 80 event so we know where resume happened */
	port_80_write(PORT_80_EVENT_RESUME);
}
コード例 #16
0
/**
 * Notify the host when battery remaining charge is lower than 10%
 */
static int notify_battery_low(void)
{
	static timestamp_t last_notify_time;
	timestamp_t now;

	if (chipset_in_state(CHIPSET_STATE_ON)) {
		now = get_time();
		if (now.val - last_notify_time.val > MINUTE) {
			CPRINTS("pmu notify battery low (< 4%)");
			last_notify_time = now;
			/* TODO(crosbug.com/p/23814): Actually notify AP */
		}
	}
	return ST_DISCHARGING;
}
コード例 #17
0
ファイル: board.c プロジェクト: coreboot/chrome-ec
/* Enable or disable input devices, based upon chipset state and tablet mode */
static void enable_input_devices(void)
{
	int kb_enable = 1;
	int tp_enable = 1;

	/* Disable KB & TP if chipset is off */
	if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
		kb_enable = 0;
		tp_enable = 0;
	}

	keyboard_scan_enable(kb_enable, KB_SCAN_DISABLE_LID_ANGLE);

	gpio_set_level(GPIO_EN_P3300_TRACKPAD_ODL, !tp_enable);
}
コード例 #18
0
ファイル: board.c プロジェクト: coreboot/chrome-ec
/* Enable or disable input devices, based upon chipset state and tablet mode */
static void enable_input_devices(void)
{
	int kb_enable = 1;
	int tp_enable = 1;

	/* Disable both TP and KB in tablet mode */
	if (!gpio_get_level(GPIO_TABLET_MODE_L))
		kb_enable = tp_enable = 0;
	/* Disable TP if chipset is off */
	else if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
		tp_enable = 0;

	keyboard_scan_enable(kb_enable, KB_SCAN_DISABLE_LID_ANGLE);
	gpio_set_level(GPIO_ENABLE_TOUCHPAD, tp_enable);
}
コード例 #19
0
ファイル: skylake.c プロジェクト: fourier49/BZ_DEV_EC
void chipset_force_shutdown(void)
{
	CPRINTS("%s()", __func__);

	/*
	 * Force off. Sending a reset command to the PMIC will power off
	 * the EC, so simulate a long power button press instead. This
	 * condition will reset once the state machine transitions to G3.
	 * Consider reducing the latency here by changing the power off
	 * hold time on the PMIC.
	 */
	if (!chipset_in_state(CHIPSET_STATE_HARD_OFF)) {
		forcing_shutdown = 1;
		power_button_pch_press();
	}
}
コード例 #20
0
int charger_profile_override(struct charge_state_data *curr)
{
	if (override_voltage)
		curr->requested_voltage = override_voltage;
	if (override_current)
		curr->requested_current = override_current;

	if (override_usec)
		return override_usec;

	/* Don't let it sleep a whole minute when the AP is off */
	if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
		return CHARGE_POLL_PERIOD_LONG;

	return 0;
}
コード例 #21
0
ファイル: panel.c プロジェクト: coreboot/chrome-ec
/**
 * Setup backlight controller and turn it on.
 */
static void lp8555_enable_pwm_mode(void)
{
	int reg;
	int rv;

	/*
	 * If not in S0, then PCH backlight enable will not be on, and if
	 * lid is closed EC backlight enable will not be on. Since these
	 * two signals are AND'ed together, no point in trying to talk to
	 * the lp8555 if either one of them is not true.
	 */
	if (!chipset_in_state(CHIPSET_STATE_ON) || !lid_is_open())
		return;

	/* Enable PWM mode. */
	rv = lp8555_read_with_retry(LP8555_REG_CONFIG, &reg);
	if (rv != EC_SUCCESS)
		return;
	reg &= ~LP8555_REG_CONFIG_MODE_MASK;
	reg |= LP8555_REG_CONFIG_MODE_PWM;
	rv = lp8555_write_with_retry(LP8555_REG_CONFIG, reg);
	if (rv != EC_SUCCESS)
		return;

	/* Set max LED current to 23mA. */
	rv = lp8555_write_with_retry(LP8555_REG_CURRENT,
				     LP8555_REG_CURRENT_MAXCURR_23MA);
	if (rv != EC_SUCCESS)
		return;

	/* Set the rate of brightness change. */
	rv = lp8555_write_with_retry(LP8555_REG_STEP,
				     LP8555_REG_STEP_STEP_200MS |
				     LP8555_REG_STEP_PWM_IN_HYST_8LSB |
				     LP8555_REG_STEP_SMOOTH_HEAVY);
	if (rv != EC_SUCCESS)
		return;

	/* Power on. */
	rv = lp8555_read_with_retry(LP8555_REG_COMMAND, &reg);
	if (rv != EC_SUCCESS)
		return;
	reg |= LP8555_REG_COMMAND_ON;
	rv = lp8555_write_with_retry(LP8555_REG_COMMAND, reg);
}
コード例 #22
0
ファイル: power_button_x86.c プロジェクト: thehobn/ec
/**
 * Set initial power button state.
 */
static void set_initial_pwrbtn_state(void)
{
	uint32_t reset_flags = system_get_reset_flags();

	if (system_jumped_to_this_image() &&
	    chipset_in_state(CHIPSET_STATE_ON)) {
		/*
		 * Jumped to this image while the chipset was already on, so
		 * simply reflect the actual power button state.
		 */
		if (power_button_is_pressed()) {
			CPRINTS("PB init-jumped-held");
			set_pwrbtn_to_pch(0);
		} else {
			CPRINTS("PB init-jumped");
		}
	} else if ((reset_flags & RESET_FLAG_AP_OFF) ||
		   (keyboard_scan_get_boot_key() == BOOT_KEY_DOWN_ARROW)) {
		/*
		 * Reset triggered by keyboard-controlled reset, and down-arrow
		 * was held down.  Or reset flags request AP off.
		 *
		 * Leave the main processor off.  This is a fail-safe
		 * combination for debugging failures booting the main
		 * processor.
		 *
		 * Don't let the PCH see that the power button was pressed.
		 * Otherwise, it might power on.
		 */
		CPRINTS("PB init-off");
		power_button_pch_release();
	} else {
		/*
		 * All other EC reset conditions power on the main processor so
		 * it can verify the EC.
		 */
#ifdef CONFIG_BRINGUP
		CPRINTS("PB idle");
		pwrbtn_state = PWRBTN_STATE_IDLE;
#else
		CPRINTS("PB init-on");
		pwrbtn_state = PWRBTN_STATE_INIT_ON;
#endif
	}
}
コード例 #23
0
ファイル: power_button_x86.c プロジェクト: thehobn/ec
static void set_pwrbtn_to_pch(int high)
{
	/*
	 * If the battery is discharging and low enough we'd shut down the
	 * system, don't press the power button. Also, don't press the
	 * power button if the battery is charging but the battery level
	 * is too low.
	 */
#ifdef CONFIG_CHARGER
	if (chipset_in_state(CHIPSET_STATE_ANY_OFF) && !high &&
	   (charge_want_shutdown() || charge_prevent_power_on())) {
		CPRINTS("PB PCH pwrbtn ignored due to battery level");
		high = 1;
	}
#endif
	CPRINTS("PB PCH pwrbtn=%s", high ? "HIGH" : "LOW");
	gpio_set_level(GPIO_PCH_PWRBTN_L, high);
}
コード例 #24
0
ファイル: charge_state_v1.c プロジェクト: longsleep/ec
/**
 * Prevent battery from going into deep discharge state
 */
static void low_battery_shutdown(struct charge_state_context *ctx)
{
	if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
		/* AP is off, so shut down the EC now */
		CPRINTS("charge force EC hibernate due to low battery");
		system_hibernate(0, 0);
	} else if (!ctx->shutdown_warning_time.val) {
		/* Warn AP battery level is so low we'll shut down */
		CPRINTS("charge warn shutdown due to low battery");
		ctx->shutdown_warning_time = get_time();
		host_set_single_event(EC_HOST_EVENT_BATTERY_SHUTDOWN);
	} else if (get_time().val > ctx->shutdown_warning_time.val +
		   LOW_BATTERY_SHUTDOWN_TIMEOUT_US) {
		/* Timeout waiting for AP to shut down, so kill it */
		CPRINTS("charge force shutdown due to low battery");
		chipset_force_shutdown();
	}
}
コード例 #25
0
ファイル: charge_state_v1.c プロジェクト: longsleep/ec
/**
 * Discharge state handler
 *
 *	- detect ac status
 *	- new state: INIT
 */
static enum charge_state state_discharge(struct charge_state_context *ctx)
{
	struct batt_params *batt = &ctx->curr.batt;
	int8_t bat_temp_c = DECI_KELVIN_TO_CELSIUS(batt->temperature);
	if (ctx->curr.ac)
		return PWR_STATE_REINIT;

	if (ctx->curr.error)
		return PWR_STATE_ERROR;

	/* Handle overtemp in discharging state by powering off host */
	if ((bat_temp_c >= ctx->battery->discharging_max_c ||
	     bat_temp_c < ctx->battery->discharging_min_c) &&
	    chipset_in_state(CHIPSET_STATE_ON)) {
		CPRINTS("charge force shutdown due to battery temp");
		chipset_force_shutdown();
		host_set_single_event(EC_HOST_EVENT_BATTERY_SHUTDOWN);
	}
	return PWR_STATE_UNCHANGE;
}
コード例 #26
0
void mkbp_send_event(uint8_t event_type)
{
	set_event(event_type);

#ifdef CONFIG_MKBP_WAKEUP_MASK
	/* checking the event if AP suspended */
	if (chipset_in_state(CHIPSET_STATE_SUSPEND)) {
		uint32_t events;
		events = *(uint32_t *)host_get_memmap(EC_MEMMAP_HOST_EVENTS);
		/*
		 * interrupt the AP if it is a wakeup event
		 * which is defined in the white list.
		 */
		if ((events & CONFIG_MKBP_WAKEUP_MASK) ||
		    (event_type == EC_MKBP_EVENT_KEY_MATRIX))
			set_host_interrupt(1);

		return;
	}
#endif

	set_host_interrupt(1);
}
コード例 #27
0
ファイル: led.c プロジェクト: coreboot/chrome-ec
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 */
	}
}
コード例 #28
0
static int calc_next_state(int state)
{
	struct batt_params batt;
	int alarm;

	battery_get_params_and_save_a_copy(&batt);

	switch (state) {
	case ST_IDLE0:
	case ST_BAD_COND:
	case ST_IDLE:
		/* Check AC and chiset state */
		if (!extpower_is_present()) {
			if (chipset_in_state(CHIPSET_STATE_ON))
				return ST_DISCHARGING;
			return ST_IDLE;
		}

		/* Stay in idle mode if charger overtemp */
		if (pmu_is_charger_alarm())
			return ST_BAD_COND;

		/* Enable charging when battery doesn't respond */
		if (!(batt.flags & BATT_FLAG_RESPONSIVE))
			return ST_PRE_CHARGING;

		/* Turn off charger when battery temperature is out
		 * of the start charging range.
		 */
		if (!battery_start_charging_range(batt.temperature))
			return ST_BAD_COND;

		/* Turn off charger on battery over temperature alarm */
		if (battery_status(&alarm) || (alarm & ALARM_OVER_TEMP))
			return ST_BAD_COND;

		/* Stop charging if the battery says it's charged */
		if (alarm & ALARM_CHARGED)
			return ST_IDLE;

		/* Start charging only when battery charge lower than 100% */
		if (!(batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE)) {
			if (batt.state_of_charge < 100)
				return ST_CHARGING;
		}

		return ST_IDLE;

	case ST_PRE_CHARGING:
		if (!extpower_is_present())
			return ST_IDLE0;

		/*
		 * If the battery goes online after enabling the charger, go
		 * into charging state.
		 */
		if (batt.flags & BATT_FLAG_RESPONSIVE) {
			if (!battery_start_charging_range(batt.temperature))
				return ST_IDLE0;
			if (!(batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE)) {
				if (batt.state_of_charge >= 100)
					return ST_IDLE0;
			}
			return ST_CHARGING;
		}

		return ST_PRE_CHARGING;

	case ST_CHARGING:
		/* Go back to idle state when AC is unplugged */
		if (!extpower_is_present())
			return ST_IDLE0;

		/*
		 * Disable charging on battery access error, or charging
		 * temperature out of range.
		 */
		if (!(batt.flags & BATT_FLAG_RESPONSIVE)) {
			CPRINTS("pmu charging: unable to get battery "
				"temperature");
			return ST_IDLE0;
		} else if (!battery_charging_range(batt.temperature)) {
			CPRINTS("pmu charging: temperature out of range "
				"%dC",
				DECI_KELVIN_TO_CELSIUS(batt.temperature));
			return ST_CHARGING_ERROR;
		}

		/*
		 * Disable charging on battery alarm events or access error:
		 *   - over temperature
		 *   - over current
		 */
		if (battery_status(&alarm))
			return ST_IDLE0;

		if (alarm & ALARM_OVER_TEMP) {
			CPRINTS("pmu charging: battery over temp");
			return ST_CHARGING_ERROR;
		}

		/* Go to idle state if battery is fully charged */
		if (alarm & ALARM_CHARGED)
			return ST_IDLE;

		/*
		 * Disable charging on charger alarm events:
		 *   - charger over current
		 *   - charger over temperature
		 */
		if (pmu_is_charger_alarm()) {
			CPRINTS("pmu charging: charger alarm");
			return ST_IDLE0;
		}

		return ST_CHARGING;

	case ST_CHARGING_ERROR:
		/*
		 * This state indicates AC is plugged but the battery is not
		 * charging. The conditions to exit this state:
		 *   - battery detected
		 *   - battery temperature is in start charging range
		 *   - no battery alarm
		 */
		if (extpower_is_present()) {
			if (battery_status(&alarm))
				return ST_CHARGING_ERROR;

			if (alarm & ALARM_OVER_TEMP)
				return ST_CHARGING_ERROR;

			if (!(batt.flags & BATT_FLAG_RESPONSIVE))
				return ST_CHARGING_ERROR;

			if (!battery_charging_range(batt.temperature))
				return ST_CHARGING_ERROR;

			return ST_CHARGING;
		}

		return ST_IDLE0;


	case ST_DISCHARGING:
		/* Go back to idle state when AC is plugged */
		if (extpower_is_present())
			return ST_IDLE0;

		/* Prepare EC sleep after system stopped discharging */
		if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
			return ST_IDLE0;

		/* Check battery discharging temperature range */
		if (batt.flags & BATT_FLAG_RESPONSIVE) {
			if (!battery_discharging_range(batt.temperature)) {
				CPRINTS("pmu discharging: temperature out of "
					"range %dC",
					DECI_KELVIN_TO_CELSIUS(
							batt.temperature));
				return system_off();
			}
		}
		/* Check discharging alarm */
		if (!battery_status(&alarm) && (alarm & ALARM_DISCHARGING)) {
			CPRINTS("pmu discharging: battery alarm %016b", alarm);
			return system_off();
		}
		/* Check remaining charge % */
		if (!(batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE)) {
			/*
			 * Shutdown AP when state of charge < 1.5%.
			 * Moving average is rounded to integer.
			 */
			if (rsoc_moving_average(batt.state_of_charge) < 2)
				return system_off();
			else if (batt.state_of_charge < 4)
				notify_battery_low();
		}

		return ST_DISCHARGING;
	}

	return ST_IDLE0;
}
コード例 #29
0
ファイル: charge_state_v2.c プロジェクト: coreboot/chrome-ec
/* Main loop */
void charger_task(void)
{
	int sleep_usec;
	int need_static = 1;
	const struct charger_info * const info = charger_get_info();

	/* Get the battery-specific values */
	batt_info = battery_get_info();

	prev_ac = prev_charge = -1;
	chg_ctl_mode = CHARGE_CONTROL_NORMAL;
	shutdown_warning_time.val = 0UL;
	battery_seems_to_be_dead = 0;

	/*
	 * If system is not locked and we don't have a battery to live on,
	 * then use max input current limit so that we can pull as much power
	 * as needed.
	 */
	battery_get_params(&curr.batt);
	prev_bp = curr.batt.is_present;
	curr.desired_input_current = get_desired_input_current(prev_bp, info);

	while (1) {

#ifdef CONFIG_SB_FIRMWARE_UPDATE
		if (sb_fw_update_in_progress()) {
			task_wait_event(CHARGE_MAX_SLEEP_USEC);
			continue;
		}
#endif

		/* Let's see what's going on... */
		curr.ts = get_time();
		sleep_usec = 0;
		problems_exist = 0;
		curr.ac = extpower_is_present();
		if (curr.ac != prev_ac) {
			if (curr.ac) {
				/*
				 * Some chargers are unpowered when the AC is
				 * off, so we'll reinitialize it when AC
				 * comes back and set the input current limit.
				 * Try again if it fails.
				 */
				int rv = charger_post_init();
				if (rv != EC_SUCCESS) {
					problem(PR_POST_INIT, rv);
				} else {
					if (curr.desired_input_current !=
					    CHARGE_CURRENT_UNINITIALIZED)
						rv = charger_set_input_current(
						    curr.desired_input_current);
					if (rv != EC_SUCCESS)
						problem(PR_SET_INPUT_CURR, rv);
					else
						prev_ac = curr.ac;
				}
			} else {
				/* Some things are only meaningful on AC */
				chg_ctl_mode = CHARGE_CONTROL_NORMAL;
				battery_seems_to_be_dead = 0;
				prev_ac = curr.ac;
			}
		}
		charger_get_params(&curr.chg);
		battery_get_params(&curr.batt);

		if (prev_bp != curr.batt.is_present) {
			prev_bp = curr.batt.is_present;

			/* Update battery info due to change of battery */
			batt_info = battery_get_info();
			need_static = 1;

			curr.desired_input_current =
				get_desired_input_current(prev_bp, info);
			if (curr.desired_input_current !=
			    CHARGE_CURRENT_UNINITIALIZED)
				charger_set_input_current(
					curr.desired_input_current);
			hook_notify(HOOK_BATTERY_SOC_CHANGE);
		}

		/*
		 * TODO(crosbug.com/p/27527). Sometimes the battery thinks its
		 * temperature is 6280C, which seems a bit high. Let's ignore
		 * anything above the boiling point of tungsten until this bug
		 * is fixed. If the battery is really that warm, we probably
		 * have more urgent problems.
		 */
		if (curr.batt.temperature > CELSIUS_TO_DECI_KELVIN(5660)) {
			CPRINTS("ignoring ridiculous batt.temp of %dC",
				 DECI_KELVIN_TO_CELSIUS(curr.batt.temperature));
			curr.batt.flags |= BATT_FLAG_BAD_TEMPERATURE;
		}

		/* If the battery thinks it's above 100%, don't believe it */
		if (curr.batt.state_of_charge > 100) {
			CPRINTS("ignoring ridiculous batt.soc of %d%%",
				curr.batt.state_of_charge);
			curr.batt.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE;
		}

		/*
		 * Now decide what we want to do about it. We'll normally just
		 * pass along whatever the battery wants to the charger. Note
		 * that if battery_get_params() can't get valid values from the
		 * battery it uses (0, 0), which is probably safer than blindly
		 * applying power to a battery we can't talk to.
		 */
		curr.requested_voltage = curr.batt.desired_voltage;
		curr.requested_current = curr.batt.desired_current;

		/* If we *know* there's no battery, wait for one to appear. */
		if (curr.batt.is_present == BP_NO) {
			ASSERT(curr.ac);	/* How are we running? */
			curr.state = ST_IDLE;
			curr.batt_is_charging = 0;
			battery_was_removed = 1;
			goto wait_for_it;
		}

		/*
		 * If we had trouble talking to the battery or the charger, we
		 * should probably do nothing for a bit, and if it doesn't get
		 * better then flag it as an error.
		 */
		if (curr.chg.flags & CHG_FLAG_BAD_ANY)
			problem(PR_CHG_FLAGS, curr.chg.flags);
		if (curr.batt.flags & BATT_FLAG_BAD_ANY)
			problem(PR_BATT_FLAGS, curr.batt.flags);

		/*
		 * If AC is present, check if input current is sufficient to
		 * actually charge battery.
		 */
		curr.batt_is_charging = curr.ac && (curr.batt.current >= 0);

		/* Don't let the battery hurt itself. */
		shutdown_on_critical_battery();

		if (!curr.ac) {
			curr.state = ST_DISCHARGE;
			goto wait_for_it;
		}

		/* Okay, we're on AC and we should have a battery. */

		/* Used for factory tests. */
		if (chg_ctl_mode != CHARGE_CONTROL_NORMAL) {
			curr.state = ST_IDLE;
			goto wait_for_it;
		}

		/* If the battery is not responsive, try to wake it up. */
		if (!(curr.batt.flags & BATT_FLAG_RESPONSIVE)) {
			if (battery_seems_to_be_dead || battery_is_cut_off()) {
				/* It's dead, do nothing */
				curr.state = ST_IDLE;
				curr.requested_voltage = 0;
				curr.requested_current = 0;
			} else if (curr.state == ST_PRECHARGE &&
				   (get_time().val > precharge_start_time.val +
				    PRECHARGE_TIMEOUT_US)) {
				/* We've tried long enough, give up */
				CPRINTS("battery seems to be dead");
				battery_seems_to_be_dead = 1;
				curr.state = ST_IDLE;
				curr.requested_voltage = 0;
				curr.requested_current = 0;
			} else {
				/* See if we can wake it up */
				if (curr.state != ST_PRECHARGE) {
					CPRINTS("try to wake battery");
					precharge_start_time = get_time();
					need_static = 1;
				}
				curr.state = ST_PRECHARGE;
				curr.requested_voltage =
					batt_info->voltage_max;
				curr.requested_current =
					batt_info->precharge_current;
			}
			goto wait_for_it;
		} else {
			/* The battery is responding. Yay. Try to use it. */
#ifdef CONFIG_BATTERY_REQUESTS_NIL_WHEN_DEAD
			/*
			 * TODO (crosbug.com/p/29467): remove this workaround
			 * for dead battery that requests no voltage/current
			 */
			if (curr.requested_voltage == 0 &&
			    curr.requested_current == 0 &&
			    curr.batt.state_of_charge == 0) {
				/* Battery is dead, give precharge current */
				curr.requested_voltage =
					batt_info->voltage_max;
				curr.requested_current =
					batt_info->precharge_current;
			} else
#endif
#ifdef CONFIG_BATTERY_REVIVE_DISCONNECT
			battery_seems_to_be_disconnected = 0;

			if (curr.requested_voltage == 0 &&
			    curr.requested_current == 0 &&
			    battery_get_disconnect_state() ==
			    BATTERY_DISCONNECTED) {
				/*
				 * Battery is in disconnect state. Apply a
				 * current to kick it out of this state.
				 */
				CPRINTS("found battery in disconnect state");
				curr.requested_voltage =
					batt_info->voltage_max;
				curr.requested_current =
					batt_info->precharge_current;
				battery_seems_to_be_disconnected = 1;
			} else
#endif
			if (curr.state == ST_PRECHARGE ||
			    battery_seems_to_be_dead ||
			    battery_was_removed) {
				CPRINTS("battery woke up");

				/* Update the battery-specific values */
				batt_info = battery_get_info();
				need_static = 1;
			    }

			battery_seems_to_be_dead = battery_was_removed = 0;
			curr.state = ST_CHARGE;
		}

		/*
		 * TODO(crosbug.com/p/27643): Quit trying if charging too long
		 * without getting full (CONFIG_CHARGER_TIMEOUT_HOURS).
		 */

wait_for_it:
#ifdef CONFIG_CHARGER_PROFILE_OVERRIDE
		sleep_usec = charger_profile_override(&curr);
		if (sleep_usec < 0)
			problem(PR_CUSTOM, sleep_usec);
#endif

		/* Keep the AP informed */
		if (need_static)
			need_static = update_static_battery_info();
		/* Wait on the dynamic info until the static info is good. */
		if (!need_static)
			update_dynamic_battery_info();
		notify_host_of_low_battery();

		/* And the EC console */
		is_full = calc_is_full();
		if ((!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) &&
		    curr.batt.state_of_charge != prev_charge) ||
		    (is_full != prev_full)) {
			show_charging_progress();
			prev_charge = curr.batt.state_of_charge;
			hook_notify(HOOK_BATTERY_SOC_CHANGE);
		}
		prev_full = is_full;

		/* Turn charger off if it's not needed */
		if (curr.state == ST_IDLE || curr.state == ST_DISCHARGE) {
			curr.requested_voltage = 0;
			curr.requested_current = 0;
		}

		/* Apply external limits */
		if (curr.requested_current > user_current_limit)
			curr.requested_current = user_current_limit;

		/* Round to valid values */
		curr.requested_voltage =
			charger_closest_voltage(curr.requested_voltage);
		curr.requested_current =
			charger_closest_current(curr.requested_current);

		/* Charger only accpets request when AC is on. */
		if (curr.ac) {
			/*
			 * Some batteries would wake up after cut-off if we keep
			 * charging it. Thus, we only charge when AC is on and
			 * battery is not cut off yet.
			 */
			if (battery_is_cut_off())
				charge_request(0, 0);
			/*
			 * As a safety feature, some chargers will stop
			 * charging if we don't communicate with it frequently
			 * enough. In manual mode, we'll just tell it what it
			 * knows.
			 */
			else if (manual_mode) {
				charge_request(curr.chg.voltage,
					       curr.chg.current);
			} else {
				charge_request(curr.requested_voltage,
					       curr.requested_current);
			}
		} else {
			charge_request(
				charger_closest_voltage(
				  curr.batt.voltage + info->voltage_step), -1);
		}

		/* How long to sleep? */
		if (problems_exist)
			/* If there are errors, don't wait very long. */
			sleep_usec = CHARGE_POLL_PERIOD_SHORT;
		else if (sleep_usec <= 0) {
			/* default values depend on the state */
			if (curr.state == ST_IDLE ||
			    curr.state == ST_DISCHARGE) {
				/* If AP is off, we can sleep a long time */
				if (chipset_in_state(CHIPSET_STATE_ANY_OFF |
						     CHIPSET_STATE_SUSPEND))
					sleep_usec =
						CHARGE_POLL_PERIOD_VERY_LONG;
				else
					/* Discharging, not too urgent */
					sleep_usec = CHARGE_POLL_PERIOD_LONG;
			} else {
				/* Charging, so pay closer attention */
				sleep_usec = CHARGE_POLL_PERIOD_CHARGE;
			}
		}

		/* Adjust for time spent in this loop */
		sleep_usec -= (int)(get_time().val - curr.ts.val);
		if (sleep_usec < CHARGE_MIN_SLEEP_USEC)
			sleep_usec = CHARGE_MIN_SLEEP_USEC;
		else if (sleep_usec > CHARGE_MAX_SLEEP_USEC)
			sleep_usec = CHARGE_MAX_SLEEP_USEC;

		task_wait_event(sleep_usec);
	}
}
コード例 #30
0
void charger_task(void)
{
	int next_state;
	int wait_time = T1_USEC;
	timestamp_t pre_chg_start = get_time();

	pmu_init();

	/* Enable low current charging */
	pmu_low_current_charging(1);

	/* Enable charger interrupt */
	gpio_enable_interrupt(GPIO_CHARGER_INT_L);

	/*
	 * EC STOP mode support
	 *   The charging loop can be stopped in idle state with AC unplugged.
	 *   Charging loop will be resumed by TPSCHROME interrupt.
	 */
	enable_charging(0);
	disable_sleep(SLEEP_MASK_CHARGING);

	while (1) {
		last_waken = get_time();
		pmu_clear_irq();

#ifdef CONFIG_PMU_TPS65090_CHARGING_LED
		update_battery_led();
#endif
		/*
		 * When battery is extremely low, the internal voltage can not
		 * power on its gas guage IC. Charging loop will enable the
		 * charger and turn on trickle charging. For safty reason,
		 * charger should be disabled if the communication to battery
		 * failed.
		 */
		if (current_state == ST_PRE_CHARGING &&
		    get_time().val - pre_chg_start.val >= PRE_CHARGING_TIMEOUT)
			next_state = ST_CHARGING_ERROR;
		else
			next_state = calc_next_state(current_state);

		if (next_state != current_state) {
			/* Reset state of charge moving average window */
			rsoc_moving_average(-1);

			CPRINTS("batt state %s -> %s",
				state_list[current_state],
				state_list[next_state]);

			current_state = next_state;

			switch (current_state) {
			case ST_PRE_CHARGING:
				pre_chg_start = get_time();
				/* Fall through */
			case ST_CHARGING:
				if (pmu_blink_led(0))
					next_state = ST_CHARGING_ERROR;
				else
					enable_charging(1);
				break;
			case ST_CHARGING_ERROR:
				/*
				 * Enable hardware charging circuit after set
				 * PMU to hardware error state.
				 */
				if (pmu_blink_led(1))
					enable_charging(0);
				else
					enable_charging(1);
				break;
			case ST_IDLE:
			case ST_IDLE0:
			case ST_BAD_COND:
			case ST_DISCHARGING:
				enable_charging(0);
				/* Ignore charger error when discharging */
				pmu_blink_led(0);
				break;
			}
		}

		switch (current_state) {
		case ST_CHARGING:
		case ST_CHARGING_ERROR:
			wait_time = T2_USEC;
			break;
		case ST_DISCHARGING:
			wait_time = T3_USEC;
			break;
		case ST_PRE_CHARGING:
			wait_time = T1_USEC;
			if (get_time().val - pre_chg_start.val >=
			    PRE_CHARGING_TIMEOUT)
				enable_charging(0);
			break;
		default:
			if (extpower_is_present()) {
				wait_time = T1_USEC;
				break;
			} else if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
				wait_time = T1_OFF_USEC;
				enable_sleep(SLEEP_MASK_CHARGING);
			} else if (chipset_in_state(CHIPSET_STATE_SUSPEND)) {
				wait_time = T1_SUSPEND_USEC;
			} else {
				wait_time = T1_USEC;
			}
		}

		if (!has_pending_event) {
			task_wait_event(wait_time);
			disable_sleep(SLEEP_MASK_CHARGING);
		} else {
			has_pending_event = 0;
		}
	}
}