743 lines
17 KiB
C
743 lines
17 KiB
C
/* Copyright 2014 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 driver for BQ27621-G1
|
|
*/
|
|
|
|
#include "battery.h"
|
|
#include "console.h"
|
|
#include "extpower.h"
|
|
#include "hooks.h"
|
|
#include "i2c.h"
|
|
#include "util.h"
|
|
#include "timer.h"
|
|
|
|
#define BQ27621_ADDR_FLAGS 0x55
|
|
#define BQ27621_TYPE_ID 0x0621
|
|
|
|
#define REG_CTRL 0x00
|
|
#define REG_TEMPERATURE 0x02
|
|
#define REG_VOLTAGE 0x04
|
|
#define REG_FLAGS 0x06
|
|
#define REG_NOMINAL_CAPACITY 0x08
|
|
#define REG_FULL_AVAILABLE_CAPACITY 0x0a
|
|
#define REG_REMAINING_CAPACITY 0x0c
|
|
#define REG_FULL_CHARGE_CAPACITY 0x0e
|
|
#define REG_EFFECTIVE_CURRENT 0x10
|
|
#define REG_AVERAGE_POWER 0x18
|
|
#define REG_STATE_OF_CHARGE 0x1c
|
|
#define REG_INTERNAL_TEMPERATURE 0x1e
|
|
#define REG_REMAINING_CAPACITY_UNFILTERED 0x28
|
|
#define REG_REMAINING_CAPACITY_FILTERED 0x2a
|
|
#define REG_FULL_CHARGE_CAPACITY_UNFILTERED 0x28
|
|
#define REG_FULL_CHARGE_CAPACITY_FILTERED 0x2a
|
|
#define REG_STATE_OF_CHARGE_UNFILTERED 0x30
|
|
#define REG_OP_CONFIG 0x3a
|
|
#define REG_DESIGN_CAPACITY 0x3c
|
|
#define REG_DATA_CLASS 0x3e
|
|
#define REG_DATA_BLOCK 0x3f
|
|
#define REG_BLOCK_DATA_CHECKSUM 0x60
|
|
#define REG_BLOCK_DATA_CONTROL 0x61
|
|
|
|
#define REGISTERS_BLOCK_OFFSET 64
|
|
#define REGISTERS_BLOCK_OP_CONFIG 0x40
|
|
#define REGISTERS_BLOCK_OP_CONFIG_B 0x42
|
|
#define REGISTERS_BLOCK_DF_VERSION 0x43
|
|
|
|
/* State block */
|
|
#define STATE_BLOCK_OFFSET 82
|
|
#define STATE_BLOCK_DESIGN_CAPACITY 0x43
|
|
#define STATE_BLOCK_DESIGN_ENERGY 0x45
|
|
#define STATE_BLOCK_TERMINATE_VOLTAGE 0x49
|
|
#define STATE_BLOCK_TAPER_RATE 0x54
|
|
|
|
/* BQ27621 Control subcommands */
|
|
#define CONTROL_CONTROL_STATUS 0x00
|
|
#define CONTROL_DEVICE_TYPE 0x01
|
|
#define CONTROL_FW_VERSION 0x02
|
|
#define CONTROL_PREV_MACWRITE 0x07
|
|
#define CONTROL_CHEM_ID 0x08
|
|
#define CONTROL_BAT_INSERT 0x0C
|
|
#define CONTROL_BAT_REMOVE 0x0D
|
|
#define CONTROL_TOGGLE_POWERMIN 0x10
|
|
#define CONTROL_SET_HIBERNATE 0x11
|
|
#define CONTROL_CLEAR_HIBERNATE 0x12
|
|
#define CONTROL_SET_CFGUPDATE 0x13
|
|
#define CONTROL_SHUTDOWN_ENABLE 0x1B
|
|
#define CONTROL_SHUTDOWN 0x1C
|
|
#define CONTROL_SEALED 0x20
|
|
#define CONTROL_TOGGLE_GPOUT 0x23
|
|
#define CONTROL_ALT_CHEM1 0x31
|
|
#define CONTROL_ALT_CHEM2 0x32
|
|
#define CONTROL_RESET 0x41
|
|
#define CONTROL_SOFT_RESET 0x42
|
|
#define CONTROL_EXIT_CFGUPDATE 0x43
|
|
#define CONTROL_EXIT_RESIM 0x44
|
|
#define CONTROL_UNSEAL 0x8000
|
|
|
|
/* BQ27621 Status bits */
|
|
#define STATUS_SHUTDOWNEN 0x8000
|
|
#define STATUS_WDRESET 0x4000
|
|
#define STATUS_SS 0x2000
|
|
#define STATUS_CALMODE 0x1000
|
|
#define STATUS_OCVCMDCOMP 0x0200
|
|
#define STATUS_OCVFAIL 0x0100
|
|
#define STATUS_INITCOMP 0x0080
|
|
#define STATUS_HIBERNATE 0x0040
|
|
#define STATUS_POWERMIN 0x0020
|
|
#define STATUS_SLEEP 0x0010
|
|
#define STATUS_LDMD 0x0008
|
|
#define STATUS_CHEMCHNG 0x0001
|
|
|
|
/* BQ27621 Flags bits */
|
|
#define FLAGS_OT 0x8000
|
|
#define FLAGS_UT 0x4000
|
|
#define FLAGS_FC 0x0200
|
|
#define FLAGS_CHG 0x0100
|
|
#define FLAGS_OCVTAKEN 0x0080
|
|
#define FLAGS_ITPOR 0x0020
|
|
#define FLAGS_CFGUPD 0x0010
|
|
#define FLAGS_BAT_DET 0x0008
|
|
#define FLAGS_SOC1 0x0004
|
|
#define FLAGS_SOCF 0x0002
|
|
#define FLAGS_DSG 0x0001
|
|
|
|
/*
|
|
* There are some parameters that need to be defined in the board file:
|
|
* BQ27621_TOGGLE_POWER_MIN - Put it in minimum power mode
|
|
* (may affect I2C timing)
|
|
* BQ27621_DESIGN_CAPACITY - mAh
|
|
* BQ27621_DESIGN_ENERGY - Design Capacity x 3.7
|
|
* BQ27621_TERMINATE_VOLTAGE - mV
|
|
* BQ27621_TAPER_CURRENT - mA
|
|
* BQ27621_CHEM_ID - 0x1202 (DEFAULT) 0x1210 (ALT_CHEM1)
|
|
* 0x354 (ALT_CHEM2)
|
|
*
|
|
* For extra large or extra small batteries, this driver scales everything but
|
|
* voltages. The recommended range is 150mAh - 6Ah
|
|
*
|
|
*/
|
|
|
|
#define BQ27621_SCALE_FACTOR (BQ27621_DESIGN_CAPACITY < 150 ? 10.0 : \
|
|
(BQ27621_DESIGN_CAPACITY > 6000 ? 0.1 : 1))
|
|
|
|
#define BQ27621_UNSCALE(x) (BQ27621_SCALE_FACTOR == 10 ? (x) / 10 : \
|
|
(BQ27621_SCALE_FACTOR == 0.1 ? (x) * 10 : (x)))
|
|
|
|
#define BQ27621_TAPER_RATE ((int)(BQ27621_DESIGN_CAPACITY/ \
|
|
(0.1 * BQ27621_TAPER_CURRENT)))
|
|
|
|
#define BQ27621_SCALED_DESIGN_CAPACITY ((int)(BQ27621_DESIGN_CAPACITY * \
|
|
BQ27621_SCALE_FACTOR))
|
|
#define BQ27621_SCALED_DESIGN_ENERGY ((int)(BQ27621_DESIGN_CAPACITY * \
|
|
BQ27621_SCALE_FACTOR))
|
|
|
|
/*
|
|
*Everything is LSB first. Parameters need to be converted.
|
|
*
|
|
* The values from the data sheet are already LSB-first.
|
|
*/
|
|
|
|
#define ENDIAN_SWAP_2B(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
|
|
#define DESIGN_CAPACITY ENDIAN_SWAP_2B(BQ27621_SCALED_DESIGN_CAPACITY)
|
|
#define DESIGN_ENERGY ENDIAN_SWAP_2B(BQ27621_SCALED_DESIGN_ENERGY)
|
|
#define TAPER_RATE ENDIAN_SWAP_2B(BQ27621_TAPER_RATE)
|
|
#define TERMINATE_VOLTAGE ENDIAN_SWAP_2B(BQ27621_TERMINATE_VOLTAGE)
|
|
|
|
struct battery_info battery_params;
|
|
|
|
static int bq27621_read(int offset, int *data)
|
|
{
|
|
return i2c_read16(I2C_PORT_BATTERY, BQ27621_ADDR, offset, data);
|
|
}
|
|
|
|
static int bq27621_read8(int offset, int *data)
|
|
{
|
|
return i2c_read8(I2C_PORT_BATTERY, BQ27621_ADDR, offset, data);
|
|
}
|
|
|
|
static int bq27621_write(int offset, int data)
|
|
{
|
|
return i2c_write16(I2C_PORT_BATTERY, BQ27621_ADDR, offset, data);
|
|
}
|
|
|
|
static int bq27621_write8(int offset, int data)
|
|
{
|
|
return i2c_write8(I2C_PORT_BATTERY, BQ27621_ADDR, offset, data);
|
|
}
|
|
|
|
static int bq27621_probe(void)
|
|
{
|
|
int rv;
|
|
int battery_type_id;
|
|
|
|
/* Delays need to be added for correct operation at > 100Kbps */
|
|
ASSERT(i2c_ports[I2C_PORT_BATTERY].kbps <= 100);
|
|
|
|
rv = bq27621_write(REG_CTRL, CONTROL_DEVICE_TYPE);
|
|
rv |= bq27621_read(REG_CTRL, &battery_type_id);
|
|
|
|
if (rv)
|
|
return rv;
|
|
if (battery_type_id == BQ27621_TYPE_ID) {
|
|
battery_params.voltage_max = BATTERY_VOLTAGE_MAX;
|
|
battery_params.voltage_normal = BATTERY_VOLTAGE_NORMAL;
|
|
battery_params.voltage_min = BATTERY_VOLTAGE_MIN;
|
|
return EC_SUCCESS;
|
|
}
|
|
return EC_ERROR_UNKNOWN;
|
|
}
|
|
|
|
static inline int bq27621_unseal(void)
|
|
{
|
|
return bq27621_write(REG_CTRL, CONTROL_UNSEAL) |
|
|
bq27621_write(REG_CTRL, CONTROL_UNSEAL);
|
|
}
|
|
|
|
static int bq27621_enter_config_update(void)
|
|
{
|
|
int tries, flags = 0, rv = EC_SUCCESS;
|
|
|
|
/* Enter Config Update Mode (Can take up to a second) */
|
|
for (tries = 2000; tries > 0 && !(flags & FLAGS_CFGUPD) &&
|
|
(rv == EC_SUCCESS); tries--) {
|
|
rv |= bq27621_write(REG_CTRL, CONTROL_SET_CFGUPDATE);
|
|
rv |= bq27621_read(REG_FLAGS, &flags);
|
|
}
|
|
|
|
if (tries == 0)
|
|
return EC_ERROR_TIMEOUT;
|
|
else
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
static int bq27621_enter_block_mode(int block)
|
|
{
|
|
int rv;
|
|
rv = bq27621_write8(REG_BLOCK_DATA_CONTROL, 0);
|
|
rv |= bq27621_write8(REG_DATA_CLASS, block);
|
|
rv |= bq27621_write8(REG_DATA_BLOCK, 0);
|
|
udelay(500); /* Shouldn't be needed, doesn't work without it. */
|
|
return rv;
|
|
}
|
|
|
|
static int bq27621_seal(void)
|
|
{
|
|
int rv = 0;
|
|
int status = 0, param = 0, checksum = 0;
|
|
|
|
rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS);
|
|
rv |= bq27621_read(REG_CTRL, &status);
|
|
|
|
if (status & STATUS_SS) /* Already sealed */
|
|
return EC_SUCCESS;
|
|
|
|
/* Enter Config Update Mode */
|
|
rv = bq27621_enter_config_update();
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
/* Set up block RAM update */
|
|
rv = bq27621_enter_block_mode(REGISTERS_BLOCK_OFFSET);
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
rv = bq27621_read8(REG_BLOCK_DATA_CHECKSUM, &checksum);
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
checksum = 0xff - checksum;
|
|
|
|
rv = bq27621_read8(REGISTERS_BLOCK_OP_CONFIG_B, ¶m);
|
|
checksum -= param; /* 1B */
|
|
|
|
param |= 1<<5; /* Set DEF_SEAL */
|
|
|
|
rv = bq27621_write8(REGISTERS_BLOCK_OP_CONFIG_B, param);
|
|
checksum += param; /* 1B */
|
|
|
|
checksum = 0xff - (0xff & checksum);
|
|
|
|
rv = bq27621_write8(REG_BLOCK_DATA_CHECKSUM, checksum);
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
/* Exit Update */
|
|
rv = bq27621_write(REG_CTRL, CONTROL_SOFT_RESET);
|
|
|
|
return rv;
|
|
}
|
|
|
|
#define CHECKSUM_2B(x) ((x & 0xff) + ((x>>8) & 0xff))
|
|
|
|
static int bq27621_init(void)
|
|
{
|
|
int rv;
|
|
int status = 0, param = 0, checksum = 0;
|
|
|
|
rv = bq27621_probe();
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
/* Unseal the device if necessary */
|
|
rv |= bq27621_write(REG_CTRL, CONTROL_CONTROL_STATUS);
|
|
rv |= bq27621_read(REG_CTRL, &status);
|
|
|
|
if (status & STATUS_SS)
|
|
rv |= bq27621_unseal();
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
/* Select the alternate chemistry if needed */
|
|
rv = bq27621_write(REG_CTRL, CONTROL_CHEM_ID);
|
|
rv |= bq27621_read(REG_CTRL, ¶m);
|
|
|
|
if (param != BQ27621_CHEM_ID) { /* Change needed */
|
|
|
|
if (BQ27621_CHEM_ID == 0x1202) { /* Return to default */
|
|
rv |= bq27621_write(REG_CTRL, CONTROL_RESET);
|
|
} else {
|
|
rv |= bq27621_enter_config_update();
|
|
|
|
if (BQ27621_CHEM_ID == 0x1210)
|
|
rv |= bq27621_write(REG_CTRL,
|
|
CONTROL_ALT_CHEM1);
|
|
if (BQ27621_CHEM_ID == 0x0354)
|
|
rv |= bq27621_write(REG_CTRL,
|
|
CONTROL_ALT_CHEM2);
|
|
|
|
/*
|
|
* The datasheet recommends checking the status here.
|
|
*
|
|
* If the CHEMCHG is active, it wasn't successful.
|
|
*
|
|
* There's no recommendation for what to do if it isn't.
|
|
*/
|
|
|
|
rv |= bq27621_write(REG_CTRL, CONTROL_EXIT_CFGUPDATE);
|
|
}
|
|
}
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
rv = bq27621_enter_config_update();
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
/* Set up block RAM update */
|
|
rv = bq27621_enter_block_mode(STATE_BLOCK_OFFSET);
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
rv = bq27621_read8(REG_BLOCK_DATA_CHECKSUM, &checksum);
|
|
if (rv)
|
|
return rv;
|
|
|
|
checksum = 0xff - checksum;
|
|
|
|
rv = bq27621_read(STATE_BLOCK_DESIGN_CAPACITY, ¶m);
|
|
checksum -= CHECKSUM_2B(param);
|
|
|
|
rv |= bq27621_read(STATE_BLOCK_DESIGN_ENERGY, ¶m);
|
|
checksum -= CHECKSUM_2B(param);
|
|
|
|
rv |= bq27621_read(STATE_BLOCK_TERMINATE_VOLTAGE, ¶m);
|
|
checksum -= CHECKSUM_2B(param);
|
|
|
|
rv |= bq27621_read(STATE_BLOCK_TAPER_RATE, ¶m);
|
|
checksum -= CHECKSUM_2B(param);
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
rv = bq27621_write(STATE_BLOCK_DESIGN_CAPACITY, DESIGN_CAPACITY);
|
|
checksum += CHECKSUM_2B(DESIGN_CAPACITY);
|
|
|
|
rv |= bq27621_write(STATE_BLOCK_DESIGN_ENERGY, DESIGN_ENERGY);
|
|
checksum += CHECKSUM_2B(DESIGN_ENERGY);
|
|
|
|
rv |= bq27621_write(STATE_BLOCK_TERMINATE_VOLTAGE, TERMINATE_VOLTAGE);
|
|
checksum += CHECKSUM_2B(TERMINATE_VOLTAGE);
|
|
|
|
rv |= bq27621_write(STATE_BLOCK_TAPER_RATE, TAPER_RATE);
|
|
checksum += CHECKSUM_2B(TAPER_RATE);
|
|
|
|
checksum = 0xff - (0xff & checksum);
|
|
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
rv = bq27621_write8(REG_BLOCK_DATA_CHECKSUM, checksum);
|
|
|
|
rv |= bq27621_write(REG_CTRL, CONTROL_SOFT_RESET);
|
|
|
|
if (rv)
|
|
return rv;
|
|
|
|
bq27621_seal();
|
|
|
|
return rv;
|
|
}
|
|
|
|
static void probe_type_id_init(void)
|
|
{
|
|
int rv = EC_SUCCESS;
|
|
|
|
rv = bq27621_probe();
|
|
|
|
if (rv)
|
|
return;
|
|
|
|
rv = bq27621_init();
|
|
|
|
if (rv) { /* Try it once more */
|
|
rv = bq27621_write(REG_CTRL, CONTROL_RESET);
|
|
rv |= bq27621_init();
|
|
}
|
|
}
|
|
|
|
DECLARE_HOOK(HOOK_INIT, probe_type_id_init, HOOK_PRIO_DEFAULT);
|
|
|
|
/* Some of the functions to make this battery "smart" */
|
|
|
|
int battery_device_name(char *device_name, int buf_size)
|
|
{
|
|
return EC_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
int battery_state_of_charge_abs(int *percent)
|
|
{
|
|
return EC_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
int battery_remaining_capacity(int *capacity)
|
|
{
|
|
int scaled_value, err_code;
|
|
|
|
err_code = bq27621_read(REG_REMAINING_CAPACITY, &scaled_value);
|
|
|
|
*capacity = BQ27621_UNSCALE(scaled_value);
|
|
|
|
return err_code;
|
|
}
|
|
|
|
int battery_full_charge_capacity(int *capacity)
|
|
{
|
|
int scaled_value, err_code;
|
|
|
|
err_code = bq27621_read(REG_FULL_CHARGE_CAPACITY, &scaled_value);
|
|
|
|
*capacity = BQ27621_UNSCALE(scaled_value);
|
|
|
|
return err_code;
|
|
}
|
|
|
|
int battery_time_to_empty(int *minutes)
|
|
{
|
|
return EC_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
int battery_time_to_full(int *minutes)
|
|
{
|
|
return EC_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
int battery_cycle_count(int *count)
|
|
{
|
|
return EC_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
int battery_design_capacity(int *capacity)
|
|
{
|
|
int scaled_value, err_code;
|
|
|
|
err_code = bq27621_read(REG_DESIGN_CAPACITY, &scaled_value);
|
|
|
|
*capacity = BQ27621_UNSCALE(scaled_value);
|
|
|
|
return err_code;
|
|
}
|
|
|
|
int battery_time_at_rate(int rate, int *minutes)
|
|
{
|
|
return EC_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
int battery_device_chemistry(char *dest, int size)
|
|
{
|
|
uint32_t rv;
|
|
int param;
|
|
|
|
rv = bq27621_write(REG_CTRL, CONTROL_CHEM_ID);
|
|
rv |= bq27621_read(REG_CTRL, ¶m);
|
|
|
|
if (param == 0x1202)
|
|
strzcpy(dest, "0x1202 (default)", size);
|
|
if (param == 0x1210)
|
|
strzcpy(dest, "0x1210 (ALT_CHEM1)", size);
|
|
if (param == 0x0354)
|
|
strzcpy(dest, "0x0354 (ALT_CHEM2)", size);
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
int battery_serial_number(int *serial)
|
|
{
|
|
return EC_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
int battery_design_voltage(int *voltage)
|
|
{
|
|
*voltage = BATTERY_VOLTAGE_NORMAL;
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
int battery_get_mode(int *mode)
|
|
{
|
|
return EC_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
int battery_status(int *status)
|
|
{
|
|
return EC_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
enum battery_present battery_is_present(void)
|
|
{
|
|
return EC_ERROR_UNIMPLEMENTED;
|
|
}
|
|
|
|
void battery_get_params(struct batt_params *batt)
|
|
{
|
|
/* Reset flags */
|
|
batt->flags = 0;
|
|
|
|
if (bq27621_read(REG_TEMPERATURE, &batt->temperature))
|
|
batt->flags |= BATT_FLAG_BAD_TEMPERATURE;
|
|
else
|
|
batt->flags |= BATT_FLAG_RESPONSIVE; /* Battery is responding */
|
|
|
|
if (bq27621_read8(REG_STATE_OF_CHARGE, &batt->state_of_charge))
|
|
batt->flags |= BATT_FLAG_BAD_STATE_OF_CHARGE;
|
|
|
|
if (bq27621_read(REG_VOLTAGE, &batt->voltage))
|
|
batt->flags |= BATT_FLAG_BAD_VOLTAGE;
|
|
|
|
batt->flags |= BATT_FLAG_BAD_CURRENT;
|
|
batt->current = 0;
|
|
|
|
/* Default to not desiring voltage and current */
|
|
batt->desired_voltage = batt->desired_current = 0;
|
|
}
|
|
|
|
/* Wait until battery is totally stable */
|
|
int battery_wait_for_stable(void)
|
|
{
|
|
/* TODO(crosbug.com/p/30426): implement me */
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
#ifdef CONFIG_CMD_BATDEBUG
|
|
#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args)
|
|
#else
|
|
#define CPRINTF(format, args...)
|
|
#endif
|
|
|
|
#ifdef CONFIG_CMD_BATDEBUG
|
|
|
|
static int command_fgunseal(int argc, char **argv)
|
|
{
|
|
int rv = EC_SUCCESS;
|
|
|
|
if (argc > 1)
|
|
return EC_ERROR_PARAM_COUNT;
|
|
|
|
rv = bq27621_unseal();
|
|
|
|
return rv;
|
|
}
|
|
|
|
DECLARE_CONSOLE_COMMAND(fgunseal, command_fgunseal,
|
|
"",
|
|
"Unseal the fg");
|
|
|
|
static int command_fgseal(int argc, char **argv)
|
|
{
|
|
int rv = EC_SUCCESS;
|
|
|
|
if (argc > 1)
|
|
return EC_ERROR_PARAM_COUNT;
|
|
|
|
rv = bq27621_seal();
|
|
|
|
return rv;
|
|
}
|
|
|
|
DECLARE_CONSOLE_COMMAND(fgseal, command_fgseal,
|
|
"",
|
|
"Seal the fg");
|
|
|
|
static int command_fginit(int argc, char **argv)
|
|
{
|
|
int rv = EC_SUCCESS;
|
|
int force = 0;
|
|
int flags = 0;
|
|
int unconfigured = 0;
|
|
char *e;
|
|
|
|
if (argc > 2)
|
|
return EC_ERROR_PARAM_COUNT;
|
|
|
|
if (argc == 2) {
|
|
force = strtoi(argv[1], &e, 0);
|
|
if (*e)
|
|
return EC_ERROR_PARAM1;
|
|
}
|
|
|
|
rv = bq27621_read(REG_FLAGS, &flags);
|
|
unconfigured = flags & FLAGS_ITPOR;
|
|
|
|
if (!unconfigured && force) {
|
|
rv |= bq27621_write(REG_CTRL, CONTROL_RESET);
|
|
unconfigured = (rv == EC_SUCCESS);
|
|
}
|
|
|
|
if (unconfigured)
|
|
rv |= bq27621_init();
|
|
|
|
return rv;
|
|
}
|
|
|
|
DECLARE_CONSOLE_COMMAND(fginit, command_fginit,
|
|
"[force]",
|
|
"Initialize the fg");
|
|
|
|
static int command_fgprobe(int argc, char **argv)
|
|
{
|
|
int rv = EC_SUCCESS;
|
|
|
|
if (argc != 1)
|
|
return EC_ERROR_PARAM_COUNT;
|
|
|
|
rv = bq27621_probe();
|
|
|
|
return rv;
|
|
}
|
|
|
|
DECLARE_CONSOLE_COMMAND(fgprobe, command_fgprobe,
|
|
"",
|
|
"Probe the fg");
|
|
|
|
static int command_fgrd(int argc, char **argv)
|
|
{
|
|
int cmd, len;
|
|
int rv = EC_SUCCESS;
|
|
int data;
|
|
char *e;
|
|
|
|
if (argc < 3)
|
|
return EC_ERROR_PARAM_COUNT;
|
|
|
|
cmd = strtoi(argv[1], &e, 0);
|
|
if (*e)
|
|
return EC_ERROR_PARAM1;
|
|
|
|
len = strtoi(argv[2], &e, 0);
|
|
if (*e)
|
|
return EC_ERROR_PARAM2;
|
|
|
|
if (len == 2)
|
|
rv = bq27621_read(cmd, &data);
|
|
else if (len == 1)
|
|
rv = bq27621_read8(cmd, &data);
|
|
else
|
|
return EC_ERROR_PARAM2;
|
|
|
|
CPRINTF("Read %d bytes @0xaa %0x: 0x%0x\n", len, cmd, data);
|
|
|
|
return rv;
|
|
}
|
|
|
|
DECLARE_CONSOLE_COMMAND(fgrd, command_fgrd,
|
|
"cmd len",
|
|
"Read _len_ words from the fg");
|
|
|
|
static int command_fgcmd(int argc, char **argv)
|
|
{
|
|
int cmd, data, byte = 0;
|
|
char *e;
|
|
|
|
if (argc < 3 || argc > 4)
|
|
return EC_ERROR_PARAM_COUNT;
|
|
|
|
cmd = strtoi(argv[1], &e, 0);
|
|
if (*e)
|
|
return EC_ERROR_PARAM1;
|
|
|
|
data = strtoi(argv[2], &e, 0);
|
|
if (*e)
|
|
return EC_ERROR_PARAM2;
|
|
|
|
if (argc >= 4) {
|
|
byte = strtoi(argv[3], &e, 0);
|
|
if (*e)
|
|
return EC_ERROR_PARAM3;
|
|
}
|
|
|
|
if (byte) {
|
|
CPRINTF("Write a byte @0xaa %0x: 0x%0x\n", cmd, data);
|
|
return bq27621_write8(cmd, data);
|
|
} else {
|
|
CPRINTF("Write 2 bytes @0xaa %0x: 0x%0x\n", cmd, data);
|
|
return bq27621_write(cmd, data);
|
|
}
|
|
|
|
}
|
|
|
|
DECLARE_CONSOLE_COMMAND(fgcmd, command_fgcmd,
|
|
"cmd data [byte]",
|
|
"Send a cmd to the fg");
|
|
|
|
static int command_fgcmdrd(int argc, char **argv)
|
|
{
|
|
int cmd, data, val;
|
|
int rv = EC_SUCCESS;
|
|
char *e;
|
|
|
|
if (argc < 3)
|
|
return EC_ERROR_PARAM_COUNT;
|
|
|
|
cmd = strtoi(argv[1], &e, 0);
|
|
if (*e)
|
|
return EC_ERROR_PARAM1;
|
|
|
|
data = strtoi(argv[2], &e, 0);
|
|
if (*e)
|
|
return EC_ERROR_PARAM2;
|
|
|
|
rv = bq27621_write(cmd, data);
|
|
rv |= bq27621_read(cmd, &val);
|
|
|
|
CPRINTF("Read: @0xaa (%x %x) %x\n", cmd, data, val);
|
|
return rv;
|
|
}
|
|
|
|
DECLARE_CONSOLE_COMMAND(fgcmdrd, command_fgcmdrd,
|
|
"cmd data",
|
|
"Send a 2-byte cmd to the fg, read back the 2-byte result");
|
|
|
|
#endif /* CONFIG_CMD_BATDEBUG */
|
|
|