diff options
Diffstat (limited to 'zephyr/projects/trogdor/lazor/src/led.c')
-rw-r--r-- | zephyr/projects/trogdor/lazor/src/led.c | 271 |
1 files changed, 218 insertions, 53 deletions
diff --git a/zephyr/projects/trogdor/lazor/src/led.c b/zephyr/projects/trogdor/lazor/src/led.c index e4b34576c8..6921068aa0 100644 --- a/zephyr/projects/trogdor/lazor/src/led.c +++ b/zephyr/projects/trogdor/lazor/src/led.c @@ -14,14 +14,21 @@ #include "hooks.h" #include "host_command.h" #include "led_common.h" +#include "power.h" #include "system.h" #include "util.h" +#include <devicetree.h> +#include <logging/log.h> +LOG_MODULE_REGISTER(gpio_led, LOG_LEVEL_ERR); + #define LED_ONE_SEC (1000 / HOOK_TICK_INTERVAL_MS) #define BAT_LED_ON 1 #define BAT_LED_OFF 0 +#define GPIO_LED_NODE DT_PATH(gpio_led, gpio_led_colors) + const enum ec_led_id supported_led_ids[] = { EC_LED_ID_BATTERY_LED, }; @@ -61,67 +68,225 @@ int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness) return EC_SUCCESS; } -static void board_led_set_battery(void) +struct led_color_node_t { + int led_color; + int acc_period; +}; + +enum led_extra_flag_t { + NONE = 0, + LED_CHFLAG_FORCE_IDLE, + LED_CHFLAG_DEFAULT, + LED_BATT_BELOW_10_PCT, + LED_BATT_ABOVE_10_PCT, +}; + +/* + * Currently 4 different colors are supported for blinking LED, each of which + * can have different periods. Each period slot is the accumulation of previous + * periods as described below. Last slot is the total accumulation which is + * used as a dividing factor to calculate ticks to switch color + * Eg LED_COLOR_1 1 sec, LED_COLOR_2 2 sec, LED_COLOR_3 3 sec, LED_COLOR_4 3 sec + * period_1 = 1, period_2 = 1 + 2, period_3 = 1 + 2 + 3, period_4 =1 + 2 + 3 + 3 + * ticks -> 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2 and so on (ticks % 9) + * 0 < period_1 -> LED_COLOR_1 for 1 sec + * 1, 2 < period_2 -> LED_COLOR_2 for 2 secs + * 3, 4, 5 < period_3 -> LED_COLOR_3 for 3 secs + * 6, 7, 8 < period_4 -> LED_COLOR_4 for 3 secs + */ +#define MAX_COLOR 4 + +struct node_prop_t { + enum charge_state pwr_state; + enum power_state chipset_state; + enum led_extra_flag_t led_extra_flag; + struct led_color_node_t led_colors[MAX_COLOR]; +}; + +/* + * acc_period is the accumulated period value of all color-x children + * led_colors[0].acc_period = period value of color-0 node + * led_colors[1].acc_period = period value of color-0 + color-1 nodes + * led_colors[2].acc_period = period value of color-0 + color-1 + color-2 nodes + * and so on. If period prop or color node doesn't exist, period val is 0 + */ + +#define PERIOD_VAL(id) COND_CODE_1(DT_NODE_HAS_PROP(id, period), \ + (DT_PROP(id, period)), \ + (0)) + +#define LED_PERIOD(color_num, state_id) \ + PERIOD_VAL(DT_CHILD(state_id, color_##color_num)) + +#define LED_PLUS_PERIOD(color_num, state_id) \ + + LED_PERIOD(color_num, state_id) + +#define ACC_PERIOD(color_num, state_id) \ + (0 UTIL_LISTIFY(color_num, LED_PLUS_PERIOD, state_id)) + +#define GET_PROP(id, prop) \ + COND_CODE_1(DT_NODE_HAS_PROP(id, prop), \ + (DT_STRING_UPPER_TOKEN(id, prop)), \ + (0)) + +#define LED_COLOR_INIT(color_num, color_num_plus_one, state_id) \ +{ \ + .led_color = GET_PROP(DT_CHILD(state_id, color_##color_num), \ + led_color), \ + .acc_period = ACC_PERIOD(color_num_plus_one, state_id) \ +} + +/* Initialize node_array struct with prop listed in dts */ +#define SET_LED_VALUES(state_id) \ +{ \ + .pwr_state = GET_PROP(state_id, charge_state), \ + .chipset_state = GET_PROP(state_id, chipset_state), \ + .led_extra_flag = GET_PROP(state_id, extra_flag), \ + .led_colors = {LED_COLOR_INIT(0, 1, state_id), \ + LED_COLOR_INIT(1, 2, state_id), \ + LED_COLOR_INIT(2, 3, state_id), \ + LED_COLOR_INIT(3, 4, state_id), \ + } \ +}, + +struct node_prop_t node_array[] = { + DT_FOREACH_CHILD(GPIO_LED_NODE, SET_LED_VALUES) +}; + +static enum power_state get_chipset_state(void) { - static int battery_ticks; - int color = LED_OFF; - int period = 0; - uint32_t chflags = charge_get_flags(); + enum power_state chipset_state = 0; - battery_ticks++; + /* + * Only covers subset of power states as other states don't + * alter LED behavior + */ + if (chipset_in_state(CHIPSET_STATE_ON)) + /* S0 */ + chipset_state = POWER_S0; + else if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND)) + /* S3 */ + chipset_state = POWER_S3; + else if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) + /* S5 */ + chipset_state = POWER_S5; - switch (charge_get_state()) { - case PWR_STATE_CHARGE: - /* Always indicate amber on when charging. */ - color = LED_AMBER; - break; - case PWR_STATE_DISCHARGE: - if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND)) { - /* Discharging in S3: Amber 1 sec, off 3 sec */ - period = (1 + 3) * LED_ONE_SEC; - battery_ticks = battery_ticks % period; - if (battery_ticks < 1 * LED_ONE_SEC) - color = LED_AMBER; - else - color = LED_OFF; - } else if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) { - /* Discharging in S5: off */ - color = LED_OFF; - } else if (chipset_in_state(CHIPSET_STATE_ON)) { - /* Discharging in S0: Blue on */ - color = LED_BLUE; + return chipset_state; +} + +static bool find_node_with_extra_flag(int i) +{ + uint32_t chflags = charge_get_flags(); + bool found_node = false; + + switch (node_array[i].led_extra_flag) { + case LED_CHFLAG_FORCE_IDLE: + case LED_CHFLAG_DEFAULT: + if (chflags & CHARGE_FLAG_FORCE_IDLE) { + if (node_array[i].led_extra_flag == + LED_CHFLAG_FORCE_IDLE) + found_node = true; + } else { + if (node_array[i].led_extra_flag == LED_CHFLAG_DEFAULT) + found_node = true; } break; - case PWR_STATE_ERROR: - /* Battery error: Amber 1 sec, off 1 sec */ - period = (1 + 1) * LED_ONE_SEC; - battery_ticks = battery_ticks % period; - if (battery_ticks < 1 * LED_ONE_SEC) - color = LED_AMBER; - else - color = LED_OFF; - break; - case PWR_STATE_CHARGE_NEAR_FULL: - /* Full Charged: Blue on */ - color = LED_BLUE; - break; - case PWR_STATE_IDLE: /* External power connected in IDLE */ - if (chflags & CHARGE_FLAG_FORCE_IDLE) { - /* Factory mode: Blue 2 sec, Amber 2 sec */ - period = (2 + 2) * LED_ONE_SEC; - battery_ticks = battery_ticks % period; - if (battery_ticks < 2 * LED_ONE_SEC) - color = LED_BLUE; - else - color = LED_AMBER; - } else - color = LED_BLUE; + case LED_BATT_BELOW_10_PCT: + case LED_BATT_ABOVE_10_PCT: + if (charge_get_percent() < 10) { + if (node_array[i].led_extra_flag == + LED_BATT_BELOW_10_PCT) + found_node = true; + } else { + if (node_array[i].led_extra_flag != + LED_BATT_ABOVE_10_PCT) + found_node = true; + } break; default: - /* Other states don't alter LED behavior */ + LOG_ERR("Invalid led extra flag %d", + node_array[i].led_extra_flag); break; } + return found_node; +} + +static int find_node(void) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(node_array); i++) { + /* Check if this node depends on power state */ + if (node_array[i].pwr_state != PWR_STATE_UNCHANGE) { + enum charge_state pwr_state = charge_get_state(); + + if (node_array[i].pwr_state != pwr_state) + continue; + } + + /* Check if this node depends on chipset state */ + if (node_array[i].chipset_state != 0) { + enum power_state chipset_state = + get_chipset_state(); + + /* Continue at current index as nodes are in sequence */ + if (node_array[i].chipset_state != chipset_state) + continue; + } + + /* Check if the node depends on any special flags */ + if (node_array[i].led_extra_flag != NONE) + if (!find_node_with_extra_flag(i)) + continue; + + /* We found the node */ + return i; + } + + /* + * Didn't find a valid node that matches all the properties + * Return -1 to signify error + */ + return -1; +} + +#define GET_PERIOD(n_idx, c_idx) node_array[n_idx].led_colors[c_idx].acc_period +#define GET_COLOR(n_idx, c_idx) node_array[n_idx].led_colors[c_idx].led_color + +static int find_color(int node_idx, int ticks) +{ + int color_idx = 0; + + /* If period value at index 0 is not 0, it's a blinking LED */ + if (GET_PERIOD(node_idx, 0) != 0) { + /* Period is accumulated at the last index */ + ticks = ticks % GET_PERIOD(node_idx, MAX_COLOR - 1); + + for (color_idx = 0; color_idx < MAX_COLOR; color_idx++) { + if (GET_PERIOD(node_idx, color_idx) < ticks) + break; + } + } + + return GET_COLOR(node_idx, color_idx); +} + +static void board_led_set_color(void) +{ + int color = LED_OFF; + int node = 0; + static int ticks; + + ticks++; + + node = find_node(); + + if (node < 0) + LOG_ERR("Invalid node id, node with matching prop not found"); + else + color = find_color(node, ticks); + led_set_color(color); } @@ -129,7 +294,7 @@ static void board_led_set_battery(void) static void led_tick(void) { if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) - board_led_set_battery(); + board_led_set_color(); } DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT); @@ -143,7 +308,7 @@ void led_control(enum ec_led_id led_id, enum ec_led_state state) if (state == LED_STATE_RESET) { led_auto_control(EC_LED_ID_BATTERY_LED, 1); - board_led_set_battery(); + board_led_set_color(); return; } |