summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDevin Lu <Devin.Lu@quantatw.com>2021-11-11 20:03:28 +0800
committerCommit Bot <commit-bot@chromium.org>2021-12-24 02:39:46 +0000
commitb612ff517307550285fcc1c3df4cee82990a2c80 (patch)
tree7cccaadec9644fd10c23e0380c9cc21f32a19a7e
parent01b91c46e326e3af16f396a25a1c3b8a1e01dde4 (diff)
downloadchrome-ec-b612ff517307550285fcc1c3df4cee82990a2c80.tar.gz
vell: Implement charging leds
There are two set charging leds on the system (right side and left side). Each side has two colors: amber and white. LEDs and ports mapping as following: +-------------------------+ | LCD | | | | | +-------------------------+ PORT_C2 | | PORT_C1 PORT_C3 | | PORT_C0 | | +-------------------------+ 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 white (0.5 sec on, 0.5 sec off) Fuel < 10%: Blinking white on right side port (1 sec on, 1 sec off) BUG=b:203158255 BRANCH=none TEST=1. Attach charger on C0, C1 port. Left side led show amber. 2. Attach charger on C2, C3 port. Right side led show amber. 3. Attach charger on C0, C1 port. Left side led show white when battery fully charged. 4. Attach charger on C2, C3 port. Right side led show white when battery fully charged. Signed-off-by: Devin Lu <Devin.Lu@quantatw.com> Change-Id: I5c8370c58b4bde01d64b1d9fbb493277218f0d19 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3276023 Reviewed-by: Boris Mittelberg <bmbm@google.com> Reviewed-by: caveh jalali <caveh@chromium.org>
-rw-r--r--board/vell/board.h22
-rw-r--r--board/vell/ec.tasklist1
-rw-r--r--board/vell/gpio.inc8
-rw-r--r--board/vell/led.c223
-rw-r--r--board/vell/pwm.c30
5 files changed, 180 insertions, 104 deletions
diff --git a/board/vell/board.h b/board/vell/board.h
index a56e739a93..154cb95bdd 100644
--- a/board/vell/board.h
+++ b/board/vell/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
-
/* Buttons */
#undef CONFIG_VOLUME_BUTTONS
@@ -118,6 +106,10 @@
#define GPIO_POWER_BUTTON_L GPIO_GSC_EC_PWR_BTN_ODL
#define GPIO_SYS_RESET_L GPIO_SYS_RST_ODL
#define GPIO_WP_L GPIO_EC_WP_ODL
+#define GPIO_RIGHT_LED_AMBER_L GPIO_LED_1_L
+#define GPIO_RIGHT_LED_WHITE_L GPIO_LED_2_L
+#define GPIO_LEFT_LED_AMBER_L GPIO_LED_3_L
+#define GPIO_LEFT_LED_WHITE_L GPIO_LED_4_L
/* System has back-lit keyboard */
#define CONFIG_PWM_KBLIGHT
@@ -228,12 +220,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/vell/ec.tasklist b/board/vell/ec.tasklist
index d615df8c6f..924d708a6b 100644
--- a/board/vell/ec.tasklist
+++ b/board/vell/ec.tasklist
@@ -12,6 +12,7 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, HOOKS_TASK_STACK_SIZE) \
+ TASK_ALWAYS(LED, led_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CHG_RAMP, chg_ramp_task, NULL, BASEBOARD_CHG_RAMP_TASK_STACK_SIZE) \
TASK_ALWAYS(USB_CHG_P0, usb_charger_task, 0, TASK_STACK_SIZE) \
TASK_ALWAYS(USB_CHG_P1, usb_charger_task, 0, TASK_STACK_SIZE) \
diff --git a/board/vell/gpio.inc b/board/vell/gpio.inc
index a9d3e72445..62ab9e0969 100644
--- a/board/vell/gpio.inc
+++ b/board/vell/gpio.inc
@@ -76,6 +76,12 @@ GPIO(USB_C0_C1_TCPC_RST_ODL, PIN(A, 7), GPIO_ODR_LOW)
GPIO(USB_C2_C3_TCPC_RST_ODL, PIN(9, 6), GPIO_ODR_LOW)
GPIO(VCCST_PWRGD_OD, PIN(A, 4), GPIO_ODR_LOW)
+/* LED */
+GPIO(LED_1_L, PIN(C, 4), GPIO_OUT_HIGH)
+GPIO(LED_2_L, PIN(C, 3), GPIO_OUT_HIGH)
+GPIO(LED_3_L, PIN(C, 2), GPIO_OUT_HIGH)
+GPIO(LED_4_L, PIN(6, 0), GPIO_OUT_HIGH)
+
/* UART alternate functions */
ALTERNATE(PIN_MASK(6, 0x30), 0, MODULE_UART, 0) /* GPIO64/CR_SIN1, GPO65/CR_SOUT1/FLPRG1_L */
@@ -91,10 +97,8 @@ ALTERNATE(PIN_MASK(F, 0x0c), 0, MODULE_I2C, 0) /* GPIOF3/I2C4_SCL1
/* PWM alternate functions */
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/vell/led.c b/board/vell/led.c
index 68945ec79e..48555f8de7 100644
--- a/board/vell/led.c
+++ b/board/vell/led.c
@@ -1,93 +1,206 @@
/* 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 Vell
*/
#include <stdint.h>
-#include "common.h"
-#include "compile_time_macros.h"
+#include "battery.h"
+#include "charge_manager.h"
+#include "charge_state.h"
#include "ec_commands.h"
-#include "led_pwm.h"
-#include "pwm.h"
+#include "gpio.h"
+#include "host_command.h"
+#include "led_common.h"
+#include "task.h"
#include "util.h"
+#define BAT_LED_ON 0
+#define BAT_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_RIGHT_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_color_map 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 {
+ RIGHT_PORT = 0,
+ LEFT_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_RIGHT_LED_AMBER_L :
+ GPIO_LEFT_LED_AMBER_L);
+ white_led = (port == RIGHT_PORT ? GPIO_RIGHT_LED_WHITE_L :
+ GPIO_LEFT_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_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;
+ 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;
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);
- else
- /* Otherwise, the "color" is "off". */
- set_pwm_led_color(pwm_id, -1);
-
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 usbc_port = charge_manager_get_active_charge_port();
+ int port = 0;
+
+ if ((usbc_port == USBC_PORT_C0) || (usbc_port == USBC_PORT_C1))
+ port = RIGHT_PORT;
+ else if ((usbc_port == USBC_PORT_C2) || (usbc_port == USBC_PORT_C3))
+ port = LEFT_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 & 0x1) ?
+ 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;
+ }
+}
+
+void led_task(void *u)
+{
+ uint32_t start_time;
+ uint32_t task_duration;
+
+ while (1) {
+ start_time = get_time().le.lo;
+
+ 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/vell/pwm.c b/board/vell/pwm.c
index 6e662f8e7d..8535de88e1 100644
--- a/board/vell/pwm.c
+++ b/board/vell/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,11 +27,6 @@ const struct pwm_t pwm_channels[] = {
.flags = PWM_CONFIG_OPEN_DRAIN | PWM_CONFIG_DSLEEP,
.freq = 1000
},
- [PWM_CH_LED4] = {
- .channel = 7,
- .flags = PWM_CONFIG_ACTIVE_LOW | PWM_CONFIG_DSLEEP,
- .freq = 4800,
- },
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
@@ -54,17 +34,7 @@ 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);
}