rambi: Control LEDs using PWM

Rambi has a pair of LEDs which are attached to the PWM fan controller.
Add support for them.  Also add a generic 'pwmduty' command which can
be used to get/set the duty cycle for any PWM channel.

Also fix rounding errors in pwm module, so that set/get duty doesn't
keep rounding down.

BUG=chrome-os-partner:22895
BRANCH=none
TEST=Boot rambi. LEDs are off.
     pwmduty -> both are 0%
     pwmduty 0 10 -> green LED on dimly
     pwmduty 1 10 -> red LED on dimly
     pwmduty 0 99 -> green LED on brightly
     pwmduty 1 100 -> red LED on brightly
     pwmduty 1 0 -> red LED off
     pwmduty 1 -1 -> red LED turns back on because fan controller is disabled
     pwmduty -> channel 0 at 99%, channel 1 disabled
     Build all platforms.  Pass all unit tests.

Change-Id: Ib0a6289a757554e696a9a0153a85bdc34e2ee2ae
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/172094
This commit is contained in:
Randall Spangler
2013-10-07 10:59:45 -07:00
committed by chrome-internal-fetch
parent 99157c265c
commit ff8c8fee79
12 changed files with 137 additions and 21 deletions

View File

@@ -14,7 +14,6 @@
#define CONFIG_KEYBOARD_PROTOCOL_MKBP
#define CONFIG_POWER_BUTTON
#undef CONFIG_WATCHDOG
#define CONFIG_PWM
#define CONFIG_SWITCH
#undef CONFIG_CONSOLE_HISTORY

View File

@@ -110,7 +110,7 @@ const struct gpio_alt_func gpio_alt_funcs[] = {
{GPIO_D, 0x0f, 2, MODULE_SPI}, /* SPI1 */
{GPIO_L, 0x3f, 15, MODULE_LPC}, /* LPC */
{GPIO_M, 0x33, 15, MODULE_LPC}, /* LPC */
{GPIO_N, 0x50, 1, MODULE_PWM_LED}, /* Power LEDs */
{GPIO_N, 0x50, 1, MODULE_PWM_LED, GPIO_OPEN_DRAIN}, /* Power LEDs */
};
const int gpio_alt_funcs_count = ARRAY_SIZE(gpio_alt_funcs);
@@ -152,8 +152,8 @@ BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
/* PWM channels */
const struct pwm_t pwm_channels[] = {
[PWM_CH_LED_GREEN] = {4, 0},
[PWM_CH_LED_RED] = {3, 0},
[PWM_CH_LED_GREEN] = {4, PWM_CONFIG_ACTIVE_LOW},
[PWM_CH_LED_RED] = {3, PWM_CONFIG_ACTIVE_LOW},
};
BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);

View File

@@ -14,6 +14,7 @@
#define CONFIG_CMD_GSV
#define CONFIG_EXTPOWER_GPIO
#define CONFIG_KEYBOARD_PROTOCOL_8042
#define CONFIG_LED_COMMON
#undef CONFIG_PECI
#define CONFIG_POWER_BUTTON
#define CONFIG_POWER_BUTTON_X86

View File

@@ -9,4 +9,4 @@
# the IC is TI Stellaris LM4
CHIP:=lm4
board-y=board.o
board-y=board.o led.o

45
board/rambi/led.c Normal file
View File

@@ -0,0 +1,45 @@
/* Copyright (c) 2013 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.
*
* Battery LED control for Rambi
*/
#include "gpio.h"
#include "hooks.h"
#include "led_common.h"
#include "pwm.h"
#include "util.h"
const enum ec_led_id supported_led_ids[] = {EC_LED_ID_BATTERY_LED};
const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids);
void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range)
{
brightness_range[EC_LED_COLOR_RED] = 100;
brightness_range[EC_LED_COLOR_GREEN] = 100;
}
int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness)
{
pwm_set_duty(PWM_CH_LED_RED, brightness[EC_LED_COLOR_RED]);
pwm_set_duty(PWM_CH_LED_GREEN, brightness[EC_LED_COLOR_GREEN]);
return EC_SUCCESS;
}
static void led_init(void)
{
/* Configure GPIOs */
gpio_config_module(MODULE_PWM_LED, 1);
/*
* Enable PWMs and set to 0% duty cycle. If they're disabled, the LM4
* seems to ground the pins instead of letting them float.
*/
pwm_enable(PWM_CH_LED_RED, 1);
pwm_set_duty(PWM_CH_LED_RED, 0);
pwm_enable(PWM_CH_LED_GREEN, 1);
pwm_set_duty(PWM_CH_LED_GREEN, 0);
}
DECLARE_HOOK(HOOK_INIT, led_init, HOOK_PRIO_DEFAULT);

View File

@@ -15,13 +15,12 @@ chip-y=clock.o gpio.o hwtimer.o jtag.o system.o uart.o
# Optional chip modules
chip-$(CONFIG_ADC)+=adc.o chip_temp_sensor.o
chip-$(CONFIG_EEPROM)+=eeprom.o
chip-$(CONFIG_FAN)+=fan.o
chip-$(CONFIG_FLASH)+=flash.o
chip-$(CONFIG_I2C)+=i2c.o
chip-$(CONFIG_LPC)+=lpc.o
chip-$(CONFIG_PECI)+=peci.o
chip-$(CONFIG_PWM)+=pwm.o
chip-$(CONFIG_FAN)+=fan.o
chip-$(CONFIG_PWM_KBLIGHT)+=pwm_kblight.o
chip-$(CONFIG_SPI)+=spi.o
chip-$(CONFIG_WATCHDOG)+=watchdog.o
chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o

View File

@@ -11,7 +11,6 @@
#include "pwm.h"
#include "pwm_data.h"
#include "registers.h"
#include "thermal.h"
#include "util.h"
/* Maximum RPM for PWM controller */
@@ -47,7 +46,10 @@ void pwm_set_duty(enum pwm_channel ch, int percent)
else if (percent > 100)
percent = 100;
duty = (MAX_PWM * percent) / 100;
if (pwm->flags & PWM_CONFIG_ACTIVE_LOW)
percent = 100 - percent;
duty = (MAX_PWM * percent + 50) / 100;
/* Always enable the channel */
pwm_enable(ch, 1);
@@ -59,8 +61,13 @@ void pwm_set_duty(enum pwm_channel ch, int percent)
int pwm_get_duty(enum pwm_channel ch)
{
const struct pwm_t *pwm = pwm_channels + ch;
int percent = ((LM4_FAN_FANCMD(pwm->channel) >> 16) * 100 + MAX_PWM / 2)
/ MAX_PWM;
return (LM4_FAN_FANCMD(pwm->channel) >> 16) * 100 / MAX_PWM;
if (pwm->flags & PWM_CONFIG_ACTIVE_LOW)
percent = 100 - percent;
return percent;
}
static void pwm_init(void)
@@ -109,4 +116,4 @@ static void pwm_init(void)
}
}
}
DECLARE_HOOK(HOOK_INIT, pwm_init, HOOK_PRIO_DEFAULT);
DECLARE_HOOK(HOOK_INIT, pwm_init, HOOK_PRIO_INIT_PWM);

View File

@@ -135,6 +135,11 @@ void pwm_enable(enum pwm_channel ch, int enabled)
pwm_disable(ch);
}
int pwm_get_enabled(enum pwm_channel ch)
{
return using_pwm[ch];
}
static void pwm_reconfigure(enum pwm_channel ch)
{
using_pwm[ch] = 0;

View File

@@ -37,6 +37,7 @@ common-$(CONFIG_EXTPOWER_FALCO)+=extpower_falco.o
common-$(CONFIG_EXTPOWER_GPIO)+=extpower_gpio.o
common-$(CONFIG_EXTPOWER_KIRBY)+=extpower_kirby.o
common-$(CONFIG_EXTPOWER_SPRING)+=extpower_spring.o
common-$(CONFIG_FAN)+=pwm_fan.o
common-$(CONFIG_FLASH)+=flash_common.o
common-$(CONFIG_FMAP)+=fmap.o
common-$(CONFIG_I2C)+=i2c_common.o
@@ -53,16 +54,17 @@ common-$(CONFIG_ONEWIRE)+=onewire.o
common-$(CONFIG_POWER_BUTTON)+=power_button.o
common-$(CONFIG_POWER_BUTTON_X86)+=power_button_x86.o
common-$(CONFIG_PSTORE)+=pstore_commands.o
common-$(CONFIG_FAN)+=pwm_fan.o
common-$(CONFIG_PWM)+=pwm_common.o
common-$(CONFIG_PWM_KBLIGHT)+=pwm_kblight.o
common-$(CONFIG_REGULATOR_IR357X)+=regulator_ir357x.o
common-$(CONFIG_SWITCH)+=switch.o
common-$(CONFIG_WIRELESS)+=wireless.o
common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o thermal.o
common-$(CONFIG_TEMP_SENSOR_G781)+=temp_sensor_g781.o
common-$(CONFIG_TEMP_SENSOR_TMP006)+=temp_sensor_tmp006.o
common-$(CONFIG_USB_PORT_POWER_SMART)+=usb_port_power_smart.o
common-$(CONFIG_USB_PORT_POWER_DUMB)+=usb_port_power_dumb.o
common-$(CONFIG_USB_PORT_POWER_SMART)+=usb_port_power_smart.o
common-$(CONFIG_USB_SWITCH_TSU6721)+=usb_switch_tsu6721.o
common-$(CONFIG_WIRELESS)+=wireless.o
common-$(HAS_TASK_CHIPSET)+=chipset.o
common-$(HAS_TASK_CONSOLE)+=console.o
common-$(HAS_TASK_HOSTCMD)+=host_command.o host_event_commands.o

63
common/pwm_common.c Normal file
View File

@@ -0,0 +1,63 @@
/* Copyright (c) 2013 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.
*/
#include "common.h"
#include "console.h"
#include "pwm.h"
#include "util.h"
/**
* Print status of a PWM channel.
*
* @param ch Channel to print.
*/
static void print_channel(enum pwm_channel ch)
{
if (pwm_get_enabled(ch))
ccprintf(" %d: %d%%\n", ch, pwm_get_duty(ch));
else
ccprintf(" %d: disabled\n", ch);
}
static int cc_pwm_duty(int argc, char **argv)
{
int percent = 0;
int ch;
char *e;
if (argc < 2) {
ccprintf("PWM channels:\n");
for (ch = 0; ch < PWM_CH_COUNT; ch++)
print_channel(ch);
return EC_SUCCESS;
}
ch = strtoi(argv[1], &e, 0);
if (*e || ch < 0 || ch >= PWM_CH_COUNT)
return EC_ERROR_PARAM1;
if (argc > 2) {
percent = strtoi(argv[2], &e, 0);
if (*e || percent > 100) {
/* Bad param */
return EC_ERROR_PARAM1;
} else if (percent < 0) {
/* Negative = disable */
pwm_enable(ch, 0);
} else {
ccprintf("Setting channel %d to %d%%\n", ch, percent);
pwm_enable(ch, 1);
pwm_set_duty(ch, percent);
}
}
print_channel(ch);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(pwmduty, cc_pwm_duty,
"[channel [<percent> | -1=disable]]",
"Get/set PWM duty cycles ",
NULL);

View File

@@ -5,7 +5,6 @@
/* PWM control module for Chromebook keyboard backlight. */
#include "clock.h"
#include "common.h"
#include "console.h"
#include "gpio.h"
@@ -13,15 +12,9 @@
#include "host_command.h"
#include "lid_switch.h"
#include "pwm.h"
#include "registers.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#include "util.h"
/* Max PWM for controller */
#define MAX_PWM 0x1ff
#define PWMKBD_SYSJUMP_TAG 0x504b /* "PK" */
#define PWM_HOOK_VERSION 1
/* Saved PWM state across sysjumps */

View File

@@ -27,6 +27,8 @@ enum hook_priority {
HOOK_PRIO_INIT_LID = HOOK_PRIO_FIRST + 3,
/* Power button inits before chipset and switch */
HOOK_PRIO_INIT_POWER_BUTTON = HOOK_PRIO_FIRST + 4,
/* PWM inits before modules which might use it (fans, LEDs) */
HOOK_PRIO_INIT_PWM = HOOK_PRIO_FIRST + 5,
/* Specific values to lump temperature-related hooks together */
HOOK_PRIO_TEMP_SENSOR = 6000,