blob: e1170a7992577b4db1005513fd19c699972b85f9 [file] [log] [blame]
/* 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.
*
* Test lid switch.
*/
#include "battery_smart.h"
#include "common.h"
#include "console.h"
#include "driver/led/lp5562.h"
#include "host_command.h"
#include "pmu_tpschrome.h"
#include "test_util.h"
#include "timer.h"
#include "util.h"
#define LP5562_I2C_ADDR (0x30 << 1)
#define LP5562_NUM_WATCH_REG 0x71
static uint8_t lp5562_reg[LP5562_NUM_WATCH_REG];
#define LED_COLOR_NONE LP5562_COLOR_NONE
#define LED_COLOR_GREEN LP5562_COLOR_GREEN(0x10)
#define LED_COLOR_YELLOW LP5562_COLOR_BLUE(0x40)
#define LED_COLOR_RED LP5562_COLOR_RED(0x80)
static enum charging_state mock_charge_state = ST_IDLE;
static int lp5562_failed_i2c_reg = -1;
static const char * const state_names[] = CHARGE_STATE_NAME_TABLE;
/*****************************************************************************/
/* Mock functions */
static void set_ac(int ac)
{
gpio_set_level(GPIO_AC_PRESENT, ac);
ccprintf("[%T TEST AC = %d]\n", ac);
}
enum charging_state charge_get_state(void)
{
return mock_charge_state;
}
static void set_charge_state(enum charging_state s)
{
mock_charge_state = s;
ccprintf("[%T TEST Charge state = %s]\n", state_names[s]);
}
static void set_battery_soc(int soc)
{
sb_write(SB_RELATIVE_STATE_OF_CHARGE, soc);
sb_write(SB_ABSOLUTE_STATE_OF_CHARGE, soc);
}
/*****************************************************************************/
/* Test utilities */
static int lp5562_i2c_write8(int port, int slave_addr, int offset, int data)
{
if (port != I2C_PORT_MASTER || slave_addr != LP5562_I2C_ADDR)
return EC_ERROR_INVAL;
if (offset == lp5562_failed_i2c_reg)
return EC_ERROR_UNKNOWN;
if (offset < LP5562_NUM_WATCH_REG)
lp5562_reg[offset] = data;
return EC_SUCCESS;
}
DECLARE_TEST_I2C_WRITE8(lp5562_i2c_write8);
static int lp5562_get_color(void)
{
return lp5562_reg[LP5562_REG_B_PWM] |
(lp5562_reg[LP5562_REG_G_PWM] << 8) |
(lp5562_reg[LP5562_REG_R_PWM] << 16);
}
static int lp5562_powered(void)
{
return lp5562_reg[LP5562_REG_ENABLE] & 0x40;
}
static int lp5562_in_pwm_mode(void)
{
return lp5562_reg[LP5562_REG_LED_MAP] == 0;
}
static int verify_color(int expected_color)
{
int actual = lp5562_get_color();
if (expected_color == LED_COLOR_NONE)
return !lp5562_powered();
if (!lp5562_powered())
return 0;
if (!lp5562_in_pwm_mode())
return 0;
ccprintf("[%T LED color = 0x%06x]\n", actual);
return actual == expected_color;
}
/*****************************************************************************/
/* Tests */
static int test_led_power(void)
{
/* Check LED is off */
TEST_ASSERT(!lp5562_powered());
/* Plug in AC, and LED should turn on within a second */
set_ac(1);
msleep(1500);
TEST_ASSERT(lp5562_powered());
/* Change state while AC is on. LED should keep on */
set_charge_state(ST_CHARGING_ERROR);
msleep(1500);
TEST_ASSERT(lp5562_powered());
/* Unplug AC. LED should turn off */
set_ac(0);
msleep(1500);
TEST_ASSERT(!lp5562_powered());
/* Plug AC again. LED should turn on */
set_ac(1);
msleep(1500);
TEST_ASSERT(lp5562_powered());
return EC_SUCCESS;
}
static int test_led_color(void)
{
/* IDLE0 */
set_ac(1);
set_charge_state(ST_IDLE0);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_YELLOW));
/* BAD_COND*/
set_charge_state(ST_BAD_COND);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_YELLOW));
/* PRE_CHARGING */
set_charge_state(ST_PRE_CHARGING);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_YELLOW));
/* IDLE */
set_charge_state(ST_IDLE);
set_battery_soc(50);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_YELLOW));
set_battery_soc(99);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_GREEN));
/* DISCHARGING */
set_charge_state(ST_DISCHARGING);
set_battery_soc(50);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_YELLOW));
set_battery_soc(99);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_GREEN));
/* CHARGING */
set_charge_state(ST_CHARGING);
set_battery_soc(50);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_YELLOW));
set_battery_soc(99);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_GREEN));
/* CHARGING_ERROR */
set_charge_state(ST_CHARGING_ERROR);
msleep(1500);
TEST_ASSERT(verify_color(LED_COLOR_RED));
return EC_SUCCESS;
}
static int test_green_yellow(void)
{
/* Make LED green */
set_ac(1);
set_charge_state(ST_CHARGING);
set_battery_soc(95);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_GREEN));
/* Make it yellow now */
set_battery_soc(90);
msleep(1500);
TEST_ASSERT(verify_color(LED_COLOR_YELLOW));
/* Shouldn't change from yellow to green in 15 seconds */
set_battery_soc(95);
msleep(13000);
TEST_ASSERT(verify_color(LED_COLOR_YELLOW));
/* After 15 seconds, it should turn green */
msleep(3000);
TEST_ASSERT(verify_color(LED_COLOR_GREEN));
/* Shouldn't change from green to yellow in 15 seconds */
set_charge_state(ST_BAD_COND);
msleep(12000);
TEST_ASSERT(verify_color(LED_COLOR_GREEN));
/* After 15 seconds, it should turn yellow */
msleep(4000);
TEST_ASSERT(verify_color(LED_COLOR_YELLOW));
return EC_SUCCESS;
}
static int test_bad_i2c(void)
{
/* Make LED green */
set_ac(1);
set_charge_state(ST_DISCHARGING);
set_battery_soc(95);
msleep(30000);
TEST_ASSERT(verify_color(LED_COLOR_GREEN));
/* Make it red, but fail the I2C write to green PWM register */
lp5562_failed_i2c_reg = LP5562_REG_G_PWM;
set_charge_state(ST_CHARGING_ERROR);
msleep(3000);
TEST_ASSERT(!verify_color(LED_COLOR_RED));
/* I2C works again. LED should turn red */
lp5562_failed_i2c_reg = -1;
msleep(1500);
TEST_ASSERT(verify_color(LED_COLOR_RED));
/* Make it green, but I2C fails again */
lp5562_failed_i2c_reg = LP5562_REG_R_PWM;
set_charge_state(ST_DISCHARGING);
msleep(1500);
TEST_ASSERT(!verify_color(LED_COLOR_GREEN));
TEST_ASSERT(!verify_color(LED_COLOR_RED));
/* I2C works now, but LED turns red at the same time */
lp5562_failed_i2c_reg = -1;
set_charge_state(ST_CHARGING_ERROR);
msleep(1500);
TEST_ASSERT(verify_color(LED_COLOR_RED));
return EC_SUCCESS;
}
void run_test(void)
{
test_reset();
RUN_TEST(test_led_power);
RUN_TEST(test_led_color);
RUN_TEST(test_green_yellow);
RUN_TEST(test_bad_i2c);
test_print_result();
}