mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-03 21:49:32 +00:00
BUG=chrome-os-partner:8728 TEST=manual I don't have a system that has both an EC and a lightsaber, so I can't be certain this works, but I *think* it will. I do have a Link proto 0.5. With that, you can say ectool lightbar test and the EC console says it's poking at the lightbar, but of course there's nothing there. If there was, it *should* flash in pretty colors. I have a lightsaber attached to a BDS, and from the EC console running "lightsaber test" does make it blink. Change-Id: Ib6021ad8e53959de52b12efda376254071e5fb4b Signed-off-by: Bill Richardson <wfrichar@chromium.org>
257 lines
7.0 KiB
C
257 lines
7.0 KiB
C
/* 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.
|
|
*
|
|
* LED controls.
|
|
*/
|
|
|
|
#include "board.h"
|
|
#include "console.h"
|
|
#include "gpio.h"
|
|
#include "host_command.h"
|
|
#include "i2c.h"
|
|
#include "timer.h"
|
|
#include "uart.h"
|
|
#include "util.h"
|
|
|
|
|
|
#define DRIVER_SMART 0x54
|
|
#define DRIVER_FUN 0x56
|
|
|
|
/* 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 0x38
|
|
#define MAX_BLUE 0x67
|
|
/* Macro to scale 0-255 into max value */
|
|
#define SCALE(VAL, MAX) ((VAL * MAX)/255 + MAX/256)
|
|
|
|
/* How we'd like to see the driver chips initialized. */
|
|
static const struct {
|
|
uint8_t reg;
|
|
uint8_t val;
|
|
} ready_vals[] = {
|
|
{0x01, 0x00}, /* standby mode */
|
|
{0x04, 0x00}, /* no backlight */
|
|
{0x05, 0x3f}, /* xRGBRGB per chip */
|
|
{0x0f, 0x01}, /* square acts more linear */
|
|
{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) */
|
|
{0x01, 0x20}, /* active (no charge pump) */
|
|
};
|
|
|
|
/* NOTE: Since there's absolutely nothing we can do about it if an I2C access
|
|
* isn't working, we're completely ignoring those results. */
|
|
|
|
/****************************************************************************/
|
|
/* External interface functions. */
|
|
|
|
/* We don't actually shut down the driver chips, because the reset pullup
|
|
* uses more power than leaving them enabled but inactive. */
|
|
static void lightbar_off(void)
|
|
{
|
|
gpio_set_level(GPIO_LIGHTBAR_RESETn, 1);
|
|
i2c_write8(I2C_PORT_LIGHTBAR, DRIVER_FUN, 0x01, 0x00);
|
|
i2c_write8(I2C_PORT_LIGHTBAR, DRIVER_SMART, 0x01, 0x00);
|
|
}
|
|
|
|
/* Initialize & activate driver chips, but no LEDs on yet. */
|
|
static void lightbar_on(void)
|
|
{
|
|
int i;
|
|
gpio_set_level(GPIO_LIGHTBAR_RESETn, 1);
|
|
for (i = 0; i < ARRAY_SIZE(ready_vals); i++) {
|
|
i2c_write8(I2C_PORT_LIGHTBAR, DRIVER_FUN, ready_vals[i].reg,
|
|
ready_vals[i].val);
|
|
i2c_write8(I2C_PORT_LIGHTBAR, DRIVER_SMART, ready_vals[i].reg,
|
|
ready_vals[i].val);
|
|
}
|
|
}
|
|
|
|
/* Set the color for an LED (0-3). RGB values should be in 0-255. They'll be
|
|
* scaled so that maxium brightness is at 255. */
|
|
static void lightbar_setcolor(int led, int red, int green, int blue)
|
|
{
|
|
int driver, bank;
|
|
driver = DRIVER_SMART + (led/2) * 2;
|
|
bank = (led % 2) * 3 + 0x15;
|
|
i2c_write8(I2C_PORT_LIGHTBAR, driver, bank, SCALE(blue, MAX_BLUE));
|
|
i2c_write8(I2C_PORT_LIGHTBAR, driver, bank+1, SCALE(red, MAX_RED));
|
|
i2c_write8(I2C_PORT_LIGHTBAR, driver, bank+2, SCALE(green, MAX_GREEN));
|
|
}
|
|
|
|
static const struct {
|
|
uint8_t r, g, b;
|
|
} testy[] = {
|
|
{0xff, 0x00, 0x00},
|
|
{0x00, 0xff, 0x00},
|
|
{0x00, 0x00, 0xff},
|
|
{0xff, 0xff, 0x00},
|
|
{0x00, 0xff, 0xff},
|
|
{0xff, 0x00, 0xff},
|
|
{0xff, 0xff, 0xff},
|
|
};
|
|
|
|
static void lightbar_test(void)
|
|
{
|
|
int i, j, k, r, g, b;
|
|
int kmax = 254;
|
|
int kstep = 4;
|
|
lightbar_on();
|
|
for (i = 0; i < ARRAY_SIZE(testy); i++) {
|
|
for (k = 0; k <= kmax; k += kstep) {
|
|
for (j = 0; j < 4; j++) {
|
|
r = testy[i].r ? k : 0;
|
|
g = testy[i].g ? k : 0;
|
|
b = testy[i].b ? k : 0;
|
|
lightbar_setcolor(j, r, g, b);
|
|
}
|
|
}
|
|
for (k = kmax; k >= 0; k -= kstep) {
|
|
for (j = 0; j < 4; j++) {
|
|
r = testy[i].r ? k : 0;
|
|
g = testy[i].g ? k : 0;
|
|
b = testy[i].b ? k : 0;
|
|
lightbar_setcolor(j, r, g, b);
|
|
}
|
|
}
|
|
}
|
|
lightbar_on();
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: Do I want some auto-cycling functions? Pulsing, etc.? Investigate to
|
|
* see what's possible and looks nice. */
|
|
|
|
/****************************************************************************/
|
|
/* host commands */
|
|
|
|
static enum lpc_status lpc_cmd_reset(uint8_t *data)
|
|
{
|
|
uart_printf("%s()\n", __func__);
|
|
lightbar_off();
|
|
return EC_LPC_RESULT_SUCCESS;
|
|
}
|
|
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_LIGHTBAR_RESET, lpc_cmd_reset);
|
|
|
|
static enum lpc_status lpc_cmd_test(uint8_t *data)
|
|
{
|
|
struct lpc_params_lightbar_test *p =
|
|
(struct lpc_params_lightbar_test *)data;
|
|
|
|
uart_printf("%s(0x%02x)\n", __func__, p->tbd);
|
|
lightbar_test();
|
|
return EC_LPC_RESULT_SUCCESS;
|
|
}
|
|
DECLARE_HOST_COMMAND(EC_LPC_COMMAND_LIGHTBAR_TEST, lpc_cmd_test);
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Console commands */
|
|
|
|
static int help(char *prog)
|
|
{
|
|
uart_printf("Usage: %s\n", prog);
|
|
uart_printf(" %s off\n", prog);
|
|
uart_printf(" %s on\n", prog);
|
|
uart_printf(" %s LED RED GREEN BLUE\n", prog);
|
|
uart_printf(" %s test [MAX]\n", prog);
|
|
uart_printf(" %s smart REG VAL\n", prog);
|
|
uart_printf(" %s fun REG VAL\n", prog);
|
|
return EC_ERROR_UNKNOWN;
|
|
}
|
|
|
|
static void dump_em(void)
|
|
{
|
|
int d1, d2, i;
|
|
int reglist[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0a, 0x0f,
|
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
|
0x18, 0x19, 0x1a };
|
|
uart_printf("reg smart fun\n");
|
|
for (i = 0; i < ARRAY_SIZE(reglist); i++) {
|
|
i2c_read8(I2C_PORT_LIGHTBAR, DRIVER_SMART, reglist[i], &d1);
|
|
i2c_read8(I2C_PORT_LIGHTBAR, DRIVER_FUN, reglist[i], &d2);
|
|
uart_printf(" %02x %02x %02x\n", reglist[i], d1, d2);
|
|
}
|
|
}
|
|
|
|
static int set(int driver, char *regstr, char *valstr)
|
|
{
|
|
int reg, val;
|
|
char *e;
|
|
reg = strtoi(regstr, &e, 16);
|
|
val = strtoi(valstr, &e, 16);
|
|
i2c_write8(I2C_PORT_LIGHTBAR, driver, reg, val);
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
static int command_lightbar(int argc, char **argv)
|
|
{
|
|
int led, red, green, blue;
|
|
char *e;
|
|
|
|
|
|
if (1 == argc) { /* no args = dump 'em all */
|
|
dump_em();
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
if (!strcasecmp(argv[1], "off")) {
|
|
lightbar_off();
|
|
dump_em();
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
if (!strcasecmp(argv[1], "on")) {
|
|
lightbar_on();
|
|
dump_em();
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
if (!strcasecmp(argv[1], "smart")) {
|
|
if (4 != argc)
|
|
return help(argv[0]);
|
|
return set(DRIVER_SMART, argv[2], argv[3]);
|
|
}
|
|
|
|
if (!strcasecmp(argv[1], "fun")) {
|
|
if (4 != argc)
|
|
return help(argv[0]);
|
|
return set(DRIVER_FUN, argv[2], argv[3]);
|
|
}
|
|
|
|
if (!strcasecmp(argv[1], "test")) {
|
|
lightbar_test();
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
if (5 != argc)
|
|
return help(argv[0]);
|
|
|
|
/* must be LED RED GREEN BLUE */
|
|
led = strtoi(argv[1], &e, 16) & 0x3;
|
|
red = strtoi(argv[2], &e, 16) & 0xff;
|
|
green = strtoi(argv[3], &e, 16) & 0xff;
|
|
blue = strtoi(argv[4], &e, 16) & 0xff;
|
|
lightbar_setcolor(led, red, green, blue);
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
DECLARE_CONSOLE_COMMAND(lightbar, command_lightbar);
|