summaryrefslogtreecommitdiff
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
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>
-rw-r--r--board/redrix/board.h18
-rw-r--r--board/redrix/ec.tasklist3
-rw-r--r--board/redrix/gpio.inc8
-rw-r--r--board/redrix/led.c263
-rw-r--r--board/redrix/pwm.c33
5 files changed, 217 insertions, 108 deletions
diff --git a/board/redrix/board.h b/board/redrix/board.h
index c79576769b..62abc99b6c 100644
--- a/board/redrix/board.h
+++ b/board/redrix/board.h
@@ -24,18 +24,6 @@
*/
#define CONFIG_HIBERNATE_PSL_VCC1_RST_WAKEUP
-/* LED */
-#define CONFIG_LED_PWM
-#define CONFIG_LED_PWM_COUNT 2
-#undef CONFIG_LED_PWM_NEAR_FULL_COLOR
-#undef CONFIG_LED_PWM_SOC_ON_COLOR
-#undef CONFIG_LED_PWM_SOC_SUSPEND_COLOR
-#undef CONFIG_LED_PWM_LOW_BATT_COLOR
-#define CONFIG_LED_PWM_NEAR_FULL_COLOR EC_LED_COLOR_WHITE
-#define CONFIG_LED_PWM_SOC_ON_COLOR EC_LED_COLOR_WHITE
-#define CONFIG_LED_PWM_SOC_SUSPEND_COLOR EC_LED_COLOR_WHITE
-#define CONFIG_LED_PWM_LOW_BATT_COLOR EC_LED_COLOR_AMBER
-
/* Sensors */
#define CONFIG_ACCELGYRO_LSM6DSO /* Base accel */
#define CONFIG_ACCEL_LSM6DSO_INT_EVENT \
@@ -240,12 +228,8 @@ enum battery_type {
};
enum pwm_channel {
- PWM_CH_LED2 = 0, /* PWM0 (white charger) */
- PWM_CH_LED3, /* PWM1 (orange on DB) */
- PWM_CH_LED1, /* PWM2 (orange charger) */
- PWM_CH_KBLIGHT, /* PWM3 */
+ PWM_CH_KBLIGHT = 0, /* PWM3 */
PWM_CH_FAN, /* PWM5 */
- PWM_CH_LED4, /* PWM7 (white on DB) */
PWM_CH_COUNT
};
diff --git a/board/redrix/ec.tasklist b/board/redrix/ec.tasklist
index 290c17c748..8fc5205931 100644
--- a/board/redrix/ec.tasklist
+++ b/board/redrix/ec.tasklist
@@ -26,4 +26,5 @@
TASK_ALWAYS(PD_C0, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS(PD_C1, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS(PD_INT_C0, pd_interrupt_handler_task, 0, TASK_STACK_SIZE) \
- TASK_ALWAYS(PD_INT_C1, pd_interrupt_handler_task, 1, TASK_STACK_SIZE)
+ TASK_ALWAYS(PD_INT_C1, pd_interrupt_handler_task, 1, TASK_STACK_SIZE) \
+ TASK_ALWAYS(LED, led_task, NULL, TASK_STACK_SIZE)
diff --git a/board/redrix/gpio.inc b/board/redrix/gpio.inc
index b996c85cd0..537ac7a6bb 100644
--- a/board/redrix/gpio.inc
+++ b/board/redrix/gpio.inc
@@ -77,6 +77,13 @@ GPIO(USB_C0_TCPC_RST_ODL, PIN(A, 7), GPIO_ODR_LOW)
GPIO(USB_C1_TCPC_RST_ODL, PIN(A, 0), GPIO_ODR_LOW)
GPIO(VCCST_PWRGD_OD, PIN(A, 4), GPIO_ODR_LOW)
+/* LED */
+GPIO(C0_CHARGE_LED_AMBER_L, PIN(C, 4), GPIO_OUT_HIGH) /* Amber C0 port */
+GPIO(C0_CHARGE_LED_WHITE_L, PIN(C, 3), GPIO_OUT_HIGH) /* White C0 port */
+GPIO(C1_CHARGE_LED_AMBER_L, PIN(5, 7), GPIO_OUT_HIGH) /* Amber C1 port */
+GPIO(C1_CHARGE_LED_WHITE_L, PIN(9, 4), GPIO_OUT_HIGH) /* White C1 port */
+GPIO(PWR_LED_WHITE_L, PIN(C, 2), GPIO_OUT_HIGH) /* Power LED */
+
/* UART alternate functions */
ALTERNATE(PIN_MASK(6, 0x30), 0, MODULE_UART, 0) /* GPIO64/CR_SIN1, GPO65/CR_SOUT1/FLPRG1_L */
@@ -95,7 +102,6 @@ ALTERNATE(PIN_MASK(4, 0x01), 0, MODULE_PWM, 0) /* GPIO40/TA1 */
ALTERNATE(PIN_MASK(6, 0x01), 0, MODULE_PWM, 0) /* GPIO60/PWM7 */
ALTERNATE(PIN_MASK(8, 0x01), 0, MODULE_PWM, 0) /* GPIO80/PWM3 */
ALTERNATE(PIN_MASK(B, 0x80), 0, MODULE_PWM, 0) /* GPIOB7/PWM5 */
-ALTERNATE(PIN_MASK(C, 0x1c), 0, MODULE_PWM, 0) /* GPIOC4/PWM2, GPIOC3/PWM0, GPIOC2/PWM1/I2C6_SCL0 */
/* ADC alternate functions */
ALTERNATE(PIN_MASK(3, 0x10), 0, MODULE_ADC, 0) /* GPIO34/PS2_DAT2/ADC6 */
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);
+ }
}
diff --git a/board/redrix/pwm.c b/board/redrix/pwm.c
index 263e494650..985305449b 100644
--- a/board/redrix/pwm.c
+++ b/board/redrix/pwm.c
@@ -11,21 +11,6 @@
#include "pwm_chip.h"
const struct pwm_t pwm_channels[] = {
- [PWM_CH_LED2] = {
- .channel = 0,
- .flags = PWM_CONFIG_ACTIVE_LOW | PWM_CONFIG_DSLEEP,
- .freq = 4800,
- },
- [PWM_CH_LED3] = {
- .channel = 1,
- .flags = PWM_CONFIG_ACTIVE_LOW | PWM_CONFIG_DSLEEP,
- .freq = 4800,
- },
- [PWM_CH_LED1] = {
- .channel = 2,
- .flags = PWM_CONFIG_ACTIVE_LOW | PWM_CONFIG_DSLEEP,
- .freq = 4800,
- },
[PWM_CH_KBLIGHT] = {
.channel = 3,
.flags = 0,
@@ -42,29 +27,11 @@ const struct pwm_t pwm_channels[] = {
.flags = PWM_CONFIG_OPEN_DRAIN,
.freq = 25000
},
- [PWM_CH_LED4] = {
- .channel = 7,
- .flags = PWM_CONFIG_ACTIVE_LOW | PWM_CONFIG_DSLEEP,
- .freq = 4800,
- },
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
static void board_pwm_init(void)
{
- /*
- * Turn on all the LED at 50%.
- * Turn on the fan at 100%.
- */
- pwm_enable(PWM_CH_LED1, 1);
- pwm_set_duty(PWM_CH_LED1, 50);
- pwm_enable(PWM_CH_LED2, 1);
- pwm_set_duty(PWM_CH_LED2, 50);
- pwm_enable(PWM_CH_LED3, 1);
- pwm_set_duty(PWM_CH_LED3, 50);
- pwm_enable(PWM_CH_LED4, 1);
- pwm_set_duty(PWM_CH_LED4, 50);
-
pwm_enable(PWM_CH_KBLIGHT, 1);
pwm_set_duty(PWM_CH_KBLIGHT, 50);
}