blob: a70fa4f4035874c4555d40e2f81ee3d364da6af2 [file] [log] [blame]
/*
* 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* Battery command interface
*/
#include <common.h>
#include <battery.h>
#include <asm/arch/power.h>
/* TODO(sjg@chromium.org): Move this to device tree */
static const struct battery_charge_config config = {
/*
* Limit temperatures in milli-degrees celsius.
*
* We have a three maximum temperatures:
* - maximum above which we will not *start* charging
* - maximum above which we stop charging
* - absolute maximum above which we disconnect power and turn off.
*/
.min_temperature = 5000, /* Minimum for charging */
.max_start_temperature = 40000, /* Maximum to start charging */
.max_charge_temperature = 55000, /* Maximum to charge */
.max_temperature = 65000, /* Over this we disconnect */
};
/**
* Perform a single step of the battery state machine
*
* @param state Returns resulting battery state
* @return 0 if ok, -1 on error
*/
static int battery_charge_step(struct battery_charge_state *state,
const struct battery_charge_config *config)
{
int err;
/* Work out the current state of affairs */
err = battery_get_charge_state(state);
if (err) {
debug("%s: Cannot read battery state\n", __func__);
return err;
}
/* Decide what action to take in response */
state->action = battery_calculate_action(state, config);
/* Perform that action */
switch (state->action) {
case BATTERY_ACT_START_CHARGE:
err = battery_set_charge_enable(1);
debug("Charging enabled\n");
break;
case BATTERY_ACT_STOP_CHARGE:
err = battery_set_charge_enable(0);
debug("Charging disabled\n");
break;
case BATTERY_ACT_DISCONNECT:
printf("Critical battery error: powering off\n");
udelay(5 * 1000);
power_shutdown(); /* Does not return */
break;
case BATTERY_ACT_NONE:
case BATTERY_ACT_COUNT:
break;
}
if (err) {
debug("%s: Cannot change charge state\n", __func__);
return err;
}
return 0;
}
static int battery_charge_report(struct battery_charge_state *state)
{
printf("%us: %s", state->seconds,
battery_get_status_name(state->status));
if (state->status != BATTERY_MISSING) {
printf(" %d%% %dmA %d.%ldC (status bat=%#04x, tps=%#02x)",
state->percent_charge,
state->average_current_ma,
state->milli_degrees_c / 1000,
(abs(state->milli_degrees_c) % 1000) / 100,
state->battery_status, state->charger_status);
if (state->action)
printf(", %s", battery_get_action_name(state->action));
}
puts("\n");
return 0;
}
static int do_battery(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
const char *cmd;
int ret = 0;
if (argc < 2)
return CMD_RET_USAGE;
cmd = argv[1];
argc -= 2;
argv += 2;
if (!strncmp(cmd, "info", 3)) {
struct battery_info info;
if (battery_get_info(&info)) {
printf("Error getting battery info\n");
} else {
printf("Manufacturer: %s\n", info.manuf_name);
printf("Device: %s\n", info.device_name);
printf("Chemistry: %s\n", info.device_chem);
printf("Serial number: %d\n", info.serial_num);
printf("Design capacity (mAhr): %d\n",
info.design_cap_mah);
printf("Design voltage (mV): %d\n",
info.design_voltage_mv);
printf("Voltage (mV): %d\n", info.voltage_mv);
printf("Average current (mA): %u\n",
info.average_current_ma);
printf("Relative charge (%%): %u\n",
info.relative_charge);
printf("Battery status: %04x\n", info.battery_status);
}
} else if (!strncmp(cmd, "init", 1)) {
ret = battery_init();
} else if (!strncmp(cmd, "charge", 1)) {
if (!argc) {
int status;
status = battery_get_status();
printf("%s\n", battery_get_status_name(status));
} else {
int enable = simple_strtoul(*argv, NULL, 10);
ret = battery_set_charge_enable(enable);
}
} else if (!strncmp(cmd, "loop", 1)) {
struct battery_charge_state state;
unsigned long start;
printf("Entering charging loop, press <space> to stop\n");
ret = battery_charge_init(&state);
start = get_timer(0);
while (!ret && !tstc()) {
ret = battery_charge_step(&state, &config);
if (!ret)
ret = battery_charge_report(&state);
if (ret) {
printf("(battery error %d)\n", ret);
ret = 0;
}
while (!tstc() && get_timer(start) < 10 * 1000)
;
start += 10 * 1000;
}
if (!ret)
printf("Charge loop complete (can power down)\n");
} else if (!strncmp(cmd, "temperature", 1)) {
int m_degrees_c;
ret = battery_get_temperature(&m_degrees_c);
printf("Battery temperature %u.%lu\n", m_degrees_c / 1000,
(abs(m_degrees_c) % 1000) / 100);
} else {
return CMD_RET_USAGE;
}
if (ret)
printf("Battery error %d\n", ret);
return CMD_RET_SUCCESS;
}
U_BOOT_CMD(
battery, 5, 1, do_battery,
"Battery utility command",
" - perform battery operations\n"
"charge [<0/1>] - See charge state, or turn charging on / off\n"
"info - Display battery information\n"
"temperature - Display battery temperature\n"
"loop - Go into battery charge loop"
);