summaryrefslogtreecommitdiff
path: root/zephyr/projects/trogdor/lazor/src/led.c
diff options
context:
space:
mode:
Diffstat (limited to 'zephyr/projects/trogdor/lazor/src/led.c')
-rw-r--r--zephyr/projects/trogdor/lazor/src/led.c271
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;
}