Files
OpenCellular/common/smart_battery.c
Rong Chang 526db244e4 Add smart battery functions read ascii info
Signed-off-by: Rong Chang <rongchang@chromium.org>

BUG=chrome-os-partner:8321
TEST=manual:
   type 'battery' in EC serial console, check following fields:
     Manufacturer
     Device name
     Device chemistry
CQ-DEPEND:I0ad3ad45b796d9ec03d8fbc1d643aa6a92d6343f

Change-Id: Iad4d63c996272568b5a661a6716790ef151b29c5
2012-03-06 16:15:30 +08:00

255 lines
5.4 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.
*
* Smart battery driver.
*/
#include "console.h"
#include "smart_battery.h"
#include "timer.h"
#include "uart.h"
#include "util.h"
/* Read battery discharging current
* unit: mA
* negative value: charging
*/
int battery_current(int *current)
{
int rv, d;
rv = sb_read(SB_CURRENT, &d);
if (rv)
return rv;
*current = (int16_t)d;
return EC_SUCCESS;
}
int battery_average_current(int *current)
{
int rv, d;
rv = sb_read(SB_AVERAGE_CURRENT, &d);
if (rv)
return rv;
*current = (int16_t)d;
return EC_SUCCESS;
}
/* 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)
{
int rv;
int ok, time;
int loop, cmd, output_sign;
if (rate == 0) {
*minutes = 0;
return EC_ERROR_INVAL;
}
rv = sb_write(SB_AT_RATE, rate);
if (rv)
return rv;
loop = 5;
while (loop--) {
rv = sb_read(SB_AT_RATE_OK, &ok);
if (rv)
return rv;
if (ok) {
if (rate > 0) {
cmd = SB_AT_RATE_TIME_TO_FULL;
output_sign = -1;
} else {
cmd = SB_AT_RATE_TIME_TO_EMPTY;
output_sign = 1;
}
rv = sb_read(cmd, &time);
if (rv)
return rv;
*minutes = (time == 0xffff) ? 0 : output_sign * time;
return EC_SUCCESS;
} else {
/* wait 10ms for AT_RATE_OK */
usleep(10000);
}
}
return EC_ERROR_TIMEOUT;
}
/* Read manufacturer date */
int battery_manufacturer_date(int *year, int *month, int *day)
{
int rv;
int ymd;
rv = sb_read(SB_SPECIFICATION_INFO, &ymd);
if (rv)
return rv;
/* battery date format:
* ymd = day + month * 32 + (year - 1980) * 256
*/
*year = (ymd >> 8) + 1980;
*month = (ymd & 0xff) / 32;
*day = (ymd & 0xff) % 32;
return EC_SUCCESS;
}
/* Console commands */
static int command_battery(int argc, char **argv)
{
int rv;
int d;
int hour, minute;
char text[32];
const char *unit;
uart_puts("Reading battery...\n");
rv = battery_temperature(&d);
if (rv)
return rv;
uart_printf(" Temperature: 0x%04x = %d x 0.1K (%d C)\n",
d, d, (d-2731)/10);
uart_printf(" Manufacturer: %s\n",
battery_manufacturer_name(text, sizeof(text)) == EC_SUCCESS ?
text : "(error)");
uart_printf(" Device: %s\n",
battery_device_name(text, sizeof(text)) == EC_SUCCESS ?
text : "(error)");
uart_printf(" Chemistry: %s\n",
battery_device_chemistry(text, sizeof(text)) == EC_SUCCESS ?
text : "(error)");
battery_serial_number(&d);
uart_printf(" Serial number: 0x%04x\n", d);
battery_voltage(&d);
uart_printf(" Voltage: 0x%04x = %d mV\n", d, d);
battery_desired_voltage(&d);
uart_printf(" Desired voltage 0x%04x = %d mV\n", d, d);
battery_design_voltage(&d);
uart_printf(" Design output voltage 0x%04x = %d mV\n", d, d);
battery_current(&d);
uart_printf(" Current: 0x%04x = %d mA",
d & 0xffff, d);
if (d > 0)
uart_puts("(CHG)");
else if (d < 0)
uart_puts("(DISCHG)");
uart_puts("\n");
battery_desired_current(&d);
uart_printf(" Desired current 0x%04x = %d mA\n", d, d);
battery_get_battery_mode(&d);
uart_printf(" Battery mode: 0x%04x\n", d);
unit = (d & MODE_CAPACITY) ? "0 mW" : " mAh";
battery_state_of_charge(&d);
uart_printf(" %% of charge: %d %%\n", d);
battery_state_of_charge_abs(&d);
uart_printf(" Abs %% of charge: %d %%\n", d);
battery_remaining_capacity(&d);
uart_printf(" Remaining capacity: %d%s\n", d, unit);
battery_full_charge_capacity(&d);
uart_printf(" Full charge capacity: %d%s\n", d, unit);
battery_design_capacity(&d);
uart_printf(" Design capacity: %d%s\n", d, unit);
battery_time_to_empty(&d);
if (d == 65535) {
hour = 0;
minute = 0;
} else {
hour = d / 60;
minute = d % 60;
}
uart_printf(" Time to empty: %dh:%d\n", hour, minute);
battery_time_to_full(&d);
if (d == 65535) {
hour = 0;
minute = 0;
} else {
hour = d / 60;
minute = d % 60;
}
uart_printf(" Time to full: %dh:%d\n", hour, minute);
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(battery, command_battery);
static int command_sb(int argc, char **argv)
{
int rv;
int cmd, d;
char *e;
if (argc < 3)
goto usage;
cmd = strtoi(argv[2], &e, 0);
if (*e) {
uart_puts("Invalid cmd.\n");
goto usage;
}
if (argv[1][0] == 'r') {
rv = i2c_read16(I2C_PORT_BATTERY, BATTERY_ADDR, cmd, &d);
if (rv) {
uart_puts("I2C read failed.\n");
return rv;
}
uart_printf("R SBCMD[%04x] 0x%04x (%d)\n", cmd, d, d);
return EC_SUCCESS;
} else if (argc >= 4 && argv[1][0] == 'w') {
d = strtoi(argv[3], &e, 0);
if (*e) {
uart_puts("Invalid w_word.\n");
goto usage;
}
uart_printf("W SBCMD[%04x] 0x%04x (%d)\n", cmd, d, d);
rv = i2c_write16(I2C_PORT_BATTERY, BATTERY_ADDR, cmd, d);
if (rv) {
uart_puts("I2C write failed.\n");
return rv;
}
return EC_SUCCESS;
}
usage:
uart_puts("Usage:sb <r/w> cmd [uint16_t w_word]\n");
uart_puts(" sb r 0x14 // desired charging current\n");
uart_puts(" sb r 0x15 // desired charging voltage\n");
uart_puts(" sb r 0x3 // battery mode\n");
uart_puts(" sb w 0x3 0xe001 // set battery mode\n");
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(sb, command_sb);