summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
}