/* Copyright 2017 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Power and battery LED control. */ #include "battery.h" #include "charge_manager.h" #include "charge_state.h" #include "chipset.h" #include "ec_commands.h" #include "gpio.h" #include "hooks.h" #include "host_command.h" #include "led_common.h" #include "system.h" #include "util.h" #define LED_ON 1 #define LED_OFF 0 #define LED_TOTAL_TICKS 20 #define LED_CHARGE_PULSE 10 #define LED_POWER_PULSE 15 const enum ec_led_id supported_led_ids[] = { EC_LED_ID_POWER_LED, EC_LED_ID_BATTERY_LED}; const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids); enum led_charge_state { LED_STATE_DISCHARGE = 0, LED_STATE_CHARGE, LED_STATE_FULL, LED_STATE_ERROR_PHASE0, LED_STATE_ERROR_PHASE1, LED_CHARGE_STATE_COUNT }; enum led_power_state { LED_STATE_S0 = 0, LED_STATE_S3_PHASE0, LED_STATE_S3_PHASE1, LED_STATE_S5, LED_POWER_STATE_COUNT }; static const struct { uint8_t led1:1; uint8_t led2:1; } led_chg_state_table[] = { [LED_STATE_DISCHARGE] = {LED_OFF, LED_OFF}, [LED_STATE_CHARGE] = {LED_OFF, LED_ON}, [LED_STATE_FULL] = {LED_ON, LED_OFF}, [LED_STATE_ERROR_PHASE0] = {LED_OFF, LED_OFF}, [LED_STATE_ERROR_PHASE1] = {LED_OFF, LED_ON} }; static const struct { uint8_t led:1; } led_pwr_state_table[] = { [LED_STATE_S0] = {LED_ON}, [LED_STATE_S3_PHASE0] = {LED_OFF}, [LED_STATE_S3_PHASE1] = {LED_ON}, [LED_STATE_S5] = {LED_OFF} }; void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range) { brightness_range[EC_LED_COLOR_WHITE] = 1; brightness_range[EC_LED_COLOR_GREEN] = 1; brightness_range[EC_LED_COLOR_AMBER] = 1; } int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness) { gpio_set_level(GPIO_PWR_LED, brightness[EC_LED_COLOR_WHITE]); gpio_set_level(GPIO_CHG_LED1, brightness[EC_LED_COLOR_GREEN]); gpio_set_level(GPIO_CHG_LED2, brightness[EC_LED_COLOR_AMBER]); return EC_SUCCESS; } void config_power_led(enum led_power_state state) { gpio_set_level(GPIO_PWR_LED, led_pwr_state_table[state].led); } void config_battery_led(enum led_charge_state state) { gpio_set_level(GPIO_CHG_LED1, led_chg_state_table[state].led1); gpio_set_level(GPIO_CHG_LED2, led_chg_state_table[state].led2); } static void rammus_led_set_power(void) { static unsigned int power_ticks; int chipset_state; chipset_state = chipset_in_state(CHIPSET_STATE_HARD_OFF) | (chipset_in_state(CHIPSET_STATE_SOFT_OFF) << 1) | (chipset_in_state(CHIPSET_STATE_SUSPEND) << 2) | (chipset_in_state(CHIPSET_STATE_ON) << 3) | (chipset_in_state(CHIPSET_STATE_STANDBY) << 4); switch (chipset_state) { case CHIPSET_STATE_ON: config_power_led(LED_STATE_S0); power_ticks = 0; break; case CHIPSET_STATE_SUSPEND: case CHIPSET_STATE_STANDBY: if ((power_ticks++ % LED_TOTAL_TICKS) < LED_POWER_PULSE) config_power_led(LED_STATE_S3_PHASE0); else config_power_led(LED_STATE_S3_PHASE1); break; case CHIPSET_STATE_HARD_OFF: case CHIPSET_STATE_SOFT_OFF: config_power_led(LED_STATE_S5); power_ticks = 0; break; default: break; } } static void rammus_led_set_battery(void) { enum charge_state chg_state = charge_get_state(); int charge_percent = charge_get_percent(); static unsigned int charge_ticks; /* CHIPSET_STATE_OFF */ switch (chg_state) { case PWR_STATE_DISCHARGE: if ((charge_get_flags() & CHARGE_FLAG_EXTERNAL_POWER) && charge_percent >= BATTERY_LEVEL_NEAR_FULL) config_battery_led(LED_STATE_FULL); else config_battery_led(LED_STATE_DISCHARGE); charge_ticks = 0; break; case PWR_STATE_CHARGE: config_battery_led(LED_STATE_CHARGE); charge_ticks = 0; break; case PWR_STATE_ERROR: if ((charge_ticks++ % LED_TOTAL_TICKS) < LED_CHARGE_PULSE) config_battery_led(LED_STATE_ERROR_PHASE0); else config_battery_led(LED_STATE_ERROR_PHASE1); break; case PWR_STATE_CHARGE_NEAR_FULL: case PWR_STATE_IDLE: if(charge_get_flags() & CHARGE_FLAG_EXTERNAL_POWER) config_battery_led(LED_STATE_FULL); else config_battery_led(LED_STATE_OFF); charge_ticks = 0; break; default: break; } } /** * Called by hook task every 200 ms */ static void led_tick(void) { if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) rammus_led_set_power(); if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) rammus_led_set_battery(); } DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT);