diff options
-rw-r--r-- | common/build.mk | 2 | ||||
-rw-r--r-- | common/lb_common.c | 270 | ||||
-rw-r--r-- | common/lightbar.c | 290 | ||||
-rw-r--r-- | include/lb_common.h | 38 |
4 files changed, 316 insertions, 284 deletions
diff --git a/common/build.mk b/common/build.mk index 7189a07432..07ea8e2ba9 100644 --- a/common/build.mk +++ b/common/build.mk @@ -71,7 +71,7 @@ common-$(HAS_TASK_CONSOLE)+=console.o console_output.o uart_buffering.o common-$(HAS_TASK_CONSOLE)+=memory_commands.o common-$(HAS_TASK_HOSTCMD)+=acpi.o host_command.o host_event_commands.o common-$(HAS_TASK_KEYSCAN)+=keyboard_scan.o -common-$(HAS_TASK_LIGHTBAR)+=lightbar.o +common-$(HAS_TASK_LIGHTBAR)+=lb_common.o lightbar.o common-$(HAS_TASK_MOTIONSENSE)+=motion_sense.o math_util.o common-$(TEST_BUILD)+=test_util.o diff --git a/common/lb_common.c b/common/lb_common.c new file mode 100644 index 0000000000..1cb49cd096 --- /dev/null +++ b/common/lb_common.c @@ -0,0 +1,270 @@ +/* Copyright (c) 2012 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. + * + * Lightbar IC interface + */ + +#include "common.h" +#include "console.h" +#include "ec_commands.h" +#include "i2c.h" +#include "lb_common.h" +#include "util.h" + +/* Console output macros */ +#define CPUTS(outstr) cputs(CC_LIGHTBAR, outstr) +#define CPRINTF(format, args...) cprintf(CC_LIGHTBAR, format, ## args) + +/******************************************************************************/ +/* How to talk to the controller */ +/******************************************************************************/ + +/* Since there's absolutely nothing we can do about it if an I2C access + * isn't working, we're completely ignoring any failures. */ + +static const uint8_t i2c_addr[] = { 0x54, 0x56 }; + +static inline void controller_write(int ctrl_num, uint8_t reg, uint8_t val) +{ + ctrl_num = ctrl_num % ARRAY_SIZE(i2c_addr); + i2c_write8(I2C_PORT_LIGHTBAR, i2c_addr[ctrl_num], reg, val); +} + +static inline uint8_t controller_read(int ctrl_num, uint8_t reg) +{ + int val = 0; + ctrl_num = ctrl_num % ARRAY_SIZE(i2c_addr); + i2c_read8(I2C_PORT_LIGHTBAR, i2c_addr[ctrl_num], reg, &val); + return val; +} + +/******************************************************************************/ +/* Controller details. We have an ADP8861 and and ADP8863, but we can treat + * them identically for our purposes */ +/******************************************************************************/ + +#ifdef BOARD_BDS +/* We need to limit the total current per ISC to no more than 20mA (5mA per + * color LED, but we have four LEDs in parallel on each ISC). Any more than + * that runs the risk of damaging the LED component. A value of 0x67 is as high + * as we want (assuming Square Law), but the blue LED is the least bright, so + * I've lowered the other colors until they all appear approximately equal + * brightness when full on. That's still pretty bright and a lot of current + * drain on the battery, so we'll probably rarely go that high. */ +#define MAX_RED 0x5c +#define MAX_GREEN 0x30 +#define MAX_BLUE 0x67 +#endif +#ifdef BOARD_LINK +/* Link uses seven segments, not four, but keep the same limits anyway */ +#define MAX_RED 0x5c +#define MAX_GREEN 0x30 +#define MAX_BLUE 0x67 +#endif +#ifdef BOARD_SAMUS +/* Samus uses completely different LEDs, so the numbers are different */ +#define MAX_RED 0x4f +#define MAX_GREEN 0x55 +#define MAX_BLUE 0x67 +#endif + +/* How we'd like to see the driver chips initialized. The controllers have some + * auto-cycling capability, but it's not much use for our purposes. For now, + * we'll just control all color changes actively. */ +struct initdata_s { + uint8_t reg; + uint8_t val; +}; + +static const struct initdata_s init_vals[] = { + {0x04, 0x00}, /* no backlight function */ + {0x05, 0x3f}, /* xRGBRGB per chip */ + {0x0f, 0x01}, /* square law looks better */ + {0x10, 0x3f}, /* enable independent LEDs */ + {0x11, 0x00}, /* no auto cycling */ + {0x12, 0x00}, /* no auto cycling */ + {0x13, 0x00}, /* instant fade in/out */ + {0x14, 0x00}, /* not using LED 7 */ + {0x15, 0x00}, /* current for LED 6 (blue) */ + {0x16, 0x00}, /* current for LED 5 (red) */ + {0x17, 0x00}, /* current for LED 4 (green) */ + {0x18, 0x00}, /* current for LED 3 (blue) */ + {0x19, 0x00}, /* current for LED 2 (red) */ + {0x1a, 0x00}, /* current for LED 1 (green) */ +}; + +static void set_from_array(const struct initdata_s *data, int count) +{ + int i; + for (i = 0; i < count; i++) { + controller_write(0, data[i].reg, data[i].val); + controller_write(1, data[i].reg, data[i].val); + } +} + +/* Controller register lookup tables. */ +static const uint8_t led_to_ctrl[] = { 1, 1, 0, 0 }; +#ifdef BOARD_BDS +static const uint8_t led_to_isc[] = { 0x18, 0x15, 0x18, 0x15 }; +#endif +#ifdef BOARD_LINK +static const uint8_t led_to_isc[] = { 0x18, 0x15, 0x18, 0x15 }; +#endif +#ifdef BOARD_SAMUS +static const uint8_t led_to_isc[] = { 0x15, 0x18, 0x15, 0x18 }; +#endif + +/* Scale 0-255 into max value */ +static inline uint8_t scale_abs(int val, int max) +{ + return (val * max)/255; +} + +/* This is the overall brightness control. */ +static int brightness = 0xc0; + +/* So that we can make brightness changes happen instantly, we need to track + * the current values. The values in the controllers aren't very helpful. */ +static uint8_t current[NUM_LEDS][3]; + +/* Scale 0-255 by brightness */ +static inline uint8_t scale(int val, int max) +{ + return scale_abs((val * brightness)/255, max); +} + +/* Helper function to set one LED color and remember it for later */ +static void setrgb(int led, int red, int green, int blue) +{ + int ctrl, bank; + current[led][0] = red; + current[led][1] = green; + current[led][2] = blue; + ctrl = led_to_ctrl[led]; + bank = led_to_isc[led]; + controller_write(ctrl, bank, scale(blue, MAX_BLUE)); + controller_write(ctrl, bank+1, scale(red, MAX_RED)); + controller_write(ctrl, bank+2, scale(green, MAX_GREEN)); +} + +/* LEDs are numbered 0-3, RGB values should be in 0-255. + * If you specify too large an LED, it sets them all. */ +void lb_set_rgb(unsigned int led, int red, int green, int blue) +{ + int i; + if (led >= NUM_LEDS) + for (i = 0; i < NUM_LEDS; i++) + setrgb(i, red, green, blue); + else + setrgb(led, red, green, blue); +} + +/* Get current LED values, if the LED number is in range. */ +int lb_get_rgb(unsigned int led, uint8_t *red, uint8_t *green, uint8_t *blue) +{ + if (led < 0 || led >= NUM_LEDS) + return EC_RES_INVALID_PARAM; + + *red = current[led][0]; + *green = current[led][1]; + *blue = current[led][2]; + + return EC_RES_SUCCESS; +} + +/* Change current display brightness (0-255) */ +void lb_set_brightness(unsigned int newval) +{ + int i; + CPRINTF("[%T LB_bright 0x%02x]\n", newval); + brightness = newval; + for (i = 0; i < NUM_LEDS; i++) + setrgb(i, current[i][0], current[i][1], current[i][2]); +} + +/* Get current display brightness (0-255) */ +uint8_t lb_get_brightness(void) +{ + return brightness; +} + +/* Initialize the controller ICs after reset */ +void lb_init(void) +{ + CPRINTF("[%T LB_init_vals]\n"); + set_from_array(init_vals, ARRAY_SIZE(init_vals)); + memset(current, 0, sizeof(current)); +} + +/* Just go into standby mode. No register values should change. */ +void lb_off(void) +{ + CPRINTF("[%T LB_off]\n"); + controller_write(0, 0x01, 0x00); + controller_write(1, 0x01, 0x00); +} + +/* Come out of standby mode. */ +void lb_on(void) +{ + CPRINTF("[%T LB_on]\n"); + controller_write(0, 0x01, 0x20); + controller_write(1, 0x01, 0x20); +} + +/* + * This sets up the auto-cycling features of the controllers to make a + * semi-random pattern of slowly fading colors. This is interesting only + * because it doesn't require any effort from the EC. +*/ +void lb_start_builtin_cycle(void) +{ + int r = scale(255, MAX_RED); + int g = scale(255, MAX_BLUE); + int b = scale(255, MAX_GREEN); + struct initdata_s pulse_vals[] = { + {0x11, 0xce}, + {0x12, 0x67}, + {0x13, 0xef}, + {0x15, b}, + {0x16, r}, + {0x17, g}, + {0x18, b}, + {0x19, r}, + {0x1a, g}, + }; + + set_from_array(pulse_vals, ARRAY_SIZE(pulse_vals)); + controller_write(1, 0x13, 0xcd); /* this one's different */ +} + +static const uint8_t dump_reglist[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a +}; + +/* Helper for host command to dump controller registers */ +void lb_hc_cmd_dump(struct ec_response_lightbar *out) +{ + int i; + uint8_t reg; + + BUILD_ASSERT(ARRAY_SIZE(dump_reglist) == + ARRAY_SIZE(out->dump.vals)); + + for (i = 0; i < ARRAY_SIZE(dump_reglist); i++) { + reg = dump_reglist[i]; + out->dump.vals[i].reg = reg; + out->dump.vals[i].ic0 = controller_read(0, reg); + out->dump.vals[i].ic1 = controller_read(1, reg); + } +} + +/* Helper for host command to write controller registers directly */ +void lb_hc_cmd_reg(const struct ec_params_lightbar *in) +{ + controller_write(in->reg.ctrl, in->reg.reg, in->reg.value); +} diff --git a/common/lightbar.c b/common/lightbar.c index 873263fe4e..6508d897fb 100644 --- a/common/lightbar.c +++ b/common/lightbar.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +/* + * Copyright (c) 2012 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. * @@ -9,10 +10,10 @@ #include "charge_state.h" #include "common.h" #include "console.h" -#include "gpio.h" +#include "ec_commands.h" #include "hooks.h" #include "host_command.h" -#include "i2c.h" +#include "lb_common.h" #include "lightbar.h" #include "pwm.h" #include "system.h" @@ -20,11 +21,10 @@ #include "timer.h" #include "util.h" - /* - * The Link lightbar had no version command, so defaulted to zero. If we make - * any incompatible changes, update the version. Indicate any new features in - * the current version with flags bits. + * The Link lightbar had no version command, so defaulted to zero. We have + * added a couple of new commands, so we've updated the version. Any + * optional features in the current version should be marked with flags. */ #define LIGHTBAR_IMPLEMENTATION_VERSION 1 #define LIGHTBAR_IMPLEMENTATION_FLAGS 0 @@ -34,267 +34,6 @@ #define CPRINTF(format, args...) cprintf(CC_LIGHTBAR, format, ## args) /******************************************************************************/ -/* How to talk to the controller */ -/******************************************************************************/ - -/* Since there's absolutely nothing we can do about it if an I2C access - * isn't working, we're completely ignoring any failures. */ - -static const uint8_t i2c_addr[] = { 0x54, 0x56 }; - -static inline void controller_write(int ctrl_num, uint8_t reg, uint8_t val) -{ - ctrl_num = ctrl_num % ARRAY_SIZE(i2c_addr); - i2c_write8(I2C_PORT_LIGHTBAR, i2c_addr[ctrl_num], reg, val); -} - -static inline uint8_t controller_read(int ctrl_num, uint8_t reg) -{ - int val = 0; - ctrl_num = ctrl_num % ARRAY_SIZE(i2c_addr); - i2c_read8(I2C_PORT_LIGHTBAR, i2c_addr[ctrl_num], reg, &val); - return val; -} - -/******************************************************************************/ -/* Controller details. We have an ADP8861 and and ADP8863, but we can treat - * them identically for our purposes */ -/******************************************************************************/ - -#ifdef BOARD_BDS -/* We need to limit the total current per ISC to no more than 20mA (5mA per - * color LED, but we have four LEDs in parallel on each ISC). Any more than - * that runs the risk of damaging the LED component. A value of 0x67 is as high - * as we want (assuming Square Law), but the blue LED is the least bright, so - * I've lowered the other colors until they all appear approximately equal - * brightness when full on. That's still pretty bright and a lot of current - * drain on the battery, so we'll probably rarely go that high. */ -#define MAX_RED 0x5c -#define MAX_GREEN 0x30 -#define MAX_BLUE 0x67 -#endif -#ifdef BOARD_LINK -/* Link uses seven segments, not four, but keep the same limits anyway */ -#define MAX_RED 0x5c -#define MAX_GREEN 0x30 -#define MAX_BLUE 0x67 -#endif -#ifdef BOARD_SAMUS -/* Samus uses completely different LEDs, so the numbers are different */ -#define MAX_RED 0x4f -#define MAX_GREEN 0x55 -#define MAX_BLUE 0x67 -#endif - -/* How many (logical) LEDs do we have? */ -#define NUM_LEDS 4 - -/* How we'd like to see the driver chips initialized. The controllers have some - * auto-cycling capability, but it's not much use for our purposes. For now, - * we'll just control all color changes actively. */ -struct initdata_s { - uint8_t reg; - uint8_t val; -}; - -static const struct initdata_s init_vals[] = { - {0x04, 0x00}, /* no backlight function */ - {0x05, 0x3f}, /* xRGBRGB per chip */ - {0x0f, 0x01}, /* square law looks better */ - {0x10, 0x3f}, /* enable independent LEDs */ - {0x11, 0x00}, /* no auto cycling */ - {0x12, 0x00}, /* no auto cycling */ - {0x13, 0x00}, /* instant fade in/out */ - {0x14, 0x00}, /* not using LED 7 */ - {0x15, 0x00}, /* current for LED 6 (blue) */ - {0x16, 0x00}, /* current for LED 5 (red) */ - {0x17, 0x00}, /* current for LED 4 (green) */ - {0x18, 0x00}, /* current for LED 3 (blue) */ - {0x19, 0x00}, /* current for LED 2 (red) */ - {0x1a, 0x00}, /* current for LED 1 (green) */ -}; - -static void set_from_array(const struct initdata_s *data, int count) -{ - int i; - for (i = 0; i < count; i++) { - controller_write(0, data[i].reg, data[i].val); - controller_write(1, data[i].reg, data[i].val); - } -} - -/* Controller register lookup tables. */ -static const uint8_t led_to_ctrl[] = { 1, 1, 0, 0 }; -#ifdef BOARD_BDS -static const uint8_t led_to_isc[] = { 0x18, 0x15, 0x18, 0x15 }; -#endif -#ifdef BOARD_LINK -static const uint8_t led_to_isc[] = { 0x18, 0x15, 0x18, 0x15 }; -#endif -#ifdef BOARD_SAMUS -static const uint8_t led_to_isc[] = { 0x15, 0x18, 0x15, 0x18 }; -#endif - -/* Scale 0-255 into max value */ -static inline uint8_t scale_abs(int val, int max) -{ - return (val * max)/255; -} - -/* This is the overall brightness control. */ -static int brightness = 0xc0; - -/* So that we can make brightness changes happen instantly, we need to track - * the current values. The values in the controllers aren't very helpful. */ -static uint8_t current[NUM_LEDS][3]; - -/* Scale 0-255 by brightness */ -static inline uint8_t scale(int val, int max) -{ - return scale_abs((val * brightness)/255, max); -} - -/* Helper function to set one LED color and remember it for later */ -static void setrgb(int led, int red, int green, int blue) -{ - int ctrl, bank; - current[led][0] = red; - current[led][1] = green; - current[led][2] = blue; - ctrl = led_to_ctrl[led]; - bank = led_to_isc[led]; - controller_write(ctrl, bank, scale(blue, MAX_BLUE)); - controller_write(ctrl, bank+1, scale(red, MAX_RED)); - controller_write(ctrl, bank+2, scale(green, MAX_GREEN)); -} - -/* LEDs are numbered 0-3, RGB values should be in 0-255. - * If you specify too large an LED, it sets them all. */ -static void lb_set_rgb(unsigned int led, int red, int green, int blue) -{ - int i; - if (led >= NUM_LEDS) - for (i = 0; i < NUM_LEDS; i++) - setrgb(i, red, green, blue); - else - setrgb(led, red, green, blue); -} - -/* Get current LED values, if the LED number is in range. */ -static int lb_get_rgb(unsigned int led, - uint8_t *red, uint8_t *green, uint8_t *blue) -{ - if (led < 0 || led >= NUM_LEDS) - return EC_RES_INVALID_PARAM; - - *red = current[led][0]; - *green = current[led][1]; - *blue = current[led][2]; - - return EC_RES_SUCCESS; -} - -/* Change current display brightness (0-255) */ -static void lb_set_brightness(unsigned int newval) -{ - int i; - CPRINTF("[%T LB_bright 0x%02x]\n", newval); - brightness = newval; - for (i = 0; i < NUM_LEDS; i++) - setrgb(i, current[i][0], current[i][1], current[i][2]); -} - -/* Get current display brightness (0-255) */ -static uint8_t lb_get_brightness(void) -{ - return brightness; -} - -/* Initialize the controller ICs after reset */ -static void lb_init(void) -{ - CPRINTF("[%T LB_init_vals]\n"); - set_from_array(init_vals, ARRAY_SIZE(init_vals)); - memset(current, 0, sizeof(current)); -} - -/* Just go into standby mode. No register values should change. */ -static void lb_off(void) -{ - CPRINTF("[%T LB_off]\n"); - controller_write(0, 0x01, 0x00); - controller_write(1, 0x01, 0x00); -} - -/* Come out of standby mode. */ -static void lb_on(void) -{ - CPRINTF("[%T LB_on]\n"); - controller_write(0, 0x01, 0x20); - controller_write(1, 0x01, 0x20); -} - - -/* - * This sets up the auto-cycling features of the controllers to make a - * semi-random pattern of slowly fading colors. This is interesting only - * because it doesn't require any effort from the EC. -*/ -static void lb_start_builtin_cycle(void) -{ - int r = scale(255, MAX_RED); - int g = scale(255, MAX_BLUE); - int b = scale(255, MAX_GREEN); - struct initdata_s pulse_vals[] = { - {0x11, 0xce}, - {0x12, 0x67}, - {0x13, 0xef}, - {0x15, b}, - {0x16, r}, - {0x17, g}, - {0x18, b}, - {0x19, r}, - {0x1a, g}, - }; - - set_from_array(pulse_vals, ARRAY_SIZE(pulse_vals)); - controller_write(1, 0x13, 0xcd); /* this one's different */ -} - - -static const uint8_t dump_reglist[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a -}; - -/* Helper for host command to dump controller registers */ -static void lb_hc_cmd_dump(struct ec_response_lightbar *out) -{ - int i; - uint8_t reg; - - BUILD_ASSERT(ARRAY_SIZE(dump_reglist) == - ARRAY_SIZE(out->dump.vals)); - - for (i = 0; i < ARRAY_SIZE(dump_reglist); i++) { - reg = dump_reglist[i]; - out->dump.vals[i].reg = reg; - out->dump.vals[i].ic0 = controller_read(0, reg); - out->dump.vals[i].ic1 = controller_read(1, reg); - } -} - -/* Helper for host command to write controller registers directly */ -static void lb_hc_cmd_reg(const struct ec_params_lightbar *in) -{ - controller_write(in->reg.ctrl, in->reg.reg, in->reg.value); -} - - - -/******************************************************************************/ /* Here's some state that we might want to maintain across sysjumps, just to * prevent the lightbar from flashing during normal boot as the EC jumps from * RO to RW. */ @@ -416,7 +155,6 @@ static void get_battery_level(void) st.battery_is_charging = (PWR_STATE_DISCHARGE != charge_get_state()); #endif - /* Find the new battery level */ bl = 0; for (i = 0; i < LB_BATTERY_LEVELS - 1; i++) @@ -431,7 +169,6 @@ static void get_battery_level(void) pct <= (st.p.battery_threshold[bl] - 1)) st.battery_level = bl; - #ifdef CONFIG_PWM_KBLIGHT /* * With nothing else to go on, use the keyboard backlight level to * @@ -459,7 +196,6 @@ static void get_battery_level(void) #endif } - /* Forcing functions for demo mode, called by the keyboard task. */ /* Up/Down keys */ @@ -504,13 +240,6 @@ void demo_brightness(int inc) lb_set_brightness(b); } - -/******************************************************************************/ -/* Basic LED control functions. Use these to implement the pretty patterns. */ -/******************************************************************************/ - - - /******************************************************************************/ /* Helper functions and data. */ /******************************************************************************/ @@ -898,8 +627,6 @@ static uint32_t sequence_PULSE(void) return TASK_EVENT_CUSTOM(msg); } - - /* The host CPU (or someone) is going to poke at the lightbar directly, so we * don't want the EC messing with it. We'll just sit here and ignore all * other messages until we're told to continue. */ @@ -940,7 +667,6 @@ static uint32_t sequence_ERROR(void) return 0; } - static const struct { uint8_t led; uint8_t r, g, b; @@ -1014,7 +740,6 @@ static const struct { {4, 0xff, 0xff, 0xff, 100000}, {4, 0x00, 0x00, 0x00, 100000}, - }; static uint32_t sequence_KONAMI(void) @@ -1233,7 +958,6 @@ DECLARE_HOST_COMMAND(EC_CMD_LIGHTBAR_CMD, lpc_cmd_lightbar, EC_VER_MASK(0)); - /****************************************************************************/ /* EC console commands */ /****************************************************************************/ diff --git a/include/lb_common.h b/include/lb_common.h new file mode 100644 index 0000000000..f2f53aae35 --- /dev/null +++ b/include/lb_common.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 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. + */ + +/* Lightbar IC interface */ + +#ifndef __CROS_EC_LB_COMMON_H +#define __CROS_EC_LB_COMMON_H + +#include "ec_commands.h" + +/* How many (logical) LEDs do we have? */ +#define NUM_LEDS 4 + +/* Set the color of one LED (or all if the LED number is too large) */ +void lb_set_rgb(unsigned int led, int red, int green, int blue); +/* Get the current color of one LED. Fails if the LED number is too large. */ +int lb_get_rgb(unsigned int led, uint8_t *red, uint8_t *green, uint8_t *blue); +/* Set the overall brightness level. */ +void lb_set_brightness(unsigned int newval); +/* Get the overall brighness level. */ +uint8_t lb_get_brightness(void); +/* Initialize the IC controller registers to sane values. */ +void lb_init(void); +/* Disable the LED current off (the IC stays on). */ +void lb_off(void); +/* Enable the LED current. */ +void lb_on(void); +/* Instruct the IC to run a built-in sequence of color changes. */ +void lb_start_builtin_cycle(void); +/* Fill in the response fields for the LIGHTBAR_CMD_DUMP command. */ +void lb_hc_cmd_dump(struct ec_response_lightbar *out); +/* Write the IC controller register given by the LIGHTBAR_CMD_REG command. */ +void lb_hc_cmd_reg(const struct ec_params_lightbar *in); + +#endif /* __CROS_EC_LB_COMMON_H */ |