diff options
-rw-r--r-- | board/redrix/board.h | 18 | ||||
-rw-r--r-- | board/redrix/ec.tasklist | 3 | ||||
-rw-r--r-- | board/redrix/gpio.inc | 8 | ||||
-rw-r--r-- | board/redrix/led.c | 263 | ||||
-rw-r--r-- | board/redrix/pwm.c | 33 |
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); } |