summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-10-07 10:59:45 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-10-08 20:41:32 +0000
commitff8c8fee79e148567c0f2128db69563acb29ee54 (patch)
tree0d3daa52c091a36c997c0cd42be8267678a13f7f
parent99157c265c8353e166059e17d250d9991d4e7ae0 (diff)
downloadchrome-ec-ff8c8fee79e148567c0f2128db69563acb29ee54.tar.gz
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
-rw-r--r--board/host/board.h1
-rw-r--r--board/rambi/board.c6
-rw-r--r--board/rambi/board.h1
-rw-r--r--board/rambi/build.mk2
-rw-r--r--board/rambi/led.c45
-rw-r--r--chip/lm4/build.mk3
-rw-r--r--chip/lm4/pwm.c15
-rw-r--r--chip/stm32/pwm.c5
-rw-r--r--common/build.mk8
-rw-r--r--common/pwm_common.c63
-rw-r--r--common/pwm_kblight.c (renamed from chip/lm4/pwm_kblight.c)7
-rw-r--r--include/hooks.h2
12 files changed, 137 insertions, 21 deletions
diff --git a/board/host/board.h b/board/host/board.h
index 6db70771ff..2529e15bc1 100644
--- a/board/host/board.h
+++ b/board/host/board.h
@@ -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
diff --git a/board/rambi/board.c b/board/rambi/board.c
index b864de5ef1..7a6f926763 100644
--- a/board/rambi/board.c
+++ b/board/rambi/board.c
@@ -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);
diff --git a/board/rambi/board.h b/board/rambi/board.h
index d9f038e850..2fdb718013 100644
--- a/board/rambi/board.h
+++ b/board/rambi/board.h
@@ -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
diff --git a/board/rambi/build.mk b/board/rambi/build.mk
index 1843369ed4..ea89781339 100644
--- a/board/rambi/build.mk
+++ b/board/rambi/build.mk
@@ -9,4 +9,4 @@
# the IC is TI Stellaris LM4
CHIP:=lm4
-board-y=board.o
+board-y=board.o led.o
diff --git a/board/rambi/led.c b/board/rambi/led.c
new file mode 100644
index 0000000000..451aae2bc3
--- /dev/null
+++ b/board/rambi/led.c
@@ -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);
diff --git a/chip/lm4/build.mk b/chip/lm4/build.mk
index 26532d347a..74ecd64d02 100644
--- a/chip/lm4/build.mk
+++ b/chip/lm4/build.mk
@@ -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
diff --git a/chip/lm4/pwm.c b/chip/lm4/pwm.c
index 5d797ded3a..68aae8fc8c 100644
--- a/chip/lm4/pwm.c
+++ b/chip/lm4/pwm.c
@@ -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;
+
+ if (pwm->flags & PWM_CONFIG_ACTIVE_LOW)
+ percent = 100 - percent;
- return (LM4_FAN_FANCMD(pwm->channel) >> 16) * 100 / MAX_PWM;
+ 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);
diff --git a/chip/stm32/pwm.c b/chip/stm32/pwm.c
index 73db55334f..f9b1aeec10 100644
--- a/chip/stm32/pwm.c
+++ b/chip/stm32/pwm.c
@@ -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;
diff --git a/common/build.mk b/common/build.mk
index d4151e0245..7fa8e043d4 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -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
diff --git a/common/pwm_common.c b/common/pwm_common.c
new file mode 100644
index 0000000000..3a3073d142
--- /dev/null
+++ b/common/pwm_common.c
@@ -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);
diff --git a/chip/lm4/pwm_kblight.c b/common/pwm_kblight.c
index f76f0399e1..41448ce7e8 100644
--- a/chip/lm4/pwm_kblight.c
+++ b/common/pwm_kblight.c
@@ -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 */
diff --git a/include/hooks.h b/include/hooks.h
index da46610505..fb3e6c236b 100644
--- a/include/hooks.h
+++ b/include/hooks.h
@@ -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,