mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-02 13:14:51 +00:00
Merge "Add battery charge state machine and task"
This commit is contained in:
@@ -81,6 +81,7 @@ enum adc_channel
|
||||
|
||||
/* Battery module */
|
||||
#define CONFIG_SMART_BATTERY
|
||||
#define CONFIG_BATTERY_ATL706486
|
||||
|
||||
/* I2C ports */
|
||||
#define I2C_PORT_BATTERY 0
|
||||
|
||||
@@ -23,4 +23,5 @@
|
||||
TASK(X86POWER, x86_power_task, NULL) \
|
||||
TASK(CONSOLE, console_task, NULL) \
|
||||
TASK(HOSTCMD, host_command_task, NULL) \
|
||||
TASK(I8042CMD, i8042_command_task, NULL)
|
||||
TASK(I8042CMD, i8042_command_task, NULL) \
|
||||
TASK(POWERSTATE, charge_state_machine_task, NULL)
|
||||
|
||||
86
common/battery_atl706486.c
Normal file
86
common/battery_atl706486.c
Normal file
@@ -0,0 +1,86 @@
|
||||
/* 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.
|
||||
*
|
||||
* Battery pack vendor provided charging profile for ATL706486
|
||||
*/
|
||||
|
||||
#include "battery_pack.h"
|
||||
|
||||
/* Convert Celsius degree to Deci Kelvin degree */
|
||||
static inline int celsius_to_deci_kelvin(int degree_c)
|
||||
{
|
||||
return degree_c * 10 + 2731;
|
||||
}
|
||||
|
||||
static inline void limit_value(int *val, int limit)
|
||||
{
|
||||
if (*val > limit)
|
||||
*val = limit;
|
||||
}
|
||||
|
||||
/* Vendor provided parameters for battery charging */
|
||||
void battery_vendor_params(struct batt_params *batt)
|
||||
{
|
||||
/* Designed capacity
|
||||
* Battery capacity = 8400 mAh
|
||||
* 1C = 8400 mA
|
||||
*/
|
||||
const int C = 8400;
|
||||
const int C_01 = C * 0.1;
|
||||
const int C_02 = C * 0.2;
|
||||
const int C_05 = C * 0.5;
|
||||
const int C_07 = C * 0.7;
|
||||
|
||||
/* Designed voltage
|
||||
* max = 8.4V
|
||||
* normal = 7.4V
|
||||
*/
|
||||
const int V_max = 8400;
|
||||
|
||||
/* Operation temperation range
|
||||
* 0 <= T_charge <= 45
|
||||
* -20 <= T_discharge <= 60
|
||||
*/
|
||||
const int T_charge_min = 0;
|
||||
const int T_charge_max = 45;
|
||||
|
||||
int *desired_current = &batt->desired_current;
|
||||
|
||||
/* Hard limits
|
||||
* - charging voltage < 8.4V
|
||||
* - charging temperature range 0 ~ 45 degree Celcius
|
||||
* */
|
||||
if (batt->desired_voltage > V_max)
|
||||
batt->desired_voltage = V_max;
|
||||
if (batt->temperature >= celsius_to_deci_kelvin(T_charge_max) ||
|
||||
batt->temperature <= celsius_to_deci_kelvin(T_charge_min)) {
|
||||
batt->desired_voltage = 0;
|
||||
batt->desired_current = 0;
|
||||
}
|
||||
|
||||
/* Vendor provided charging method
|
||||
* temp : I - V , I - V
|
||||
* - 0 ~ 10 : 0.2C - 8.0V, 0.1C to 8.4V
|
||||
* - 10 ~ 23 : 0.5C - 8.0V, 0.2C to 8.4V
|
||||
* - 23 ~ 45 : 0.7C - 8.0V, 0.2C to 8.4V
|
||||
*/
|
||||
if (batt->temperature <= celsius_to_deci_kelvin(10)) {
|
||||
if (batt->voltage < 8000)
|
||||
limit_value(desired_current, C_02);
|
||||
else
|
||||
limit_value(desired_current, C_01);
|
||||
} else if (batt->temperature <= celsius_to_deci_kelvin(23)) {
|
||||
if (batt->voltage < 8000)
|
||||
limit_value(desired_current, C_05);
|
||||
else
|
||||
limit_value(desired_current, C_02);
|
||||
} else {
|
||||
if (batt->voltage < 8000)
|
||||
limit_value(desired_current, C_07);
|
||||
else
|
||||
limit_value(desired_current, C_02);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
24
common/battery_pack.h
Normal file
24
common/battery_pack.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* 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.
|
||||
*
|
||||
* Common API for battery pack vendor provided charging profile
|
||||
*/
|
||||
#ifndef __CROS_EC_BATTERY_PACK_H
|
||||
#define __CROS_EC_BATTERY_PACK_H
|
||||
|
||||
/* Battery parameters */
|
||||
struct batt_params {
|
||||
int temperature;
|
||||
int state_of_charge;
|
||||
int voltage;
|
||||
int current;
|
||||
int desired_voltage;
|
||||
int desired_current;
|
||||
};
|
||||
|
||||
/* Vendor provided parameters for battery charging */
|
||||
void battery_vendor_params(struct batt_params *batt);
|
||||
|
||||
#endif //__CROS_EC_BATTERY_PACK_H
|
||||
|
||||
@@ -23,4 +23,5 @@ common-$(CONFIG_LIGHTBAR)+=leds.o
|
||||
|
||||
# Board driver modules
|
||||
common-$(CONFIG_CHARGER_BQ24725)+=charger_bq24725.o
|
||||
common-$(CONFIG_SMART_BATTERY)+=smart_battery.o
|
||||
common-$(CONFIG_BATTERY_ATL706486)+=battery_atl706486.o
|
||||
common-$(CONFIG_SMART_BATTERY)+=smart_battery.o charge_state.o
|
||||
|
||||
365
common/charge_state.c
Normal file
365
common/charge_state.c
Normal file
@@ -0,0 +1,365 @@
|
||||
/* 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.
|
||||
*
|
||||
* Battery charging task and state machine.
|
||||
*/
|
||||
|
||||
|
||||
#include "battery_pack.h"
|
||||
#include "board.h"
|
||||
#include "console.h"
|
||||
#include "charger.h"
|
||||
#include "gpio.h"
|
||||
#include "smart_battery.h"
|
||||
#include "timer.h"
|
||||
#include "uart.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Stop charge when state of charge reaches this percentage */
|
||||
#define STOP_CHARGE_THRESHOLD 100
|
||||
|
||||
/* power state task polling period in usec */
|
||||
#define POLL_PERIOD_LONG 500000
|
||||
#define POLL_PERIOD_CHARGE 250000
|
||||
#define POLL_PERIOD_SHORT 100000
|
||||
#define MIN_SLEEP_USEC 50000
|
||||
|
||||
/* Power states */
|
||||
enum power_state {
|
||||
PWR_STATE_UNCHANGE = 0,
|
||||
PWR_STATE_INIT,
|
||||
PWR_STATE_IDLE,
|
||||
PWR_STATE_DISCHARGE,
|
||||
PWR_STATE_CHARGE,
|
||||
PWR_STATE_ERROR
|
||||
};
|
||||
/* Debugging constants, in the same order as power_state.
|
||||
* This state name table and debug print will be removed
|
||||
* before production.
|
||||
*/
|
||||
const static char *_state_name[] = {
|
||||
"null",
|
||||
"init",
|
||||
"idle",
|
||||
"discharge",
|
||||
"charge",
|
||||
"error"
|
||||
};
|
||||
|
||||
|
||||
/* helper function(s) */
|
||||
static inline int get_ac(void)
|
||||
{
|
||||
return gpio_get_level(GPIO_AC_PRESENT);
|
||||
}
|
||||
|
||||
/* Get battery charging parameters from battery and
|
||||
* battery pack vendor table
|
||||
*/
|
||||
static int battery_params(struct batt_params *batt)
|
||||
{
|
||||
int rv;
|
||||
rv = battery_temperature(&batt->temperature);
|
||||
if (rv)
|
||||
return rv;
|
||||
rv = battery_voltage(&batt->voltage);
|
||||
if (rv)
|
||||
return rv;
|
||||
rv = battery_current(&batt->current);
|
||||
if (rv)
|
||||
return rv;
|
||||
rv = battery_desired_voltage(&batt->desired_voltage);
|
||||
if (rv)
|
||||
return rv;
|
||||
rv = battery_desired_current(&batt->desired_current);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
battery_vendor_params(batt);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/* Init state handler
|
||||
* - check ac, charger, battery and temperature
|
||||
* - initialize charger
|
||||
* - new states: DISCHARGE, IDLE
|
||||
*/
|
||||
static enum power_state state_init(void)
|
||||
{
|
||||
int rv, val;
|
||||
|
||||
/* Stop charger, unconditionally */
|
||||
charger_set_current(0);
|
||||
charger_set_voltage(0);
|
||||
|
||||
/* Detect AC, init charger */
|
||||
if (!get_ac())
|
||||
return PWR_STATE_DISCHARGE;
|
||||
|
||||
/* Initialize charger to power on reset mode */
|
||||
rv = charger_post_init();
|
||||
if (rv)
|
||||
return PWR_STATE_ERROR;
|
||||
/* Check if charger is online */
|
||||
rv = charger_get_status(&val);
|
||||
if (rv)
|
||||
return PWR_STATE_ERROR;
|
||||
|
||||
/* Detect battery */
|
||||
if (battery_temperature(&val))
|
||||
return PWR_STATE_ERROR;
|
||||
|
||||
return PWR_STATE_IDLE;
|
||||
}
|
||||
|
||||
/* Idle state handler
|
||||
* - both charger and battery are online
|
||||
* - detect charger and battery status change
|
||||
* - new states: CHARGE, INIT
|
||||
*/
|
||||
static enum power_state state_idle(void)
|
||||
{
|
||||
int voltage, current, state_of_charge;
|
||||
struct batt_params batt;
|
||||
|
||||
if (!get_ac())
|
||||
return PWR_STATE_INIT;
|
||||
|
||||
/* Prevent charging in idle mode */
|
||||
if (charger_get_voltage(&voltage))
|
||||
return PWR_STATE_ERROR;
|
||||
if (charger_get_current(¤t))
|
||||
return PWR_STATE_ERROR;
|
||||
if (voltage || current)
|
||||
return PWR_STATE_INIT;
|
||||
|
||||
if (battery_state_of_charge(&state_of_charge))
|
||||
return PWR_STATE_ERROR;
|
||||
|
||||
if (state_of_charge >= STOP_CHARGE_THRESHOLD)
|
||||
return PWR_STATE_UNCHANGE;
|
||||
|
||||
/* Check if the batter is good to charge */
|
||||
if (battery_params(&batt))
|
||||
return PWR_STATE_ERROR;
|
||||
|
||||
/* Configure init charger state and switch to charge state */
|
||||
if (batt.desired_voltage && batt.desired_current) {
|
||||
if (charger_set_voltage(batt.desired_voltage))
|
||||
return PWR_STATE_ERROR;
|
||||
if (charger_set_current(batt.desired_current))
|
||||
return PWR_STATE_ERROR;
|
||||
return PWR_STATE_CHARGE;
|
||||
}
|
||||
|
||||
return PWR_STATE_UNCHANGE;
|
||||
}
|
||||
|
||||
/* Charge state handler
|
||||
* - detect battery status change
|
||||
* - new state: INIT
|
||||
*/
|
||||
static enum power_state state_charge(void)
|
||||
{
|
||||
int chg_voltage, chg_current;
|
||||
struct batt_params batt;
|
||||
|
||||
if (!get_ac())
|
||||
return PWR_STATE_INIT;
|
||||
|
||||
if (charger_get_voltage(&chg_voltage))
|
||||
return PWR_STATE_ERROR;
|
||||
if (charger_get_current(&chg_current))
|
||||
return PWR_STATE_ERROR;
|
||||
/* Check charger reset */
|
||||
if (chg_voltage == 0 || chg_current == 0)
|
||||
return PWR_STATE_INIT;
|
||||
|
||||
if (battery_params(&batt))
|
||||
return PWR_STATE_ERROR;
|
||||
|
||||
if (batt.desired_voltage != chg_voltage)
|
||||
if (charger_set_voltage(batt.desired_voltage))
|
||||
return PWR_STATE_ERROR;
|
||||
if (batt.desired_current != chg_current)
|
||||
if (charger_set_current(batt.desired_current))
|
||||
return PWR_STATE_ERROR;
|
||||
|
||||
if (battery_state_of_charge(&batt.state_of_charge))
|
||||
return PWR_STATE_ERROR;
|
||||
|
||||
if (batt.state_of_charge >= STOP_CHARGE_THRESHOLD) {
|
||||
if (charger_set_voltage(0) || charger_set_current(0))
|
||||
return PWR_STATE_ERROR;
|
||||
return PWR_STATE_IDLE;
|
||||
}
|
||||
|
||||
return PWR_STATE_UNCHANGE;
|
||||
}
|
||||
|
||||
/* Discharge state handler
|
||||
* - detect ac status
|
||||
* - new state: INIT
|
||||
*/
|
||||
static enum power_state state_discharge(void)
|
||||
{
|
||||
if (get_ac())
|
||||
return PWR_STATE_INIT;
|
||||
|
||||
/* TODO: handle overtemp in discharge mode */
|
||||
|
||||
return PWR_STATE_UNCHANGE;
|
||||
}
|
||||
|
||||
/* Error state handler
|
||||
* - check charger and battery communication
|
||||
* - log error
|
||||
* - new state: INIT
|
||||
*/
|
||||
static enum power_state state_error(void)
|
||||
{
|
||||
enum { F_CHG_V, F_CHG_I, F_BAT_V, F_BAT_I,
|
||||
F_DES_V, F_DES_I, F_BAT_T, F_LAST };
|
||||
static int last_error_flags;
|
||||
int error_flags = 0;
|
||||
int ac = 0;
|
||||
int bat_v = -1, bat_i = -1, bat_temp = -1;
|
||||
int desired_v = -1, desired_i = -1;
|
||||
|
||||
ac = get_ac();
|
||||
if (ac) {
|
||||
if (charger_set_voltage(0))
|
||||
error_flags |= (1 << F_CHG_V);
|
||||
if (charger_set_current(0))
|
||||
error_flags |= (1 << F_CHG_I);
|
||||
}
|
||||
|
||||
if (battery_voltage(&bat_v))
|
||||
error_flags |= (1 << F_BAT_V);
|
||||
if (battery_current(&bat_i))
|
||||
error_flags |= (1 << F_BAT_I);
|
||||
if (battery_temperature(&bat_temp))
|
||||
error_flags |= (1 << F_BAT_T);
|
||||
if (battery_desired_voltage(&desired_v))
|
||||
error_flags |= (1 << F_DES_V);
|
||||
if (battery_desired_current(&desired_i))
|
||||
error_flags |= (1 << F_DES_I);
|
||||
|
||||
if (error_flags == 0) {
|
||||
last_error_flags = 0;
|
||||
return PWR_STATE_INIT;
|
||||
}
|
||||
|
||||
if (error_flags != last_error_flags) {
|
||||
uart_printf("errors : %02x\n", error_flags);
|
||||
uart_printf("previous : %02x\n", last_error_flags);
|
||||
last_error_flags = error_flags;
|
||||
uart_printf("ac : %d\n", ac);
|
||||
uart_puts("charger\n");
|
||||
if (ac)
|
||||
if (error_flags & (F_CHG_V | F_CHG_I))
|
||||
uart_puts(" error\n");
|
||||
else
|
||||
uart_puts(" ok\n");
|
||||
else
|
||||
uart_puts(" offline\n");
|
||||
|
||||
uart_puts("battery\n");
|
||||
uart_printf(" voltage: %d\n", bat_v);
|
||||
uart_printf(" current: %d\n", bat_i);
|
||||
uart_printf(" temp : %d\n", bat_temp);
|
||||
uart_printf(" des_vol: %d\n", desired_v);
|
||||
uart_printf(" des_cur: %d\n", desired_i);
|
||||
}
|
||||
|
||||
return PWR_STATE_UNCHANGE;
|
||||
}
|
||||
|
||||
static void charging_progress(void)
|
||||
{
|
||||
static int state_of_charge;
|
||||
int d;
|
||||
|
||||
if (battery_state_of_charge(&d))
|
||||
return;
|
||||
|
||||
if (d != state_of_charge) {
|
||||
state_of_charge = d;
|
||||
if (get_ac())
|
||||
battery_time_to_full(&d);
|
||||
else
|
||||
battery_time_to_empty(&d);
|
||||
|
||||
uart_printf("[Battery %3d%% / %dh:%d]\n", state_of_charge,
|
||||
d / 60, d % 60);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Battery charging task */
|
||||
void charge_state_machine_task(void)
|
||||
{
|
||||
timestamp_t prev_ts, ts;
|
||||
int sleep_usec, diff_usec;
|
||||
enum power_state current_state, new_state;
|
||||
|
||||
prev_ts.val = 0;
|
||||
current_state = PWR_STATE_INIT;
|
||||
|
||||
while (1) {
|
||||
ts = get_time();
|
||||
|
||||
switch (current_state) {
|
||||
case PWR_STATE_INIT:
|
||||
new_state = state_init();
|
||||
break;
|
||||
case PWR_STATE_IDLE:
|
||||
new_state = state_idle();
|
||||
break;
|
||||
case PWR_STATE_DISCHARGE:
|
||||
new_state = state_discharge();
|
||||
break;
|
||||
case PWR_STATE_CHARGE:
|
||||
new_state = state_charge();
|
||||
break;
|
||||
case PWR_STATE_ERROR:
|
||||
new_state = state_error();
|
||||
break;
|
||||
default:
|
||||
new_state = PWR_STATE_ERROR;
|
||||
}
|
||||
|
||||
if (new_state)
|
||||
uart_printf("CHARGE: %s --> %s\n",
|
||||
_state_name[current_state],
|
||||
_state_name[new_state]);
|
||||
|
||||
switch (new_state) {
|
||||
case PWR_STATE_IDLE:
|
||||
case PWR_STATE_DISCHARGE:
|
||||
sleep_usec = POLL_PERIOD_LONG;
|
||||
break;
|
||||
case PWR_STATE_CHARGE:
|
||||
sleep_usec = POLL_PERIOD_CHARGE;
|
||||
break;
|
||||
default:
|
||||
sleep_usec = POLL_PERIOD_SHORT;
|
||||
}
|
||||
|
||||
diff_usec = (int)(ts.val - prev_ts.val);
|
||||
sleep_usec -= diff_usec;
|
||||
if (sleep_usec < MIN_SLEEP_USEC)
|
||||
sleep_usec = MIN_SLEEP_USEC;
|
||||
|
||||
prev_ts = ts;
|
||||
usleep(sleep_usec);
|
||||
|
||||
if (new_state)
|
||||
current_state = new_state;
|
||||
|
||||
charging_progress();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,5 +225,22 @@ static inline int battery_design_voltage(int *voltage)
|
||||
static inline int battery_serial_number(int *serial)
|
||||
{ return sb_read(SB_SERIAL_NUMBER, serial); }
|
||||
|
||||
/* Read battery discharging current
|
||||
* unit: mA
|
||||
* negative value: charging
|
||||
*/
|
||||
int battery_current(int *current);
|
||||
int battery_average_current(int *current);
|
||||
|
||||
/* Calculate battery time in minutes, under a charging rate
|
||||
* rate > 0: charging, negative time to full
|
||||
* rate < 0: discharging, positive time to empty
|
||||
* rate == 0: invalid input, time = 0
|
||||
*/
|
||||
int battery_time_at_rate(int rate, int *minutes);
|
||||
|
||||
/* Read manufacturer date */
|
||||
int battery_manufacturer_date(int *year, int *month, int *day);
|
||||
|
||||
#endif /* __CROS_EC_SMART_BATTERY_H */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user