| /* 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(); |
| } |