mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-28 02:35:28 +00:00
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 <dhendrix@chromium.org> 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 <sjg@chromium.org> Commit-Ready: David Hendricks <dhendrix@chromium.org> Tested-by: David Hendricks <dhendrix@chromium.org>
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user