summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2015-03-30 14:43:46 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-04-02 19:01:27 +0000
commitde24d511621fcc98b36152a7c373eeaa566fea74 (patch)
treebebd27e2bc3290b972598d56415d4a2abaa77f13
parent6cb426e137ebf15dd1f428c657e26bd3d367b7ac (diff)
downloadchrome-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>
-rw-r--r--driver/build.mk3
-rw-r--r--driver/charger/bq2589x.c306
-rw-r--r--driver/charger/bq2589x.h53
-rw-r--r--include/config.h3
4 files changed, 365 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, &reg_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 */
diff --git a/include/config.h b/include/config.h
index ad1dba54df..bc8807d436 100644
--- a/include/config.h
+++ b/include/config.h
@@ -240,6 +240,9 @@
#undef CONFIG_CHARGER_BQ24738
#undef CONFIG_CHARGER_BQ24770
#undef CONFIG_CHARGER_BQ24773
+#undef CONFIG_CHARGER_BQ25890
+#undef CONFIG_CHARGER_BQ25892
+#undef CONFIG_CHARGER_BQ25895
#undef CONFIG_CHARGER_TPS65090 /* Note: does not use CONFIG_CHARGER */
/*