diff options
author | YH Lin <yueherngl@google.com> | 2017-11-22 14:04:38 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-11-29 22:37:49 -0800 |
commit | bf80bbf769270e094f224560e23f32fa4ca77144 (patch) | |
tree | 1008ea7af9564383c3ce6051a305a3287d70bb06 /board/nami/led.c | |
parent | 3895a168b2c0c65ad4323e2972a31a40e50d0bdf (diff) | |
download | chrome-ec-bf80bbf769270e094f224560e23f32fa4ca77144.tar.gz |
nami: initial setup for ec
Add initial files for nami from fizz, to be revised later.
BUG=b:69628538
TEST=None
BRANCH=None
CQ-DEPEND=CL:782239
Change-Id: I910a8fc9603471d5de0b34ca5888fff147f9cd6f
Signed-off-by: YH Lin <yueherngl@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/783557
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Diffstat (limited to 'board/nami/led.c')
-rw-r--r-- | board/nami/led.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/board/nami/led.c b/board/nami/led.c new file mode 100644 index 0000000000..9b6942d241 --- /dev/null +++ b/board/nami/led.c @@ -0,0 +1,232 @@ +/* Copyright 2017 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 Fizz + */ + +#include "chipset.h" +#include "console.h" +#include "ec_commands.h" +#include "gpio.h" +#include "hooks.h" +#include "led_common.h" +#include "pwm.h" +#include "timer.h" +#include "util.h" + +const enum ec_led_id supported_led_ids[] = {EC_LED_ID_POWER_LED}; +const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids); + +enum led_color { + LED_OFF = 0, + LED_RED, + LED_GREEN, + LED_AMBER, + + /* Number of colors, not a color itself */ + LED_COLOR_COUNT +}; + +static int set_color_power(enum led_color color, int duty) +{ + int green = 0; + int red = 0; + + if (duty < 0 || 100 < duty) + return EC_ERROR_UNKNOWN; + + switch (color) { + case LED_OFF: + break; + case LED_GREEN: + green = 1; + break; + case LED_RED: + red = 1; + break; + case LED_AMBER: + green = 1; + red = 1; + break; + default: + return EC_ERROR_UNKNOWN; + } + + if (red) + pwm_set_duty(PWM_CH_LED_RED, duty); + else + pwm_set_duty(PWM_CH_LED_RED, 0); + + if (green) + pwm_set_duty(PWM_CH_LED_GREEN, duty); + else + pwm_set_duty(PWM_CH_LED_GREEN, 0); + + return EC_SUCCESS; +} + +static int set_color(enum ec_led_id id, enum led_color color, int duty) +{ + switch (id) { + case EC_LED_ID_POWER_LED: + return set_color_power(color, duty); + default: + return EC_ERROR_UNKNOWN; + } +} + +#define LED_PULSE_US (2 * SECOND) +/* 40 msec for nice and smooth transition. */ +#define LED_PULSE_TICK_US (40 * MSEC) + +/* When pulsing is enabled, brightness is incremented by <duty_inc> every + * <interval> usec from 0 to 100% in LED_PULSE_US usec. Then it's decremented + * likewise in LED_PULSE_US usec. */ +static struct { + uint32_t interval; + int duty_inc; + enum led_color color; + int duty; +} led_pulse; + +#define CONFIG_TICK(interval, color) \ + config_tick((interval), 100 / (LED_PULSE_US / (interval)), (color)) + +static void config_tick(uint32_t interval, int duty_inc, enum led_color color) +{ + led_pulse.interval = interval; + led_pulse.duty_inc = duty_inc; + led_pulse.color = color; + led_pulse.duty = 0; +} + +static void pulse_power_led(enum led_color color) +{ + set_color(EC_LED_ID_POWER_LED, color, led_pulse.duty); + if (led_pulse.duty + led_pulse.duty_inc > 100) + led_pulse.duty_inc = led_pulse.duty_inc * -1; + else if (led_pulse.duty + led_pulse.duty_inc < 0) + led_pulse.duty_inc = led_pulse.duty_inc * -1; + led_pulse.duty += led_pulse.duty_inc; +} + +static void led_tick(void); +DECLARE_DEFERRED(led_tick); +static void led_tick(void) +{ + uint32_t elapsed; + uint32_t next = 0; + uint32_t start = get_time().le.lo; + static uint8_t pwm_enabled = 0; + + if (!pwm_enabled) { + pwm_enable(PWM_CH_LED_RED, 1); + pwm_enable(PWM_CH_LED_GREEN, 1); + pwm_enabled = 1; + } + if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) + pulse_power_led(led_pulse.color); + elapsed = get_time().le.lo - start; + next = led_pulse.interval > elapsed ? led_pulse.interval - elapsed : 0; + hook_call_deferred(&led_tick_data, next); +} + +static void led_suspend(void) +{ + CONFIG_TICK(LED_PULSE_TICK_US, LED_GREEN); + led_tick(); +} +DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, led_suspend, HOOK_PRIO_DEFAULT); + +static void led_shutdown(void) +{ + hook_call_deferred(&led_tick_data, -1); + if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) + set_color(EC_LED_ID_POWER_LED, LED_OFF, 0); +} +DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, led_shutdown, HOOK_PRIO_DEFAULT); + +static void led_resume(void) +{ + /* Assume there is no race condition with led_tick, which also + * runs in hook_task. */ + hook_call_deferred(&led_tick_data, -1); + if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) + set_color(EC_LED_ID_POWER_LED, LED_GREEN, 100); +} +DECLARE_HOOK(HOOK_CHIPSET_RESUME, led_resume, HOOK_PRIO_DEFAULT); + +void led_alert(int enable) +{ + if (enable) { + /* Overwrite the current signal */ + config_tick(1 * SECOND, 100, LED_RED); + led_tick(); + } else { + /* Restore the previous signal */ + if (chipset_in_state(CHIPSET_STATE_ON)) + led_resume(); + else if (chipset_in_state(CHIPSET_STATE_SUSPEND)) + led_suspend(); + else if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) + led_shutdown(); + } +} + +void led_critical(void) +{ + hook_call_deferred(&led_tick_data, -1); + if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) + set_color(EC_LED_ID_POWER_LED, LED_RED, 100); +} + +static int command_led(int argc, char **argv) +{ + enum ec_led_id id = EC_LED_ID_POWER_LED; + + if (argc < 2) + return EC_ERROR_PARAM_COUNT; + + if (!strcasecmp(argv[1], "debug")) { + led_auto_control(id, !led_auto_control_is_enabled(id)); + ccprintf("o%s\n", led_auto_control_is_enabled(id) ? "ff" : "n"); + } else if (!strcasecmp(argv[1], "off")) { + set_color(id, LED_OFF, 0); + } else if (!strcasecmp(argv[1], "red")) { + set_color(id, LED_RED, 100); + } else if (!strcasecmp(argv[1], "green")) { + set_color(id, LED_GREEN, 100); + } else if (!strcasecmp(argv[1], "amber")) { + set_color(id, LED_AMBER, 100); + } else if (!strcasecmp(argv[1], "alert")) { + led_alert(1); + } else if (!strcasecmp(argv[1], "crit")) { + led_critical(); + } else { + return EC_ERROR_PARAM1; + } + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(led, command_led, + "[debug|red|green|amber|off|alert|crit]", + "Turn on/off LED."); + +void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range) +{ + brightness_range[EC_LED_COLOR_RED] = 100; + brightness_range[EC_LED_COLOR_GREEN] = 100; + brightness_range[EC_LED_COLOR_AMBER] = 100; +} + +int led_set_brightness(enum ec_led_id id, const uint8_t *brightness) +{ + if (brightness[EC_LED_COLOR_RED]) + return set_color(id, LED_RED, brightness[EC_LED_COLOR_RED]); + else if (brightness[EC_LED_COLOR_GREEN]) + return set_color(id, LED_GREEN, brightness[EC_LED_COLOR_GREEN]); + else if (brightness[EC_LED_COLOR_AMBER]) + return set_color(id, LED_AMBER, brightness[EC_LED_COLOR_AMBER]); + else + return set_color(id, LED_OFF, 0); +} |