From 0f5d89e24b7ab6bfe464affaaf2be905520d4f6a Mon Sep 17 00:00:00 2001 From: Zick Wei Date: Wed, 7 Sep 2022 19:02:36 +0800 Subject: yaviks: update led behavior yaviks has charge leds on left side and right side, each side have two colors: amber and white. The led behavior define as following: Charging led: led on with charging port active, other port is off. Charging: Amber. Discharging: Off. Battery Error: Blinking amber on both side (0.5 sec on, 0.5 sec off) Fuel < 10%: Blinking amber on both side (1 sec on, 1 sec off) Force idle for factory: Blinking amber (1 sec on, 1 sec off) System suspend with non-charging state: Blinking both side LED white (1 sec on, 1 sec off) BUG=b:246414045 BRANCH=none TEST=verify led behavior as intended, verify VT2 command: ectool led left/right auto/white/amber/off. Signed-off-by: Zick Wei Change-Id: I7d7ecaba5f1a78609d9093b94b67a23a40d62812 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3878626 Commit-Queue: Andrew McRae Reviewed-by: Andrew McRae Code-Coverage: Andrew McRae Reviewed-by: Peter Marheine Reviewed-by: Devin Lu --- zephyr/projects/nissa/BUILD.py | 1 - zephyr/projects/nissa/CMakeLists.txt | 2 +- zephyr/projects/nissa/yaviks/gpio.dts | 12 ++ zephyr/projects/nissa/yaviks/overlay.dts | 6 +- zephyr/projects/nissa/yaviks/prj.conf | 3 + zephyr/projects/nissa/yaviks/pwm_leds.dts | 60 -------- zephyr/projects/nissa/yaviks/src/led.c | 231 ++++++++++++++++++++++++++++++ 7 files changed, 248 insertions(+), 67 deletions(-) delete mode 100644 zephyr/projects/nissa/yaviks/pwm_leds.dts create mode 100644 zephyr/projects/nissa/yaviks/src/led.c (limited to 'zephyr/projects') diff --git a/zephyr/projects/nissa/BUILD.py b/zephyr/projects/nissa/BUILD.py index 42e0bf04e2..93ef8277da 100644 --- a/zephyr/projects/nissa/BUILD.py +++ b/zephyr/projects/nissa/BUILD.py @@ -117,6 +117,5 @@ yaviks = register_nissa_project( "overlay.dts", "keyboard.dts", "power_signals.dts", - "pwm_leds.dts", ], ) diff --git a/zephyr/projects/nissa/CMakeLists.txt b/zephyr/projects/nissa/CMakeLists.txt index 99fedacd93..2907d969b3 100644 --- a/zephyr/projects/nissa/CMakeLists.txt +++ b/zephyr/projects/nissa/CMakeLists.txt @@ -74,7 +74,7 @@ endif() if(DEFINED CONFIG_BOARD_YAVIKS) project(yaviks) zephyr_library_sources( - "src/led.c" + "yaviks/src/led.c" "yaviks/src/keyboard.c" "yaviks/src/hdmi.c" ) diff --git a/zephyr/projects/nissa/yaviks/gpio.dts b/zephyr/projects/nissa/yaviks/gpio.dts index 79e491d416..0158d5b19b 100644 --- a/zephyr/projects/nissa/yaviks/gpio.dts +++ b/zephyr/projects/nissa/yaviks/gpio.dts @@ -201,6 +201,18 @@ gpio_vccin_aux_vid1: vccin_aux_vid1 { gpios = <&gpiok 1 (GPIO_INPUT | GPIO_VOLTAGE_1P8)>; }; + gpio_c1_charger_led_white_l: c1_charger_led_white_l { + gpios = <&gpiol 4 GPIO_OUTPUT_HIGH>; + }; + gpio_c1_charger_led_amber_l: c1_charger_led_amber_l { + gpios = <&gpiod 4 GPIO_OUTPUT_HIGH>; + }; + gpio_c0_charger_led_white_l: c0_charger_led_white_l { + gpios = <&gpioc 3 GPIO_OUTPUT_HIGH>; + }; + gpio_c0_charger_led_amber_l: c0_charger_led_amber_l { + gpios = <&gpioj 7 GPIO_OUTPUT_HIGH>; + }; }; named-i2c-ports { diff --git a/zephyr/projects/nissa/yaviks/overlay.dts b/zephyr/projects/nissa/yaviks/overlay.dts index 56bcd98d31..3c5a8ff7b5 100644 --- a/zephyr/projects/nissa/yaviks/overlay.dts +++ b/zephyr/projects/nissa/yaviks/overlay.dts @@ -77,15 +77,11 @@ compatible = "unused-gpios"; unused-gpios = <&gpioa 7 0>, <&gpioc 0 0>, - <&gpioc 3 0>, - <&gpiod 4 0>, <&gpiod 7 0>, <&gpioh 2 0>, <&gpioi 6 0>, <&gpioi 7 0>, - <&gpioj 0 0>, - <&gpioj 7 0>, - <&gpiol 4 0>; + <&gpioj 0 0>; }; named-gpios { diff --git a/zephyr/projects/nissa/yaviks/prj.conf b/zephyr/projects/nissa/yaviks/prj.conf index d4de1bb856..e74049aad7 100644 --- a/zephyr/projects/nissa/yaviks/prj.conf +++ b/zephyr/projects/nissa/yaviks/prj.conf @@ -72,3 +72,6 @@ CONFIG_TACH_IT8XXX2=n # Ensure recovery key combination (esc+refresh+power) is reliable: b/236580049 CONFIG_PLATFORM_EC_KEYBOARD_PWRBTN_ASSERTS_KSI3=y CONFIG_PLATFORM_EC_KEYBOARD_REFRESH_ROW3=y + +# LED +CONFIG_PLATFORM_EC_LED_PWM=n diff --git a/zephyr/projects/nissa/yaviks/pwm_leds.dts b/zephyr/projects/nissa/yaviks/pwm_leds.dts deleted file mode 100644 index aa4a76b271..0000000000 --- a/zephyr/projects/nissa/yaviks/pwm_leds.dts +++ /dev/null @@ -1,60 +0,0 @@ -/* Copyright 2022 The ChromiumOS Authors - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/ { - pwmleds { - compatible = "pwm-leds"; - pwm_led0: pwm_led_0 { - pwms = <&pwm1 1 PWM_HZ(1296) PWM_POLARITY_INVERTED>, - <&pwm2 2 PWM_HZ(1296) PWM_POLARITY_INVERTED>, - <&pwm3 3 PWM_HZ(1296) PWM_POLARITY_INVERTED>; - }; - }; - - cros-pwmleds { - compatible = "cros-ec,pwm-leds"; - - leds = <&pwm_led0>; - - /**/ - color-map-red = <100 0 0>; - color-map-green = < 0 100 0>; - color-map-blue = < 0 0 100>; - color-map-yellow = < 0 50 50>; - color-map-white = <100 100 100>; - color-map-amber = <100 15 0>; - - brightness-range = <100 100 100 0 0 0>; - - #address-cells = <1>; - #size-cells = <0>; - - pwm_led_0@0 { - reg = <0>; - ec-led-name = "EC_LED_ID_BATTERY_LED"; - }; - }; -}; - -&pwm1 { - status = "okay"; - prescaler-cx = ; - pinctrl-0 = <&pwm1_gpa1_default>; - pinctrl-names = "default"; -}; - -&pwm2 { - status = "okay"; - prescaler-cx = ; - pinctrl-0 = <&pwm2_gpa2_default>; - pinctrl-names = "default"; -}; - -&pwm3 { - status = "okay"; - prescaler-cx = ; - pinctrl-0 = <&pwm3_gpa3_default>; - pinctrl-names = "default"; -}; diff --git a/zephyr/projects/nissa/yaviks/src/led.c b/zephyr/projects/nissa/yaviks/src/led.c new file mode 100644 index 0000000000..e4f49dc9ad --- /dev/null +++ b/zephyr/projects/nissa/yaviks/src/led.c @@ -0,0 +1,231 @@ +/* Copyright 2022 The ChromiumOS Authors. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include + +#include "battery.h" +#include "charge_manager.h" +#include "charge_state.h" +#include "chipset.h" +#include "ec_commands.h" +#include "gpio.h" +#include "host_command.h" +#include "led_common.h" +#include "hooks.h" + +#define BAT_LED_ON 0 +#define BAT_LED_OFF 1 + +#define BATT_LOW_BCT 10 + +#define LED_TICKS_PER_CYCLE 4 +#define LED_TICKS_PER_CYCLE_S3 4 +#define LED_ON_TICKS 2 +#define POWER_LED_ON_S3_TICKS 2 + +const enum ec_led_id supported_led_ids[] = { EC_LED_ID_LEFT_LED, + EC_LED_ID_RIGHT_LED }; + +const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids); + +enum led_color { + LED_OFF = 0, + LED_AMBER, + LED_WHITE, + LED_COLOR_COUNT /* Number of colors, not a color itself */ +}; + +enum led_port { LEFT_PORT = 0, RIGHT_PORT }; + +static void led_set_color_battery(int port, enum led_color color) +{ + const struct gpio_dt_spec *amber_led, *white_led; + + if (port == LEFT_PORT) { + amber_led = GPIO_DT_FROM_NODELABEL(gpio_c0_charger_led_amber_l); + white_led = GPIO_DT_FROM_NODELABEL(gpio_c0_charger_led_white_l); + } else if (port == RIGHT_PORT) { + amber_led = GPIO_DT_FROM_NODELABEL(gpio_c1_charger_led_amber_l); + white_led = GPIO_DT_FROM_NODELABEL(gpio_c1_charger_led_white_l); + } + + switch (color) { + case LED_WHITE: + gpio_pin_set_dt(white_led, BAT_LED_ON); + gpio_pin_set_dt(amber_led, BAT_LED_OFF); + break; + case LED_AMBER: + gpio_pin_set_dt(white_led, BAT_LED_OFF); + gpio_pin_set_dt(amber_led, BAT_LED_ON); + break; + case LED_OFF: + gpio_pin_set_dt(white_led, BAT_LED_OFF); + gpio_pin_set_dt(amber_led, BAT_LED_OFF); + break; + default: + break; + } +} + +void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range) +{ + switch (led_id) { + case EC_LED_ID_LEFT_LED: + brightness_range[EC_LED_COLOR_WHITE] = 1; + brightness_range[EC_LED_COLOR_AMBER] = 1; + break; + case EC_LED_ID_RIGHT_LED: + brightness_range[EC_LED_COLOR_WHITE] = 1; + brightness_range[EC_LED_COLOR_AMBER] = 1; + break; + default: + break; + } +} + +int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness) +{ + switch (led_id) { + case EC_LED_ID_LEFT_LED: + if (brightness[EC_LED_COLOR_WHITE] != 0) + led_set_color_battery(LEFT_PORT, LED_WHITE); + else if (brightness[EC_LED_COLOR_AMBER] != 0) + led_set_color_battery(LEFT_PORT, LED_AMBER); + else + led_set_color_battery(LEFT_PORT, LED_OFF); + break; + case EC_LED_ID_RIGHT_LED: + if (brightness[EC_LED_COLOR_WHITE] != 0) + led_set_color_battery(RIGHT_PORT, LED_WHITE); + else if (brightness[EC_LED_COLOR_AMBER] != 0) + led_set_color_battery(RIGHT_PORT, LED_AMBER); + else + led_set_color_battery(RIGHT_PORT, LED_OFF); + break; + default: + return EC_ERROR_PARAM1; + } + + return EC_SUCCESS; +} + +/* + * Set active charge port color to the parameter, turn off all others. + * If no port is active (-1), turn off all LEDs. + */ +static void set_active_port_color(enum led_color color) +{ + int port = charge_manager_get_active_charge_port(); + + if (led_auto_control_is_enabled(EC_LED_ID_RIGHT_LED)) + led_set_color_battery(RIGHT_PORT, + (port == RIGHT_PORT) ? color : LED_OFF); + if (led_auto_control_is_enabled(EC_LED_ID_LEFT_LED)) + led_set_color_battery(LEFT_PORT, + (port == LEFT_PORT) ? color : LED_OFF); +} + +static void led_set_battery(void) +{ + static unsigned int battery_ticks; + static int suspend_ticks; + + battery_ticks++; + + /* + * Override battery LEDs for Yaviks, Yaviks is non-power LED + * design, blinking both two side battery white LEDs to indicate + * system suspend with non-charging state. + */ + if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND) && + charge_get_state() != PWR_STATE_CHARGE) { + suspend_ticks++; + + led_set_color_battery(RIGHT_PORT, + suspend_ticks % LED_TICKS_PER_CYCLE_S3 < + POWER_LED_ON_S3_TICKS ? + LED_WHITE : + LED_OFF); + led_set_color_battery(LEFT_PORT, + suspend_ticks % LED_TICKS_PER_CYCLE_S3 < + POWER_LED_ON_S3_TICKS ? + LED_WHITE : + LED_OFF); + return; + } + + suspend_ticks = 0; + + switch (charge_get_state()) { + case PWR_STATE_CHARGE: + /* Always indicate when charging, even in suspend. */ + set_active_port_color(LED_AMBER); + break; + case PWR_STATE_DISCHARGE: + /* + * Blinking amber LEDs slowly if battery is lower 10 + * percentage. + */ + if (led_auto_control_is_enabled(EC_LED_ID_RIGHT_LED)) { + if (charge_get_percent() < BATT_LOW_BCT) + led_set_color_battery( + RIGHT_PORT, + (battery_ticks % LED_TICKS_PER_CYCLE < + LED_ON_TICKS) ? + LED_AMBER : + LED_OFF); + else + led_set_color_battery(RIGHT_PORT, LED_OFF); + } + + if (led_auto_control_is_enabled(EC_LED_ID_LEFT_LED)) { + if (charge_get_percent() < BATT_LOW_BCT) + led_set_color_battery( + LEFT_PORT, + (battery_ticks % LED_TICKS_PER_CYCLE < + LED_ON_TICKS) ? + LED_AMBER : + LED_OFF); + else + led_set_color_battery(LEFT_PORT, LED_OFF); + } + break; + case PWR_STATE_ERROR: + if (led_auto_control_is_enabled(EC_LED_ID_RIGHT_LED)) { + led_set_color_battery( + RIGHT_PORT, + (battery_ticks & 0x1) ? LED_AMBER : LED_OFF); + } + + if (led_auto_control_is_enabled(EC_LED_ID_LEFT_LED)) { + led_set_color_battery(LEFT_PORT, (battery_ticks & 0x1) ? + LED_AMBER : + LED_OFF); + } + break; + case PWR_STATE_CHARGE_NEAR_FULL: + set_active_port_color(LED_WHITE); + break; + case PWR_STATE_IDLE: /* External power connected in IDLE */ + set_active_port_color(LED_WHITE); + break; + case PWR_STATE_FORCED_IDLE: + set_active_port_color( + (battery_ticks % LED_TICKS_PER_CYCLE < LED_ON_TICKS) ? + LED_AMBER : + LED_OFF); + break; + default: + /* Other states don't alter LED behavior */ + break; + } +} + +/* Called by hook task every TICK(IT83xx 500ms) */ +static void led_tick(void) +{ + led_set_battery(); +} +DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT); -- cgit v1.2.1