summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorreno.wang <reno.wang@lcfc.corp-partner.google.com>2021-03-06 04:19:44 +0800
committerCommit Bot <commit-bot@chromium.org>2021-04-05 20:08:42 +0000
commitfa0de6bceebfe97fe2f07ddcfba5d68e484bb246 (patch)
tree7824a9b42e3fa7dbb7f89caf4840465273cde32d
parent7230929bc18d3354504eeda5caed1be947258090 (diff)
downloadchrome-ec-fa0de6bceebfe97fe2f07ddcfba5d68e484bb246.tar.gz
Lindar: Lindar's lightbar support in S0ix/S3
1. Lid is closed, lightbar keep off 2. Lid is opened, its behavior follow below. AC+Battery < 20%, lightbar solid 2 amber led on. AC+Battery < 40%, lightbar solid 4 amber led on. AC+Battery < 60%, lightbar solid 6 amber led on. AC+Battery < 80%, lightbar solid 8 amber led on. AC+Battery < 97%, lightbar solid 10 amber led on. AC+Battery >= 97%, lightbar solid 10 green led on. Battery only >= 15%, lightbar keep off. Battery low < 15%, lightbar blink amber color, 1s on, 5s off. 3. Some SKU un-support lightbar, and shouldn't run lightbar task. 4. Lightbar is powered by PP3300_A, and shouldn't run it in S4/S5/G3. 5. Add debounce time for lightbar state change. BUG=b:174133147 BRANCH=firmware-volteer-13672.B-main TEST=make buildall, test lightbar behavior in S0ix/S3. Signed-off-by: reno.wang <reno.wang@lcfc.corp-partner.google.com> Change-Id: Ibbdc17627f7b2d1b2abbbad23b6c06024455e66b Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2803991 Reviewed-by: Abe Levkoy <alevkoy@chromium.org> Commit-Queue: Abe Levkoy <alevkoy@chromium.org>
-rw-r--r--board/lindar/board.c12
-rw-r--r--board/lindar/board.h1
-rw-r--r--board/lindar/ktd20xx.h141
-rw-r--r--board/lindar/led.c328
4 files changed, 480 insertions, 2 deletions
diff --git a/board/lindar/board.c b/board/lindar/board.c
index c65421b08b..57d9fdeb14 100644
--- a/board/lindar/board.c
+++ b/board/lindar/board.c
@@ -91,6 +91,18 @@ static void board_init(void)
}
DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
+int board_is_i2c_port_powered(int port)
+{
+ if (port != I2C_PORT_LIGHTBAR)
+ return 1;
+
+ /*
+ * Lightbar rails are off in S5/G3
+ * Refer CL-2739008.
+ */
+ return chipset_in_state(CHIPSET_STATE_ANY_OFF) ? 0 : 1;
+}
+
int board_is_lid_angle_tablet_mode(void)
{
return ec_cfg_has_tabletmode();
diff --git a/board/lindar/board.h b/board/lindar/board.h
index 17c6fea8ff..2b78c25249 100644
--- a/board/lindar/board.h
+++ b/board/lindar/board.h
@@ -118,6 +118,7 @@
/* I2C Bus Configuration */
#define CONFIG_I2C
+#define CONFIG_I2C_BUS_MAY_BE_UNPOWERED
#define I2C_PORT_SENSOR NPCX_I2C_PORT0_0
#define I2C_PORT_USB_C0 NPCX_I2C_PORT1_0
#define I2C_PORT_USB_C1 NPCX_I2C_PORT2_0
diff --git a/board/lindar/ktd20xx.h b/board/lindar/ktd20xx.h
new file mode 100644
index 0000000000..ad93ee3de8
--- /dev/null
+++ b/board/lindar/ktd20xx.h
@@ -0,0 +1,141 @@
+/* Copyright 2021 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.
+ *
+ * Public header for Kinetic 36-Channel RGB LED Drivers with I2C control,
+ * including KTD2061/58/59/60.
+ */
+
+#ifndef __CROS_EC_DRIVER_RGB_LED_DRIVER_KTD20XX_PUBLIC_H
+#define __CROS_EC_DRIVER_RGB_LED_DRIVER_KTD20XX_PUBLIC_H
+
+/*
+ * KTD20xx Register Definition
+ *
+ * Reg0x00: ID Data Register
+ * skip...
+ * Reg0x01: MONITOR Status Register
+ * skip...
+ * Reg0x02: CONTROL Configuration Register
+ * BIT7:6 is EN_MODE[1:0]
+ * 00 = global off, 01 = Night mode,
+ * 10 = Normal mode, 11 = reset as default
+ * BIT5 is BrightExtendTM Enable
+ * 0 = disable/1 = enable
+ * BIT4:3 is CoolExtendTM Temperature Setting
+ * 00 = 135°C rising, 01 = 120°C
+ * 10 = 105°C, 11 = 90°C
+ * BIT2:0 is Fade Rate Exponential Time-Constant Setting
+ * 000 = 31ms, 001 = 63ms, 010 = 125ms, 011 = 250ms
+ * 100 = 500ms, 101 = 1s, 110 = 2s, 111 = 4s
+ *
+ * Reg0x03: IRED0 Color Configuration Register
+ * IRED_SET0[7:0] Red Current Setting 0
+ * 0000 0000 = 0μA
+ * 0000 0001 = 125μA
+ * ...
+ * 0010 1000 = 5mA
+ * ...
+ * 1100 0000 = 24mA
+ * 1100 0001 = 24mA (reads back as 1100 0000)
+ * ...
+ * 1111 1111 = 24mA (reads back as 1100 0000)
+ * Reg0x04: IGRN0 Color Configuration Register
+ * IGRN_SET0[7:0] Green Current Setting 0
+ * Reg0x05: IBLU0 Color Configuration Register
+ * IBLU_SET0[7:0] Blue Current Setting 0
+ * Reg0x06: IRED1 Color Configuration Register
+ * IRED_SET1[7:0] Red Current Setting 1
+ * Reg0x07: IGRN1 Color Configuration Register
+ * IGRN_SET1[7:0] Green Current Setting 1
+ * Reg0x08: IBLU1 Color Configuration Register
+ * IBLU_SET1[7:0] Blue Current Setting 1
+ *
+ * Reg0x09: ISELA12 Selection Configuration Register
+ * BIT7 is ENA1, Enable RGB with anode connected to LEDA1 pin
+ * 0 = use 0μA for these LEDs (includes fade to 0μA)
+ * 1 = use the settings selected by RGBA1_SEL[2:0]
+ * BIT6:4 is RGBA1_SEL[2:0]
+ * Current Selection for RGB with anode connected to LEDA1 pin
+ * 0XX = I LEDA3 selects IRED_SET0[7:0]
+ * 1XX = I LEDA3 selects IRED_SET1[7:0]
+ * X0X = I LEDA2 selects IGRN_SET0[7:0]
+ * X1X = I LEDA2 selects IGRN_SET1[7:0]
+ * XX0 = I LEDA4 selects IBLU_SET0[7:0]
+ * XX1 = I LEDA4 selects IBLU_SET1[7:0]
+ * BIT3 IS ENA2
+ * 0 = use 0μA for these LEDs (includes fade to 0μA)
+ * 1 = use the settings selected by RGBA2_SEL[2:0]
+ * BIT2:0 is RGBA2_SEL[2:0]
+ * Current Selection for RGB with anode connected to LEDA2 pin
+ * 0XX = I LEDA4 selects IRED_SET0[7:0]
+ * 1XX = I LEDA4 selects IRED_SET1[7:0]
+ * X0X = I LEDA3 selects IGRN_SET0[7:0]
+ * X1X = I LEDA3 selects IGRN_SET1[7:0]
+ * XX0 = I LEDA1 selects IBLU_SET0[7:0]
+ * XX1 = I LEDA1 selects IBLU_SET1[7:0]
+ * Reg0x0A: ISELA34 Selection Configuration Register
+ * BIT7 is ENA3, Enable RGB with anode connected to LEDA3 pin
+ * 0 = use 0μA for these LEDs (includes fade to 0μA)
+ * 1 = use the settings selected by RGBA3_SEL[2:0]
+ * BIT6:4 is RGBA3_SEL[2:0]
+ * Current Selection for RGB with anode connected to LEDA3 pin
+ * 0XX = I LEDA1 selects IRED_SET0[7:0]
+ * 1XX = I LEDA1 selects IRED_SET1[7:0]
+ * X0X = I LEDA4 selects IGRN_SET0[7:0]
+ * X1X = I LEDA4 selects IGRN_SET1[7:0]
+ * XX0 = I LEDA2 selects IBLU_SET0[7:0]
+ * XX1 = I LEDA2 selects IBLU_SET1[7:0]
+ * BIT3 IS ENA4
+ * 0 = use 0μA for these LEDs (includes fade to 0μA)
+ * 1 = use the settings selected by RGBA4_SEL[2:0]
+ * BIT2:0 is RGBA4_SEL[2:0]
+ * Current Selection for RGB with anode connected to LEDA4 pin
+ * 0XX = I LEDA2 selects IRED_SET0[7:0]
+ * 1XX = I LEDA2 selects IRED_SET1[7:0]
+ * X0X = I LEDA1 selects IGRN_SET0[7:0]
+ * X1X = I LEDA1 selects IGRN_SET1[7:0]
+ * XX0 = I LEDA3 selects IBLU_SET0[7:0]
+ * XX1 = I LEDA3 selects IBLU_SET1[7:0]
+ * Reg0x0B: ISELB12 Selection Configuration Register
+ * BIT7 is ENB1, Enable RGB with anode connected to LEDB1 pin
+ * 0 = use 0μA for these LEDs (includes fade to 0μA)
+ * 1 = use the settings selected by RGB1_SEL[2:0]
+ * BIT6:4 is RGBB1_SEL[2:0]
+ * Current Selection for RGB with anode connected to LEDB1 pin
+ * 0XX = I LEDB3 selects IRED_SET0[7:0]
+ * 1XX = I LEDB3 selects IRED_SET1[7:0]
+ * X0X = I LEDB2 selects IGRN_SET0[7:0]
+ * X1X = I LEDB2 selects IGRN_SET1[7:0]
+ * XX0 = I LEDB4 selects IBLU_SET0[7:0]
+ * XX1 = I LEDB4 selects IBLU_SET1[7:0]
+ * BIT3 IS ENB2
+ * ...
+ * Reg0x0C: ISELB34 Selection Configuration Register
+ * ...
+ * Reg0x0D: ISELC12 Selection Configuration Register
+ * ...
+ * Reg0x0E: ISELC34 Selection Configuration Register
+ * ...
+ */
+
+enum ktd20xx_register {
+ KTD20XX_ID_DATA = 0x00,
+ KTD20XX_STATUS_REG = 0x01,
+ KTD20XX_CTRL_CFG = 0x02,
+ KTD20XX_IRED_SET0 = 0x03,
+ KTD20XX_IGRN_SET0 = 0x04,
+ KTD20XX_IBLU_SET0 = 0x05,
+ KTD20XX_IRED_SET1 = 0x06,
+ KTD20XX_IGRN_SET1 = 0x07,
+ KTD20XX_IBLU_SET1 = 0x08,
+ KTD20XX_ISEL_A12 = 0x09,
+ KTD20XX_ISEL_A34 = 0x0A,
+ KTD20XX_ISEL_B12 = 0x0B,
+ KTD20XX_ISEL_B34 = 0x0C,
+ KTD20XX_ISEL_C12 = 0x0D,
+ KTD20XX_ISEL_C34 = 0x0E,
+ KTD20XX_TOTOAL_REG
+};
+
+#endif /* __CROS_EC_DRIVER_RGB_LED_DRIVER_KTD20XX_PUBLIC_H */
diff --git a/board/lindar/led.c b/board/lindar/led.c
index 0b65213052..890f309842 100644
--- a/board/lindar/led.c
+++ b/board/lindar/led.c
@@ -5,10 +5,23 @@
* Power and battery LED control for Malefor
*/
+#include "charge_state.h"
#include "common.h"
-#include "led_onoff_states.h"
-#include "led_common.h"
+#include "cros_board_info.h"
+#include "extpower.h"
#include "gpio.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "ktd20xx.h"
+#include "led_common.h"
+#include "led_onoff_states.h"
+#include "lid_switch.h"
+#include "stdbool.h"
+#include "task.h"
+#include "timer.h"
+
+#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args)
#define LED_OFF_LVL 1
#define LED_ON_LVL 0
@@ -109,3 +122,314 @@ int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness)
return EC_SUCCESS;
}
+
+static const uint16_t lightbar_i2c_addr = 0x68;
+static void controller_write(uint8_t reg, uint8_t val)
+{
+ uint8_t buf[2];
+
+ buf[0] = reg;
+ buf[1] = val;
+
+ i2c_xfer_unlocked(I2C_PORT_LIGHTBAR, lightbar_i2c_addr,
+ buf, 2, 0, 0,
+ I2C_XFER_SINGLE);
+}
+
+enum lightbar_states {
+ LB_STATE_OFF,
+ LB_STATE_LID_CLOSE,
+ LB_STATE_AC_ONLY,
+ LB_STATE_AC_BAT_LOW,
+ LB_STATE_AC_BAT_20,
+ LB_STATE_AC_BAT_40,
+ LB_STATE_AC_BAT_60,
+ LB_STATE_AC_BAT_80,
+ LB_STATE_AC_BAT_100,
+ LB_STATE_BAT_LOW,
+ LB_STATE_BAT_ONLY,
+ LB_NUM_STATES
+};
+
+/*
+ * All lightbar states should have one phase defined,
+ * and an additional phase can be defined for blinking
+ */
+enum lightbar_phase {
+ LIGHTBAR_PHASE_0 = 0,
+ LIGHTBAR_PHASE_1 = 1,
+ LIGHTBAR_NUM_PHASES
+};
+
+enum ec_lightbar_colors {
+ BAR_RESET = 0x00,
+ BAR_OFF = 0x01,
+ BAR_COLOR_ORG_20_PERCENT = 0x02,
+ BAR_COLOR_ORG_40_PERCENT = 0x03,
+ BAR_COLOR_ORG_60_PERCENT = 0x04,
+ BAR_COLOR_ORG_80_PERCENT = 0x05,
+ BAR_COLOR_ORG_FULL = 0x06,
+ BAR_COLOR_GRN_FULL = 0x07,
+ LIGHTBAR_COLOR_TOTAL
+};
+
+struct lightbar_descriptor {
+ enum ec_lightbar_colors color;
+ uint8_t ticks;
+};
+
+#define BAR_INFINITE UINT8_MAX
+#define LIGHTBAR_ONE_SEC (1000 / HOOK_TICK_INTERVAL_MS)
+const struct lightbar_descriptor
+ lb_table[LB_NUM_STATES][LIGHTBAR_NUM_PHASES] = {
+ [LB_STATE_OFF] = {{BAR_OFF, BAR_INFINITE} },
+ [LB_STATE_LID_CLOSE] = {{BAR_OFF, BAR_INFINITE} },
+ [LB_STATE_AC_ONLY] = {{BAR_OFF, BAR_INFINITE} },
+ [LB_STATE_AC_BAT_LOW] = {{BAR_COLOR_ORG_20_PERCENT, BAR_INFINITE} },
+ [LB_STATE_AC_BAT_20] = {{BAR_COLOR_ORG_40_PERCENT, BAR_INFINITE} },
+ [LB_STATE_AC_BAT_40] = {{BAR_COLOR_ORG_60_PERCENT, BAR_INFINITE} },
+ [LB_STATE_AC_BAT_60] = {{BAR_COLOR_ORG_80_PERCENT, BAR_INFINITE} },
+ [LB_STATE_AC_BAT_80] = {{BAR_COLOR_ORG_FULL, BAR_INFINITE} },
+ [LB_STATE_AC_BAT_100] = {{BAR_COLOR_GRN_FULL, BAR_INFINITE} },
+ [LB_STATE_BAT_LOW] = {{BAR_OFF, 5*LIGHTBAR_ONE_SEC},
+ {BAR_COLOR_ORG_FULL, LIGHTBAR_ONE_SEC} },
+ [LB_STATE_BAT_ONLY] = {{BAR_OFF, BAR_INFINITE} },
+};
+
+/*
+ * From EE's information, lindar only support two colors lightbar,
+ * Orange (Amber) and Green. And they connect KTD20xx's red color
+ * channel to orange color led, and green color
+ * channel to green color led.
+ * Blue color channel is unused.
+ */
+#define DISABLE_LIGHTBAR 0x00
+#define ENABLE_LIGHTBAR 0x80
+#define I_OFF 0x00
+#define I_ON 0x02
+#define SEL_OFF 0x00
+#define SEL_1ST_LED BIT(7)
+#define SEL_2ND_LED BIT(3)
+#define SEL_BOTH (SEL_1ST_LED | SEL_2ND_LED)
+#define SKU_ID_NONE 0x00
+#define SKU_ID_INVALID 0x01
+#define LB_SUPPORTED_SKUID_LOWER 458700
+#define LB_SUPPORTED_SKUID_UPPER 458800
+
+static bool lightbar_is_supported(void)
+{
+ static uint32_t skuid = SKU_ID_NONE;
+ bool result;
+
+ /*
+ * TODO(b/183826778):
+ * [Lillipup/Lindar] Move to SSFC/FW_CONFIG for lightbar supporting
+ * check
+ */
+ if (skuid == SKU_ID_NONE) {
+ if (cbi_get_sku_id(&skuid)) {
+ CPRINTS("Cannot get skuid for lightbar supported");
+ skuid = SKU_ID_INVALID;
+ }
+ }
+ if (skuid >= LB_SUPPORTED_SKUID_LOWER &&
+ skuid <= LB_SUPPORTED_SKUID_UPPER)
+ result = true;
+ else
+ result = false;
+ return result;
+}
+
+/*
+ * Todo.
+ * Maybe, we need to provide some command to tool kit to test lightbar
+ * in factory. So, it may need a way to stop lightbar_update().
+ */
+static bool lightbar_is_enabled(void)
+{
+ if (!lightbar_is_supported())
+ return false;
+
+ /*
+ * Lightbar's I2C is powered by PP3300_A, and its power will be turn
+ * when system enter S4/S5. It may get I2C error if EC keep polling
+ * lightbar. We should stop it when EC doesn't turn on PP330_A.
+ */
+ if (!board_is_i2c_port_powered(I2C_PORT_LIGHTBAR))
+ return false;
+
+ return true;
+}
+
+const uint8_t lightbar_ctrl[LIGHTBAR_COLOR_TOTAL][KTD20XX_TOTOAL_REG] = {
+ [BAR_RESET] = {
+ 0x00, 0x00, DISABLE_LIGHTBAR,
+ I_OFF, I_OFF, I_OFF, I_OFF, I_OFF, I_OFF,
+ SEL_OFF, SEL_OFF, SEL_OFF, SEL_OFF, SEL_OFF, SEL_OFF
+ },
+ [BAR_OFF] = {
+ 0x00, 0x00, DISABLE_LIGHTBAR,
+ I_OFF, I_OFF, I_OFF, I_OFF, I_OFF, I_OFF,
+ SEL_OFF, SEL_OFF, SEL_OFF, SEL_OFF, SEL_OFF, SEL_OFF
+ },
+ [BAR_COLOR_ORG_20_PERCENT] = {
+ 0x00, 0x00, ENABLE_LIGHTBAR,
+ I_ON, I_OFF, I_OFF, I_OFF, I_OFF, I_OFF,
+ SEL_BOTH, SEL_OFF, SEL_OFF, SEL_OFF, SEL_OFF, SEL_OFF
+ },
+ [BAR_COLOR_ORG_40_PERCENT] = {
+ 0x00, 0x00, ENABLE_LIGHTBAR,
+ I_ON, I_OFF, I_OFF, I_OFF, I_OFF, I_OFF,
+ SEL_BOTH, SEL_BOTH, SEL_OFF, SEL_OFF, SEL_OFF, SEL_OFF
+ },
+ [BAR_COLOR_ORG_60_PERCENT] = {
+ 0x00, 0x00, ENABLE_LIGHTBAR,
+ I_ON, I_OFF, I_OFF, I_OFF, I_OFF, I_OFF,
+ SEL_BOTH, SEL_BOTH, SEL_BOTH, SEL_OFF, SEL_OFF, SEL_OFF
+ },
+ [BAR_COLOR_ORG_80_PERCENT] = {
+ 0x00, 0x00, ENABLE_LIGHTBAR,
+ I_ON, I_OFF, I_OFF, I_OFF, I_OFF, I_OFF,
+ SEL_BOTH, SEL_BOTH, SEL_BOTH, SEL_BOTH, SEL_OFF, SEL_OFF
+ },
+ [BAR_COLOR_ORG_FULL] = {
+ 0x00, 0x00, ENABLE_LIGHTBAR,
+ I_ON, I_OFF, I_OFF, I_OFF, I_OFF, I_OFF,
+ SEL_BOTH, SEL_BOTH, SEL_BOTH, SEL_BOTH, SEL_BOTH, SEL_OFF
+ },
+ [BAR_COLOR_GRN_FULL] = {
+ 0x00, 0x00, ENABLE_LIGHTBAR,
+ I_OFF, I_ON, I_OFF, I_OFF, I_OFF, I_OFF,
+ SEL_BOTH, SEL_BOTH, SEL_BOTH, SEL_BOTH, SEL_BOTH, SEL_OFF
+ }
+};
+
+static void lightbar_set_color(enum ec_lightbar_colors color)
+{
+ enum ktd20xx_register i;
+
+ if (color >= LIGHTBAR_COLOR_TOTAL) {
+ CPRINTS("Lightbar Error! Incorrect lightbard color %d", color);
+ color = BAR_RESET;
+ }
+
+ i2c_lock(I2C_PORT_LIGHTBAR, 1);
+ for (i = KTD20XX_IRED_SET0; i <= KTD20XX_ISEL_C34; i++)
+ controller_write(i, lightbar_ctrl[color][i]);
+
+ controller_write(KTD20XX_CTRL_CFG,
+ lightbar_ctrl[color][KTD20XX_CTRL_CFG]);
+
+ i2c_lock(I2C_PORT_LIGHTBAR, 0);
+}
+
+static void lightbar_init(void)
+{
+ if (!lightbar_is_enabled())
+ return;
+
+ lightbar_set_color(BAR_RESET);
+}
+
+DECLARE_HOOK(HOOK_CHIPSET_STARTUP, lightbar_init, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, lightbar_init, HOOK_PRIO_DEFAULT);
+
+const int lightbar_bat_low = 15;
+static enum lightbar_states lightbar_get_state(void)
+{
+ enum lightbar_states new_state = LB_NUM_STATES;
+ int cur_bat_percent;
+
+ cur_bat_percent = charge_get_percent();
+
+ if (!chipset_in_state(CHIPSET_STATE_ANY_SUSPEND))
+ return LB_STATE_OFF;
+
+ if (!lid_is_open())
+ return LB_STATE_LID_CLOSE;
+
+ if (extpower_is_present()) {
+ if (charge_get_display_charge()) {
+ if (cur_bat_percent < 20)
+ new_state = LB_STATE_AC_BAT_LOW;
+ else if (cur_bat_percent < 40)
+ new_state = LB_STATE_AC_BAT_20;
+ else if (cur_bat_percent < 60)
+ new_state = LB_STATE_AC_BAT_40;
+ else if (cur_bat_percent < 80)
+ new_state = LB_STATE_AC_BAT_60;
+ else if (cur_bat_percent < 97)
+ new_state = LB_STATE_AC_BAT_80;
+ else
+ new_state = LB_STATE_AC_BAT_100;
+ } else
+ new_state = LB_STATE_AC_ONLY;
+ } else {
+ if (cur_bat_percent < lightbar_bat_low)
+ new_state = LB_STATE_BAT_LOW;
+ else
+ new_state = LB_STATE_BAT_ONLY;
+ }
+
+ return new_state;
+}
+
+#define LIGHTBAR_DEBOUNCE_TICKS 1
+static void lightbar_update(void)
+{
+ static uint8_t ticks, period;
+ static enum lightbar_states lb_cur_state = LB_NUM_STATES;
+ static int debounce_lightbar_state_update;
+ enum lightbar_states desired_state;
+ int phase;
+
+ if (!lightbar_is_enabled())
+ return;
+
+ desired_state = lightbar_get_state();
+ if (desired_state != lb_cur_state &&
+ desired_state < LB_NUM_STATES) {
+ /* State is changing */
+ lb_cur_state = desired_state;
+ /* Reset ticks and period when state changes */
+ ticks = 0;
+
+ period = lb_table[lb_cur_state][LIGHTBAR_PHASE_0].ticks +
+ lb_table[lb_cur_state][LIGHTBAR_PHASE_1].ticks;
+
+ /*
+ * System will be waken up when AC status change in S0ix. Due to
+ * EC may be late to update chipset state and cause lightbar
+ * flash a while when system transfer to S0. We add to debounce
+ * for any lightbar status change.
+ * It can make sure lightbar state is ready to to update.
+ */
+ debounce_lightbar_state_update = LIGHTBAR_DEBOUNCE_TICKS;
+ }
+
+ /* If this state is undefined, turn lightbar off */
+ if (period == 0) {
+ CPRINTS("Undefined lightbar behavior for lightbar state %d,"
+ "turning off lightbar", lb_cur_state);
+ lightbar_set_color(BAR_OFF);
+ return;
+ }
+
+ if (debounce_lightbar_state_update != 0) {
+ debounce_lightbar_state_update--;
+ return;
+ }
+
+ /*
+ * Determine which phase of the state table to use. The phase is
+ * determined if it falls within first phase time duration.
+ */
+ phase = ticks < lb_table[lb_cur_state][LIGHTBAR_PHASE_0].ticks ? 0 : 1;
+ ticks = (ticks + 1) % period;
+
+ /* Set the color for the given state and phase */
+ lightbar_set_color(lb_table[lb_cur_state][phase].color);
+
+}
+
+DECLARE_HOOK(HOOK_TICK, lightbar_update, HOOK_PRIO_DEFAULT);