From 1f091487b210125e351c8397186e2012d8a19cb7 Mon Sep 17 00:00:00 2001 From: David Hendricks Date: Wed, 8 Aug 2012 17:28:13 -0700 Subject: snow/stm32: re-configure power LED on the fly (input vs. pwm) Usually the power LED is driven by the PWM mode so that its nominal brightness can be set to a "soft" on value. However, when the LED is to remain off the LED should be switched to floating input mode. This reduces voltage leakage. This CL updates the power_led_task to configure the LED however is appropriate and adds board functions to re-configure the GPIO. Signed-off-by: David Hendricks BRANCH=snow BUG=chrome-os-partner:12381 TEST=LED responds as expected in suspend and on/off states, also tested that leakage is reduced with multimeter Change-Id: If90ac78aaffe7358cce80dd02ec1423c2cb4f664 Reviewed-on: https://gerrit.chromium.org/gerrit/29705 Reviewed-by: Simon Glass Commit-Ready: David Hendricks Tested-by: David Hendricks --- board/snow/board.c | 36 ++++++++++++++++++++++++++++++----- board/snow/board.h | 1 + chip/stm32/power_led.c | 51 +++++++++++++++++++++++++++++++++++++++++++------- include/power_led.h | 6 ++++++ 4 files changed, 82 insertions(+), 12 deletions(-) diff --git a/board/snow/board.c b/board/snow/board.c index 50fcdfd04c..b612955af3 100644 --- a/board/snow/board.c +++ b/board/snow/board.c @@ -12,6 +12,7 @@ #include "gpio.h" #include "i2c.h" #include "pmu_tpschrome.h" +#include "power_led.h" #include "registers.h" #include "spi.h" #include "timer.h" @@ -67,6 +68,7 @@ const struct gpio_info gpio_list[GPIO_COUNT] = { {"CHARGER_EN", GPIO_B, (1<<2), GPIO_OUT_LOW, NULL}, {"EC_INT", GPIO_B, (1<<9), GPIO_HI_Z, NULL}, {"CODEC_INT", GPIO_D, (1<<1), GPIO_HI_Z, NULL}, + {"LED_POWER_L", GPIO_B, (1<<3), GPIO_INPUT, NULL}, {"KB_OUT00", GPIO_B, (1<<0), GPIO_KB_OUTPUT, NULL}, {"KB_OUT01", GPIO_B, (1<<8), GPIO_KB_OUTPUT, NULL}, {"KB_OUT02", GPIO_B, (1<<12), GPIO_KB_OUTPUT, NULL}, @@ -107,11 +109,6 @@ void configure_board(void) STM32_GPIO_AFIO_MAPR = (STM32_GPIO_AFIO_MAPR & ~(0x3 << 8)) | (1 << 8); - /* set power LED to alternate function to be driven by TIM2/PWM */ - val = STM32_GPIO_CRL_OFF(GPIO_B) & ~0x0000f000; - val |= 0x00009000; - STM32_GPIO_CRL_OFF(GPIO_B) = val; - /* * I2C SCL/SDA on PB10-11 and PB6-7, bi-directional, no pull-up/down, * initialized as hi-Z until alt. function is set @@ -152,6 +149,35 @@ void board_keyboard_suppress_noise(void) gpio_set_level(GPIO_CODEC_INT, 1); } +void board_power_led_config(enum powerled_config config) +{ + uint32_t val; + + switch (config) { + case POWERLED_CONFIG_PWM: + val = STM32_GPIO_CRL_OFF(GPIO_B) & ~0x0000f000; + val |= 0x00009000; /* alt. function (TIM2/PWM) */ + STM32_GPIO_CRL_OFF(GPIO_B) = val; + break; + case POWERLED_CONFIG_MANUAL_OFF: + /* + * Re-configure GPIO as a floating input. Alternatively we could + * configure it as an open-drain output and set it to high + * impedence, but reconfiguring as an input had better results + * in testing. + */ + gpio_set_flags(GPIO_LED_POWER_L, GPIO_INPUT); + gpio_set_level(GPIO_LED_POWER_L, 1); + break; + case POWERLED_CONFIG_MANUAL_ON: + gpio_set_flags(GPIO_LED_POWER_L, GPIO_OUTPUT | GPIO_OPEN_DRAIN); + gpio_set_level(GPIO_LED_POWER_L, 0); + break; + default: + break; + } +} + enum { /* Time between requesting bus and deciding that we have it */ BUS_SLEW_DELAY_US = 10, diff --git a/board/snow/board.h b/board/snow/board.h index c7ecae04e7..07b29f0fb7 100644 --- a/board/snow/board.h +++ b/board/snow/board.h @@ -87,6 +87,7 @@ enum gpio_signal { GPIO_CHARGER_EN, GPIO_EC_INT, GPIO_CODEC_INT, /* To audio codec (KB noise cancellation) */ + GPIO_LED_POWER_L, /* Keyboard power LED */ GPIO_KB_OUT00, GPIO_KB_OUT01, GPIO_KB_OUT02, diff --git a/chip/stm32/power_led.c b/chip/stm32/power_led.c index a080dbfa07..bc354ee492 100644 --- a/chip/stm32/power_led.c +++ b/chip/stm32/power_led.c @@ -7,7 +7,8 @@ * Keyboard power button LED state machine. * * This sets up TIM2 to drive the power button LED so that the duty cycle - * can range from 0-100%. + * can range from 0-100%. When the lid is closed or turned off, then the + * PWM is disabled and the GPIO is reconfigured to minimize leakage voltage. * * In suspend mode, duty cycle transitions progressively slower from 0% * to 100%, and progressively faster from 100% back down to 0%. This @@ -25,8 +26,9 @@ #define LED_HOLD_TIME 330000 /* hold for 330ms at min/max */ #define LED_STEP_PERCENT 4 /* incremental value of each step */ -static enum powerled_state led_state; -static int power_led_percent; +static enum powerled_state led_state = POWERLED_STATE_ON; +static enum powerled_config led_config = POWERLED_CONFIG_MANUAL_OFF; +static int power_led_percent = 100; void powerled_set_state(enum powerled_state new_state) { @@ -35,8 +37,19 @@ void powerled_set_state(enum powerled_state new_state) task_wake(TASK_ID_POWERLED); } -static void power_led_timer_init(void) +/* set board-level power LED config options (e.g. manual off/on, PWM) */ +void board_power_led_config(enum powerled_state config) + __attribute__((weak, alias("__board_power_led_config"))); + +/* Provide a default function in case the board doesn't have one */ +void __board_power_led_config(enum powerled_config config) +{ +} + +static void power_led_use_pwm(void) { + board_power_led_config(POWERLED_CONFIG_PWM); + /* enable TIM2 clock */ STM32_RCC_APB1ENR |= 0x1; @@ -66,6 +79,20 @@ static void power_led_timer_init(void) /* enable auto-reload preload, start counting */ STM32_TIM_CR1(2) |= (1 << 7) | (1 << 0); + + led_config = POWERLED_CONFIG_PWM; +} + +static void power_led_manual_off(void) +{ + /* disable counter */ + STM32_TIM_CR1(2) &= ~0x1; + + /* disable TIM2 clock */ + STM32_RCC_APB1ENR &= ~0x1; + + board_power_led_config(POWERLED_CONFIG_MANUAL_OFF); + led_config = POWERLED_CONFIG_MANUAL_OFF; } static void power_led_set_duty(int percent) @@ -109,21 +136,31 @@ static int power_led_step(void) void power_led_task(void) { - power_led_timer_init(); - while (1) { int state_timeout = -1; switch (led_state) { case POWERLED_STATE_ON: + /* + * "ON" implies driving the LED using the PWM with a + * duty duty cycle of 100%. This produces a softer + * brightness than setting the GPIO to solid ON. + */ + if (led_config != POWERLED_CONFIG_PWM) + power_led_use_pwm(); power_led_set_duty(100); state_timeout = -1; break; case POWERLED_STATE_OFF: - power_led_set_duty(0); + /* reconfigure GPIO to disable the LED */ + if (led_config != POWERLED_CONFIG_MANUAL_OFF) + power_led_manual_off(); state_timeout = -1; break; case POWERLED_STATE_SUSPEND: + /* drive using PWM with variable duty cycle */ + if (led_config != POWERLED_CONFIG_PWM) + power_led_use_pwm(); state_timeout = power_led_step(); break; default: diff --git a/include/power_led.h b/include/power_led.h index 9301a5fdf5..b255c557bb 100644 --- a/include/power_led.h +++ b/include/power_led.h @@ -25,6 +25,12 @@ enum powerled_state { POWERLED_STATE_COUNT }; +enum powerled_config { + POWERLED_CONFIG_MANUAL_OFF, + POWERLED_CONFIG_MANUAL_ON, + POWERLED_CONFIG_PWM, +}; + /* Set the power adapter LED to the specified color. */ int powerled_set(enum powerled_color color); -- cgit v1.2.1