summaryrefslogtreecommitdiff
path: root/board/redrix/led.c
diff options
context:
space:
mode:
authorDevin Lu <Devin.Lu@quantatw.com>2021-07-13 14:31:30 +0800
committerCommit Bot <commit-bot@chromium.org>2021-07-21 02:19:25 +0000
commitc1acd051f35d1a46a3ec4454886f1de1b68558ff (patch)
tree4d2d8638607b2c8467fe4f6e6474ccc401521a10 /board/redrix/led.c
parent991635ce353d85e833b1e7a2110752730289d21c (diff)
downloadchrome-ec-c1acd051f35d1a46a3ec4454886f1de1b68558ff.tar.gz
redrix: Implement leds
Simply copy from: https://chromium.googlesource.com/chromiumos/platform/ec/+/refs/heads/main/board/jinlon/led.c |1. Add some macro changes and change C0 charging led to left side.| |2. Add a LED task to replace the hook task.| 1. Redrix has the same design as Jinlon, there are two set charging leds on system (right side and left side), each side has two colors amber and white. 2. Redrix has a power led to indicate power state suspend/off. The led behavior define as following: 1. Charging led: led on with charging port active, other port is off. Charging: Amber. Discharging: Off. Battery Error: Blinking white (0.5 sec on, 0.5 sec off) Fuel < 10%: Blinking white on right side port (1 sec on, 1 sec off) Force idle for factory: Blinking amber (1 sec on, 1 sec off) 2. Power led: System is S0: White System is suspend/S0ix: Blinking white (1 sec on, 1 sec off) System is S5: Off BUG=b:193945754 BRANCH=none TEST=Cherry-picked this patch to Jinlon and Verified as following: make sure led behavior intended. make sure ectool led power white/off/auto work correctly. make sure ectool led left white/amber/off/auto work correctly. make sure ectool led right white/amber/off/auto work correctly. Signed-off-by: Devin Lu <Devin.Lu@quantatw.com> Change-Id: If05c9e2750ca3afcbcfaf51ce495d0f03d1fa756 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3023511 Reviewed-by: caveh jalali <caveh@chromium.org> Reviewed-by: Boris Mittelberg <bmbm@google.com>
Diffstat (limited to 'board/redrix/led.c')
-rw-r--r--board/redrix/led.c263
1 files changed, 207 insertions, 56 deletions
diff --git a/board/redrix/led.c b/board/redrix/led.c
index 38caa38d37..be48e16cff 100644
--- a/board/redrix/led.c
+++ b/board/redrix/led.c
@@ -1,93 +1,244 @@
/* 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.
- */
-
-/* Brya specific PWM LED settings: there are 2 LEDs on each side of the board,
- * each one can be controlled separately. The LED colors are white or amber,
- * and the default behavior is tied to the charging process: both sides are
- * amber while charging the battery and white when the battery is charged.
+ *
+ * Power and battery LED control for Redrix
*/
#include <stdint.h>
-#include "common.h"
-#include "compile_time_macros.h"
+#include "battery.h"
+#include "charge_manager.h"
+#include "charge_state.h"
+#include "chipset.h"
#include "ec_commands.h"
-#include "led_pwm.h"
-#include "pwm.h"
-#include "util.h"
+#include "gpio.h"
+#include "host_command.h"
+#include "led_common.h"
+#include "task.h"
+
+#define BAT_LED_ON 0
+#define BAT_LED_OFF 1
+
+#define POWER_LED_ON 0
+#define POWER_LED_OFF 1
+
+#define LED_TICK_INTERVAL_MS (500 * MSEC)
+#define LED_CYCLE_TIME_MS (2000 * MSEC)
+#define LED_TICKS_PER_CYCLE (LED_CYCLE_TIME_MS / LED_TICK_INTERVAL_MS)
+#define LED_ON_TIME_MS (1000 * MSEC)
+#define LED_ON_TICKS (LED_ON_TIME_MS / LED_TICK_INTERVAL_MS)
const enum ec_led_id supported_led_ids[] = {
EC_LED_ID_LEFT_LED,
EC_LED_ID_RIGHT_LED,
+ EC_LED_ID_POWER_LED
};
const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids);
-/*
- * We only have a white and an amber LED, so setting any other color results in
- * both LEDs being off.
- */
-struct pwm_led led_color_map[EC_LED_COLOR_COUNT] = {
- /* Amber, White */
- [EC_LED_COLOR_RED] = { 0, 0 },
- [EC_LED_COLOR_GREEN] = { 0, 0 },
- [EC_LED_COLOR_BLUE] = { 0, 0 },
- [EC_LED_COLOR_YELLOW] = { 0, 0 },
- [EC_LED_COLOR_WHITE] = { 0, 100 },
- [EC_LED_COLOR_AMBER] = { 100, 0 },
+enum led_color {
+ LED_OFF = 0,
+ LED_AMBER,
+ LED_WHITE,
+ LED_COLOR_COUNT /* Number of colors, not a color itself */
};
-/* Two logical LEDs with amber and white channels. */
-struct pwm_led pwm_leds[CONFIG_LED_PWM_COUNT] = {
- {
- .ch0 = PWM_CH_LED1,
- .ch1 = PWM_CH_LED2,
- .ch2 = PWM_LED_NO_CHANNEL,
- .enable = &pwm_enable,
- .set_duty = &pwm_set_duty,
- },
- {
- .ch0 = PWM_CH_LED3,
- .ch1 = PWM_CH_LED4,
- .ch2 = PWM_LED_NO_CHANNEL,
- .enable = &pwm_enable,
- .set_duty = &pwm_set_duty,
- },
+enum led_port {
+ LEFT_PORT = 0,
+ RIGHT_PORT
};
+static void led_set_color_battery(int port, enum led_color color)
+{
+ enum gpio_signal amber_led, white_led;
+
+ amber_led = (port == RIGHT_PORT ? GPIO_C0_CHARGE_LED_AMBER_L :
+ GPIO_C1_CHARGE_LED_AMBER_L);
+ white_led = (port == RIGHT_PORT ? GPIO_C0_CHARGE_LED_WHITE_L :
+ GPIO_C1_CHARGE_LED_WHITE_L);
+
+ switch (color) {
+ case LED_WHITE:
+ gpio_set_level(white_led, BAT_LED_ON);
+ gpio_set_level(amber_led, BAT_LED_OFF);
+ break;
+ case LED_AMBER:
+ gpio_set_level(white_led, BAT_LED_OFF);
+ gpio_set_level(amber_led, BAT_LED_ON);
+ break;
+ case LED_OFF:
+ gpio_set_level(white_led, BAT_LED_OFF);
+ gpio_set_level(amber_led, BAT_LED_OFF);
+ break;
+ default:
+ break;
+ }
+}
+
+void led_set_color_power(enum ec_led_colors color)
+{
+ switch (color) {
+ case LED_OFF:
+ gpio_set_level(GPIO_PWR_LED_WHITE_L, POWER_LED_OFF);
+ break;
+ case LED_WHITE:
+ gpio_set_level(GPIO_PWR_LED_WHITE_L, POWER_LED_ON);
+ break;
+ default:
+ break;
+ }
+}
+
void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range)
{
- memset(brightness_range, '\0',
- sizeof(*brightness_range) * EC_LED_COLOR_COUNT);
- brightness_range[EC_LED_COLOR_AMBER] = 100;
- brightness_range[EC_LED_COLOR_WHITE] = 100;
+ 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;
+ case EC_LED_ID_POWER_LED:
+ brightness_range[EC_LED_COLOR_WHITE] = 1;
+ break;
+ default:
+ break;
+ }
}
int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness)
{
- enum pwm_led_id pwm_id;
-
- /* Convert ec_led_id to pwm_led_id. */
switch (led_id) {
case EC_LED_ID_LEFT_LED:
- pwm_id = PWM_LED0;
+ 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:
- pwm_id = PWM_LED1;
+ 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;
+ case EC_LED_ID_POWER_LED:
+ if (brightness[EC_LED_COLOR_WHITE] != 0)
+ led_set_color_power(LED_WHITE);
+ else
+ led_set_color_power(LED_OFF);
break;
default:
- return EC_ERROR_UNKNOWN;
+ return EC_ERROR_PARAM1;
}
- if (brightness[EC_LED_COLOR_WHITE])
- set_pwm_led_color(pwm_id, EC_LED_COLOR_WHITE);
- else if (brightness[EC_LED_COLOR_AMBER])
- set_pwm_led_color(pwm_id, EC_LED_COLOR_AMBER);
+ 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;
+ uint32_t chflags = charge_get_flags();
+
+ battery_ticks++;
+
+ 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:
+ if (led_auto_control_is_enabled(EC_LED_ID_RIGHT_LED)) {
+ if (charge_get_percent() < 10)
+ led_set_color_battery(RIGHT_PORT,
+ (battery_ticks % LED_TICKS_PER_CYCLE
+ < LED_ON_TICKS) ? LED_WHITE : LED_OFF);
+ else
+ led_set_color_battery(RIGHT_PORT, LED_OFF);
+ }
+
+ if (led_auto_control_is_enabled(EC_LED_ID_LEFT_LED))
+ led_set_color_battery(LEFT_PORT, LED_OFF);
+ break;
+ case PWR_STATE_ERROR:
+ set_active_port_color((battery_ticks & 0x2) ?
+ LED_WHITE : 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 */
+ if (chflags & CHARGE_FLAG_FORCE_IDLE)
+ set_active_port_color((battery_ticks %
+ LED_TICKS_PER_CYCLE < LED_ON_TICKS) ?
+ LED_AMBER : LED_OFF);
+ else
+ set_active_port_color(LED_WHITE);
+ break;
+ default:
+ /* Other states don't alter LED behavior */
+ break;
+ }
+}
+
+static void led_set_power(void)
+{
+ static unsigned int power_tick;
+
+ power_tick++;
+
+ if (chipset_in_state(CHIPSET_STATE_ON))
+ led_set_color_power(LED_WHITE);
+ else if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND))
+ led_set_color_power((power_tick %
+ LED_TICKS_PER_CYCLE < LED_ON_TICKS) ?
+ LED_WHITE : LED_OFF);
else
- /* Otherwise, the "color" is "off". */
- set_pwm_led_color(pwm_id, -1);
+ led_set_color_power(LED_OFF);
+}
- return EC_SUCCESS;
+void led_task(void *u)
+{
+ uint32_t start_time;
+ uint32_t task_duration;
+
+ while (1) {
+ start_time = get_time().le.lo;
+
+ if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED))
+ led_set_power();
+
+ led_set_battery();
+
+ /* Compute time for this iteration */
+ task_duration = get_time().le.lo - start_time;
+ /*
+ * Compute wait time required to for next desired LED tick. If
+ * the duration exceeds the tick time, then don't sleep.
+ */
+ if (task_duration < LED_TICK_INTERVAL_MS)
+ usleep(LED_TICK_INTERVAL_MS - task_duration);
+ }
}