278 lines
5.8 KiB
C
278 lines
5.8 KiB
C
|
/* Copyright 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.
|
||
|
*
|
||
|
* TI bq24192 battery charger driver.
|
||
|
*/
|
||
|
|
||
|
#include "bq24192.h"
|
||
|
#include "charger.h"
|
||
|
#include "common.h"
|
||
|
#include "console.h"
|
||
|
#include "gpio.h"
|
||
|
#include "hooks.h"
|
||
|
#include "i2c.h"
|
||
|
#include "printf.h"
|
||
|
#include "util.h"
|
||
|
|
||
|
/* Console output macros */
|
||
|
#define CPUTS(outstr) cputs(CC_CHARGER, outstr)
|
||
|
#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args)
|
||
|
|
||
|
/* Charger information */
|
||
|
static const struct charger_info bq24192_charger_info = {
|
||
|
.name = "bq24192",
|
||
|
.voltage_max = 4400,
|
||
|
.voltage_min = 3504,
|
||
|
.voltage_step = 16,
|
||
|
.current_max = 4544,
|
||
|
.current_min = 512,
|
||
|
.current_step = 64,
|
||
|
.input_current_max = 3000,
|
||
|
.input_current_min = 100,
|
||
|
.input_current_step = -1,
|
||
|
};
|
||
|
|
||
|
static const int input_current_steps[] = {
|
||
|
100, 150, 500, 900, 1200, 1500, 2000, 3000};
|
||
|
|
||
|
static int bq24192_read(int reg, int *value)
|
||
|
{
|
||
|
return i2c_read8(I2C_PORT_CHARGER, BQ24192_ADDR, reg, value);
|
||
|
}
|
||
|
|
||
|
static int bq24192_write(int reg, int value)
|
||
|
{
|
||
|
return i2c_write8(I2C_PORT_CHARGER, BQ24192_ADDR, reg, value);
|
||
|
}
|
||
|
|
||
|
static int bq24192_watchdog_reset(void)
|
||
|
{
|
||
|
int rv, val;
|
||
|
|
||
|
rv = bq24192_read(BQ24192_REG_POWER_ON_CFG, &val);
|
||
|
if (rv)
|
||
|
return rv;
|
||
|
val |= BIT(6);
|
||
|
return bq24192_write(BQ24192_REG_POWER_ON_CFG, val) ||
|
||
|
bq24192_write(BQ24192_REG_POWER_ON_CFG, val);
|
||
|
}
|
||
|
|
||
|
static int bq24192_set_terminate_current(int current)
|
||
|
{
|
||
|
int reg_val, rv;
|
||
|
int val = (current - 128) / 128;
|
||
|
|
||
|
rv = bq24192_read(BQ24192_REG_PRE_CHG_CURRENT, ®_val);
|
||
|
if (rv)
|
||
|
return rv;
|
||
|
reg_val = (reg_val & ~0xf) | (val & 0xf);
|
||
|
return bq24192_write(BQ24192_REG_PRE_CHG_CURRENT, reg_val);
|
||
|
}
|
||
|
|
||
|
#ifdef CONFIG_CHARGER_OTG
|
||
|
int charger_enable_otg_power(int enabled)
|
||
|
{
|
||
|
int val, rv;
|
||
|
|
||
|
gpio_set_level(GPIO_BCHGR_OTG, enabled);
|
||
|
rv = bq24192_read(BQ24192_REG_POWER_ON_CFG, &val);
|
||
|
if (rv)
|
||
|
return rv;
|
||
|
val = (val & ~0x30) | (enabled ? 0x20 : 0x10);
|
||
|
return bq24192_write(BQ24192_REG_POWER_ON_CFG, val);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
int charger_set_input_current(int input_current)
|
||
|
{
|
||
|
int i, value, rv;
|
||
|
|
||
|
for (i = 1; i < ARRAY_SIZE(input_current_steps); ++i)
|
||
|
if (input_current_steps[i] > input_current) {
|
||
|
--i;
|
||
|
break;
|
||
|
}
|
||
|
if (i == ARRAY_SIZE(input_current_steps))
|
||
|
--i;
|
||
|
|
||
|
rv = bq24192_read(BQ24192_REG_INPUT_CTRL, &value);
|
||
|
if (rv)
|
||
|
return rv;
|
||
|
value = value & ~(0x7);
|
||
|
value |= (i & 0x7);
|
||
|
return bq24192_write(BQ24192_REG_INPUT_CTRL, value);
|
||
|
}
|
||
|
|
||
|
int charger_get_input_current(int *input_current)
|
||
|
{
|
||
|
int rv, value;
|
||
|
|
||
|
rv = bq24192_read(BQ24192_REG_INPUT_CTRL, &value);
|
||
|
if (rv)
|
||
|
return rv;
|
||
|
*input_current = input_current_steps[value & 0x7];
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int charger_manufacturer_id(int *id)
|
||
|
{
|
||
|
return EC_ERROR_UNIMPLEMENTED;
|
||
|
}
|
||
|
|
||
|
int charger_device_id(int *id)
|
||
|
{
|
||
|
return bq24192_read(BQ24192_REG_ID, id);
|
||
|
}
|
||
|
|
||
|
int charger_get_option(int *option)
|
||
|
{
|
||
|
return EC_ERROR_UNIMPLEMENTED;
|
||
|
}
|
||
|
|
||
|
int charger_set_option(int option)
|
||
|
{
|
||
|
return EC_ERROR_UNIMPLEMENTED;
|
||
|
}
|
||
|
|
||
|
const struct charger_info *charger_get_info(void)
|
||
|
{
|
||
|
return &bq24192_charger_info;
|
||
|
}
|
||
|
|
||
|
int charger_get_status(int *status)
|
||
|
{
|
||
|
return EC_ERROR_UNIMPLEMENTED;
|
||
|
}
|
||
|
|
||
|
int charger_set_mode(int mode)
|
||
|
{
|
||
|
return EC_ERROR_UNIMPLEMENTED;
|
||
|
}
|
||
|
|
||
|
int charger_get_current(int *current)
|
||
|
{
|
||
|
int rv, val;
|
||
|
const struct charger_info * const info = charger_get_info();
|
||
|
|
||
|
rv = bq24192_read(BQ24192_REG_CHG_CURRENT, &val);
|
||
|
if (rv)
|
||
|
return rv;
|
||
|
val = (val >> 2) & 0x3f;
|
||
|
*current = val * info->current_step + info->current_min;
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int charger_set_current(int current)
|
||
|
{
|
||
|
int rv, val;
|
||
|
const struct charger_info * const info = charger_get_info();
|
||
|
|
||
|
current = charger_closest_current(current);
|
||
|
rv = bq24192_read(BQ24192_REG_CHG_CURRENT, &val);
|
||
|
if (rv)
|
||
|
return rv;
|
||
|
val = val & 0x3;
|
||
|
val |= ((current - info->current_min) / info->current_step) << 2;
|
||
|
return bq24192_write(BQ24192_REG_CHG_CURRENT, val);
|
||
|
}
|
||
|
|
||
|
int charger_get_voltage(int *voltage)
|
||
|
{
|
||
|
int rv, val;
|
||
|
const struct charger_info * const info = charger_get_info();
|
||
|
|
||
|
rv = bq24192_read(BQ24192_REG_CHG_VOLTAGE, &val);
|
||
|
if (rv)
|
||
|
return rv;
|
||
|
val = (val >> 2) & 0x3f;
|
||
|
*voltage = val * info->voltage_step + info->voltage_min;
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int charger_set_voltage(int voltage)
|
||
|
{
|
||
|
int rv, val;
|
||
|
const struct charger_info * const info = charger_get_info();
|
||
|
|
||
|
rv = bq24192_read(BQ24192_REG_CHG_VOLTAGE, &val);
|
||
|
if (rv)
|
||
|
return rv;
|
||
|
val = val & 0x3;
|
||
|
val |= ((voltage - info->voltage_min) / info->voltage_step) << 2;
|
||
|
return bq24192_write(BQ24192_REG_CHG_VOLTAGE, val);
|
||
|
}
|
||
|
|
||
|
/* Charging power state initialization */
|
||
|
int charger_post_init(void)
|
||
|
{
|
||
|
/* Input current controlled by extpower module. Do nothing here. */
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
/* Hooks */
|
||
|
|
||
|
static void bq24192_init(void)
|
||
|
{
|
||
|
int val;
|
||
|
|
||
|
if (charger_device_id(&val) || val != BQ24192_DEVICE_ID) {
|
||
|
CPRINTF("BQ24192 incorrent ID: 0x%02x\n", val);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Disable I2C watchdog timer.
|
||
|
*
|
||
|
* TODO(crosbug.com/p/22238): Re-enable watchdog timer and kick it
|
||
|
* periodically in charger task.
|
||
|
*/
|
||
|
if (bq24192_read(BQ24192_REG_CHG_TERM_TMR, &val))
|
||
|
return;
|
||
|
|
||
|
val &= ~0x30;
|
||
|
|
||
|
if (bq24192_write(BQ24192_REG_CHG_TERM_TMR, val))
|
||
|
return;
|
||
|
|
||
|
if (bq24192_set_terminate_current(128))
|
||
|
return;
|
||
|
|
||
|
if (bq24192_watchdog_reset())
|
||
|
return;
|
||
|
|
||
|
CPRINTF("BQ24192 initialized\n");
|
||
|
}
|
||
|
DECLARE_HOOK(HOOK_INIT, bq24192_init, HOOK_PRIO_LAST);
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
/* Console commands */
|
||
|
#ifdef CONFIG_CMD_CHARGER
|
||
|
static int command_bq24192(int argc, char **argv)
|
||
|
{
|
||
|
int i;
|
||
|
int value;
|
||
|
int rv;
|
||
|
|
||
|
ccprintf("REG:");
|
||
|
for (i = 0; i <= 0xa; ++i)
|
||
|
ccprintf(" %02x", i);
|
||
|
ccprintf("\n");
|
||
|
|
||
|
ccprintf("VAL:");
|
||
|
for (i = 0; i <= 0xa; ++i) {
|
||
|
rv = bq24192_read(i, &value);
|
||
|
if (rv)
|
||
|
return rv;
|
||
|
ccprintf(" %02x", value);
|
||
|
}
|
||
|
ccprintf("\n");
|
||
|
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
DECLARE_CONSOLE_COMMAND(bq24192, command_bq24192,
|
||
|
NULL, NULL);
|
||
|
#endif
|