| /* Copyright 2020 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 for Asurada |
| */ |
| #include "charge_manager.h" |
| #include "charge_state.h" |
| #include "common.h" |
| #include "console.h" |
| #include "driver/bc12/mt6360.h" |
| #include "hooks.h" |
| #include "led_common.h" |
| #include "pwm.h" |
| #include "stdbool.h" |
| #include "util.h" |
| |
| #define CPRINTS(format, args...) cprints(CC_PWM, format, ## args) |
| |
| #define LED_OFF EC_LED_COLOR_COUNT |
| |
| const enum ec_led_id supported_led_ids[] = { |
| /* Main LED */ |
| EC_LED_ID_LEFT_LED, |
| EC_LED_ID_RIGHT_LED, |
| |
| /* Not used, give them some random name for testing */ |
| EC_LED_ID_POWER_LED, |
| EC_LED_ID_BATTERY_LED |
| }; |
| const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids); |
| |
| static void led_set_color_left(enum ec_led_colors color, int duty) |
| { |
| mt6360_led_set_brightness(MT6360_LED_RGB2, duty); |
| mt6360_led_set_brightness(MT6360_LED_RGB3, duty); |
| |
| switch (color) { |
| case EC_LED_COLOR_AMBER: |
| mt6360_led_enable(MT6360_LED_RGB2, 0); |
| mt6360_led_enable(MT6360_LED_RGB3, 1); |
| break; |
| case EC_LED_COLOR_WHITE: |
| mt6360_led_enable(MT6360_LED_RGB2, 1); |
| mt6360_led_enable(MT6360_LED_RGB3, 0); |
| break; |
| default: /* LED_OFF and other unsupported colors */ |
| mt6360_led_enable(MT6360_LED_RGB2, 0); |
| mt6360_led_enable(MT6360_LED_RGB3, 0); |
| break; |
| } |
| } |
| |
| static void led_set_color_right(enum ec_led_colors color, int duty) |
| { |
| pwm_set_duty(PWM_CH_LED2, duty); |
| pwm_set_duty(PWM_CH_LED3, duty); |
| |
| switch (color) { |
| case EC_LED_COLOR_AMBER: |
| pwm_enable(PWM_CH_LED2, 0); |
| pwm_enable(PWM_CH_LED3, 1); |
| break; |
| case EC_LED_COLOR_WHITE: |
| pwm_enable(PWM_CH_LED2, 1); |
| pwm_enable(PWM_CH_LED3, 0); |
| break; |
| default: /* LED_OFF and other unsupported colors */ |
| pwm_enable(PWM_CH_LED2, 0); |
| pwm_enable(PWM_CH_LED3, 0); |
| break; |
| } |
| } |
| |
| static void led_set_color_power(enum ec_led_colors color, int duty) |
| { |
| pwm_set_duty(PWM_CH_LED1, duty); |
| pwm_enable(PWM_CH_LED1, color == EC_LED_COLOR_WHITE); |
| } |
| |
| static void led_set_color_battery(enum ec_led_colors color, int duty) |
| { |
| mt6360_led_set_brightness(MT6360_LED_RGB1, duty); |
| mt6360_led_enable(MT6360_LED_RGB1, color == EC_LED_COLOR_WHITE); |
| } |
| |
| static enum ec_error_list set_color(enum ec_led_id led_id, |
| enum ec_led_colors color, |
| int duty) |
| { |
| switch (led_id) { |
| case EC_LED_ID_LEFT_LED: |
| led_set_color_left(color, duty); |
| return EC_SUCCESS; |
| case EC_LED_ID_RIGHT_LED: |
| led_set_color_right(color, duty); |
| return EC_SUCCESS; |
| case EC_LED_ID_POWER_LED: |
| led_set_color_power(color, duty); |
| return EC_SUCCESS; |
| case EC_LED_ID_BATTERY_LED: |
| led_set_color_battery(color, duty); |
| return EC_SUCCESS; |
| default: |
| return EC_ERROR_INVAL; |
| } |
| } |
| |
| 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_AMBER] = |
| MT6360_LED_BRIGHTNESS_MAX; |
| brightness_range[EC_LED_COLOR_WHITE] = |
| MT6360_LED_BRIGHTNESS_MAX; |
| break; |
| case EC_LED_ID_RIGHT_LED: |
| brightness_range[EC_LED_COLOR_AMBER] = 100; |
| brightness_range[EC_LED_COLOR_WHITE] = 100; |
| break; |
| case EC_LED_ID_POWER_LED: |
| brightness_range[EC_LED_COLOR_WHITE] = 100; |
| break; |
| case EC_LED_ID_BATTERY_LED: |
| brightness_range[EC_LED_COLOR_WHITE] = |
| MT6360_LED_BRIGHTNESS_MAX; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness) |
| { |
| if (brightness[EC_LED_COLOR_AMBER]) |
| return set_color(led_id, EC_LED_COLOR_AMBER, |
| brightness[EC_LED_COLOR_AMBER]); |
| if (brightness[EC_LED_COLOR_WHITE]) |
| return set_color(led_id, EC_LED_COLOR_WHITE, |
| brightness[EC_LED_COLOR_WHITE]); |
| |
| return set_color(led_id, LED_OFF, 0); |
| } |
| |
| static void update_led(enum ec_led_id led_id, bool is_active_charge_port, |
| int duty, int tick) |
| { |
| enum charge_state power_state = charge_get_state(); |
| |
| if (power_state == PWR_STATE_IDLE) { |
| /* Factory mode: blinking white (2sec on + 2sec off) */ |
| set_color(led_id, (tick % 8 < 4) ? EC_LED_COLOR_WHITE : LED_OFF, |
| duty); |
| } else if (power_state == PWR_STATE_ERROR) { |
| /* Battery error: blinking amber (1sec on + 1sec off) */ |
| set_color(led_id, (tick % 4 < 2) ? EC_LED_COLOR_AMBER : LED_OFF, |
| duty); |
| } else if (is_active_charge_port) { |
| /* |
| * Active charge port: amber when charging, white if fully |
| * charged. |
| */ |
| if (power_state == PWR_STATE_CHARGE) |
| set_color(led_id, EC_LED_COLOR_AMBER, duty); |
| else |
| set_color(led_id, EC_LED_COLOR_WHITE, duty); |
| } else { |
| /* |
| * Non-active port: |
| * Solid white in S0, blinking amber (3sec on + 1sec off) in S3, |
| * and LED off in S5 |
| */ |
| if (chipset_in_state(CHIPSET_STATE_ON)) |
| set_color(led_id, EC_LED_COLOR_WHITE, duty); |
| else if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND)) |
| set_color( |
| led_id, |
| (tick % 8 < 6) ? EC_LED_COLOR_AMBER : LED_OFF, |
| duty); |
| else |
| set_color(led_id, LED_OFF, 0); |
| |
| } |
| } |
| |
| static void led_tick(void) |
| { |
| static int tick; |
| int port = charge_manager_get_active_charge_port(); |
| |
| ++tick; |
| /* Pick duty 1 and 50 respectively to have same brightness */ |
| if (led_auto_control_is_enabled(EC_LED_ID_LEFT_LED)) |
| update_led(EC_LED_ID_LEFT_LED, port == 0, 1, tick); |
| if (led_auto_control_is_enabled(EC_LED_ID_RIGHT_LED)) |
| update_led(EC_LED_ID_RIGHT_LED, port == 1, 50, tick); |
| /* Turn off unused LEDs */ |
| if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) |
| set_color(EC_LED_ID_POWER_LED, LED_OFF, 0); |
| if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) |
| set_color(EC_LED_ID_BATTERY_LED, LED_OFF, 0); |
| } |
| DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT); |
| DECLARE_HOOK(HOOK_INIT, led_tick, HOOK_PRIO_DEFAULT); |