diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2015-03-30 14:43:46 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-04-02 19:01:27 +0000 |
commit | de24d511621fcc98b36152a7c373eeaa566fea74 (patch) | |
tree | bebd27e2bc3290b972598d56415d4a2abaa77f13 /driver | |
parent | 6cb426e137ebf15dd1f428c657e26bd3d367b7ac (diff) | |
download | chrome-ec-de24d511621fcc98b36152a7c373eeaa566fea74.tar.gz |
charger: add TI BQ2589x charger driver
Driver for Texas Instrument bq25890/bq25892/bq25895 battery charger
chip.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BRANCH=none
BUG=chrome-os-partner:38603
TEST=On a modified board with BQ25892, charge a 1S battery and check ADC
values.
Change-Id: I536c6b58438464a63ad3d3536b9bb84ff35920e8
Reviewed-on: https://chromium-review.googlesource.com/263458
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r-- | driver/build.mk | 3 | ||||
-rw-r--r-- | driver/charger/bq2589x.c | 306 | ||||
-rw-r--r-- | driver/charger/bq2589x.h | 53 |
3 files changed, 362 insertions, 0 deletions
diff --git a/driver/build.mk b/driver/build.mk index 0ad76ed902..545b4cc934 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -31,6 +31,9 @@ driver-$(CONFIG_CHARGER_BQ24735)+=charger/bq24735.o driver-$(CONFIG_CHARGER_BQ24738)+=charger/bq24738.o driver-$(CONFIG_CHARGER_BQ24770)+=charger/bq24773.o driver-$(CONFIG_CHARGER_BQ24773)+=charger/bq24773.o +driver-$(CONFIG_CHARGER_BQ25890)+=charger/bq2589x.o +driver-$(CONFIG_CHARGER_BQ25892)+=charger/bq2589x.o +driver-$(CONFIG_CHARGER_BQ25895)+=charger/bq2589x.o # I/O expander driver-$(CONFIG_IO_EXPANDER_PCA9534)+=ioexpander_pca9534.o diff --git a/driver/charger/bq2589x.c b/driver/charger/bq2589x.c new file mode 100644 index 0000000000..3e9e4bfd36 --- /dev/null +++ b/driver/charger/bq2589x.c @@ -0,0 +1,306 @@ +/* Copyright 2015 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 bq25890/bq25892/bq25895 battery charger driver. + */ + +#include "config.h" +#include "bq2589x.h" +#include "charger.h" +#include "common.h" +#include "console.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 bq2589x_charger_info = { + .name = "bq2589x", + .voltage_max = 4608, + .voltage_min = 3840, + .voltage_step = 16, + .current_max = 5056, + .current_min = 0, + .current_step = 64, + .input_current_max = 3250, + .input_current_min = 100, + .input_current_step = 50, +}; + +static int bq2589x_read(int reg, int *value) +{ + return i2c_read8(I2C_PORT_CHARGER, BQ2589X_ADDR, reg, value); +} + +static int bq2589x_write(int reg, int value) +{ + return i2c_write8(I2C_PORT_CHARGER, BQ2589X_ADDR, reg, value); +} + +static int bq2589x_watchdog_reset(void) +{ + int rv, val; + + rv = bq2589x_read(BQ2589X_REG_CFG2, &val); + if (rv) + return rv; + val |= (1 << 6); + return bq2589x_write(BQ2589X_REG_CFG2, val); +} + +static int bq2589x_set_terminate_current(int current) +{ + int reg_val, rv; + int val = (current - 64) / 64; + + rv = bq2589x_read(BQ2589X_REG_PRE_CHG_CURR, ®_val); + if (rv) + return rv; + reg_val = (reg_val & ~0xf) | (val & 0xf); + return bq2589x_write(BQ2589X_REG_PRE_CHG_CURR, reg_val); +} + +int charger_enable_otg_power(int enabled) +{ + int val, rv; + + rv = bq2589x_read(BQ2589X_REG_CFG2, &val); + if (rv) + return rv; + val = (val & ~0x30) | (enabled ? 0x20 : 0x10); + return bq2589x_write(BQ2589X_REG_CFG2, val); +} + +int charger_set_input_current(int input_current) +{ + int value, rv; + const struct charger_info * const info = charger_get_info(); + + input_current -= info->input_current_min; + if (input_current < 0) + input_current = 0; + + rv = bq2589x_read(BQ2589X_REG_INPUT_CURR, &value); + if (rv) + return rv; + value = value & ~(0x3f); + value |= (input_current / info->input_current_step) & 0x3f; + return bq2589x_write(BQ2589X_REG_INPUT_CURR, value); +} + +int charger_get_input_current(int *input_current) +{ + int rv, value; + const struct charger_info * const info = charger_get_info(); + + rv = bq2589x_read(BQ2589X_REG_INPUT_CURR, &value); + if (rv) + return rv; + + *input_current = (value & 0x3f) * info->input_current_step + + info->input_current_min; + + return EC_SUCCESS; +} + +int charger_manufacturer_id(int *id) +{ + return EC_ERROR_UNIMPLEMENTED; +} + +int charger_device_id(int *id) +{ + int res = bq2589x_read(BQ2589X_REG_ID, id); + + if (res == EC_SUCCESS) + *id &= BQ2589X_DEVICE_ID_MASK; + + return res; +} + +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 &bq2589x_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 = bq2589x_read(BQ2589X_REG_CHG_CURR, &val); + if (rv) + return rv; + *current = val * info->current_step + info->current_min; + return EC_SUCCESS; +} + +int charger_set_current(int current) +{ + const struct charger_info * const info = charger_get_info(); + + current = charger_closest_current(current); + + return bq2589x_write(BQ2589X_REG_CHG_CURR, + current / info->current_step); +} + +int charger_get_voltage(int *voltage) +{ + int rv, val; + const struct charger_info * const info = charger_get_info(); + + rv = bq2589x_read(BQ2589X_REG_CHG_VOLT, &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(); + + voltage = charger_closest_current(voltage); + + rv = bq2589x_read(BQ2589X_REG_CHG_VOLT, &val); + if (rv) + return rv; + val = val & 0x3; + val |= ((voltage - info->voltage_min) / info->voltage_step) << 2; + return bq2589x_write(BQ2589X_REG_CHG_VOLT, val); +} + +int charger_discharge_on_ac(int enable) +{ + return EC_SUCCESS; +} + +/* Charging power state initialization */ +int charger_post_init(void) +{ +#ifdef CONFIG_CHARGER_ILIM_PIN_DISABLED + int val, rv; + rv = bq2589x_read(BQ2589X_REG_INPUT_CURR, &val); + if (rv) + return rv; + val &= ~0x40; + rv = bq2589x_write(BQ2589X_REG_INPUT_CURR, val); + if (rv) + return rv; +#endif /* CONFIG_CHARGER_ILIM_PIN_DISABLED */ + + /* Input current controlled by extpower module. Do nothing here. */ + return EC_SUCCESS; +} + + +/*****************************************************************************/ +/* Hooks */ + +static void bq2589x_init(void) +{ + int val; + + if (charger_device_id(&val) || val != BQ2589X_DEVICE_ID) { + CPRINTF("BQ2589X incorrent ID: 0x%02x\n", val); + return; + } + + /* + * Disable I2C watchdog timer. + * + * TODO(crosbug.com/p/38603): Re-enable watchdog timer and kick it + * periodically in charger task. + */ + if (bq2589x_read(BQ2589X_REG_TIMER, &val)) + return; + val &= ~0x30; + if (bq2589x_write(BQ2589X_REG_TIMER, val)) + return; + + if (bq2589x_set_terminate_current(64)) + return; + + if (bq2589x_watchdog_reset()) + return; + + CPRINTF("BQ2589%c initialized\n", + BQ2589X_DEVICE_ID == BQ25890_DEVICE_ID ? '0' : + (BQ2589X_DEVICE_ID == BQ25895_DEVICE_ID ? '5' : '2')); +} +DECLARE_HOOK(HOOK_INIT, bq2589x_init, HOOK_PRIO_LAST); + +/*****************************************************************************/ +/* Console commands */ + +static int command_bq2589x(int argc, char **argv) +{ + int i; + int value; + int rv; + int batt_mv, sys_mv, vbus_mv, chg_ma, input_ma; + + /* Trigger one ADC conversion */ + bq2589x_read(BQ2589X_REG_CFG1, &value); + bq2589x_write(BQ2589X_REG_CFG1, value | 0x80); + do { + bq2589x_read(BQ2589X_REG_CFG1, &value); + } while (value & 0x80); /* Wait for End of Conversion */ + + bq2589x_read(BQ2589X_REG_ADC_BATT_VOLT, &batt_mv); + bq2589x_read(BQ2589X_REG_ADC_SYS_VOLT, &sys_mv); + bq2589x_read(BQ2589X_REG_ADC_VBUS_VOLT, &vbus_mv); + bq2589x_read(BQ2589X_REG_ADC_CHG_CURR, &chg_ma); + bq2589x_read(BQ2589X_REG_ADC_INPUT_CURR, &input_ma); + ccprintf("ADC Batt %dmV Sys %dmV VBUS %dmV Chg %dmA Input %dmA\n", + 2304 + (batt_mv & 0x7f) * 20, 2304 + sys_mv * 20, + 2600 + (vbus_mv & 0x7f) * 100, + chg_ma * 50, 100 + (input_ma & 0x3f) * 50); + + ccprintf("REG:"); + for (i = 0; i <= 0x14; ++i) + ccprintf(" %02x", i); + ccprintf("\n"); + + ccprintf("VAL:"); + for (i = 0; i <= 0x14; ++i) { + rv = bq2589x_read(i, &value); + if (rv) + return rv; + ccprintf(" %02x", value); + } + ccprintf("\n"); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(bq2589x, command_bq2589x, + NULL, NULL, NULL); diff --git a/driver/charger/bq2589x.h b/driver/charger/bq2589x.h new file mode 100644 index 0000000000..cd74404b79 --- /dev/null +++ b/driver/charger/bq2589x.h @@ -0,0 +1,53 @@ +/* Copyright 2015 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 bq25890/bq25892/bq25895 battery charger driver. + */ + +#ifndef __CROS_EC_CHARGER_BQ2589X_H +#define __CROS_EC_CHARGER_BQ2589X_H + +/* Registers */ +#define BQ2589X_REG_INPUT_CURR 0x00 +#define BQ2589X_REG_VINDPM 0x01 +#define BQ2589X_REG_CFG1 0x02 +#define BQ2589X_REG_CFG2 0x03 +#define BQ2589X_REG_CHG_CURR 0x04 +#define BQ2589X_REG_PRE_CHG_CURR 0x05 +#define BQ2589X_REG_CHG_VOLT 0x06 +#define BQ2589X_REG_TIMER 0x07 +#define BQ2589X_REG_IR_COMP 0x08 +#define BQ2589X_REG_FORCE 0x09 +#define BQ2589X_REG_BOOST_MODE 0x0A +#define BQ2589X_REG_STATUS 0x0B /* Read-only */ +#define BQ2589X_REG_FAULT 0x0C /* Read-only */ +#define BQ2589X_REG_VINDPM_THRESH 0x0D +#define BQ2589X_REG_ADC_BATT_VOLT 0x0E /* Read-only */ +#define BQ2589X_REG_ADC_SYS_VOLT 0x0F /* Read-only */ +#define BQ2589X_REG_ADC_TS 0x10 /* Read-only */ +#define BQ2589X_REG_ADC_VBUS_VOLT 0x11 /* Read-only */ +#define BQ2589X_REG_ADC_CHG_CURR 0x12 /* Read-only */ +#define BQ2589X_REG_ADC_INPUT_CURR 0x13 /* Read-only */ +#define BQ2589X_REG_ID 0x14 + +#define BQ2589X_DEVICE_ID_MASK 0x38 +#define BQ25890_DEVICE_ID 0x18 +#define BQ25892_DEVICE_ID 0x00 +#define BQ25895_DEVICE_ID 0x38 + +/* Variant-specific configuration */ +#if defined(CONFIG_CHARGER_BQ25890) +#define BQ2589X_DEVICE_ID BQ25890_DEVICE_ID +#define BQ2589X_ADDR (0x6A << 1) +#elif defined(CONFIG_CHARGER_BQ25895) +#define BQ2589X_DEVICE_ID BQ25895_DEVICE_ID +#define BQ2589X_ADDR (0x6A << 1) +#elif defined(CONFIG_CHARGER_BQ25892) +#define BQ2589X_DEVICE_ID BQ25892_DEVICE_ID +#define BQ2589X_ADDR (0x6B << 1) +#else +#error BQ2589X unknown variant +#endif + +#endif /* __CROS_EC_CHARGER_BQ2589X_H */ |