summaryrefslogtreecommitdiff
path: root/common/charger.c
diff options
context:
space:
mode:
authorDiana Z <dzigterman@chromium.org>2020-01-14 14:18:08 -0700
committerCommit Bot <commit-bot@chromium.org>2020-01-28 20:22:22 +0000
commit4eb3a5fe699247a5767ae38c66c75872f4afc575 (patch)
tree81787f2f54ff3470ce326047213abfae234b50a1 /common/charger.c
parentd9a869beb6e1778cec38dcce64f289aba353a8d5 (diff)
downloadchrome-ec-4eb3a5fe699247a5767ae38c66c75872f4afc575.tar.gz
Charger: Create charger driver structure
With upcoming boards which use multiple charger chips, the EC codebase needs to be changed to assume chargers may have different I2C ports. This commit creates the driver structure and wrapper functions, which for now are hard-coded to chip 0 for equivalent behavior with previous code. A general charger config is created for all boards in charger.c for now, which uses the build information to fill in the structure. All boards will default to defining CONFIG_CHARGER_SINGLE_CHIP, which in turn defines a CHARGER_SOLO which can be used by drivers which have code that needs to determine charger numbers. For boards which have multiple chips, they may undefine this config and should generate build errors if their driver is still using the hardcoded charger reference of CHARGER_SOLO. Older drivers may continue using CHARGER_SOLO in non-static functions until they're needed in a multiple charger board. For boards which may be supporting different I2C configurations for the charger over board versions, they may define CONFIG_CHARGER_RUNTIME_CONFIG to fill in these fields after boot. BRANCH=none BUG=b:147672225 TEST=builds, chargers on hatch and octopus work Change-Id: I390ede494226252e512595c48099fa1288ffe93e Signed-off-by: Diana Z <dzigterman@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2008451 Reviewed-by: Jett Rink <jettrink@chromium.org>
Diffstat (limited to 'common/charger.c')
-rw-r--r--common/charger.c443
1 files changed, 434 insertions, 9 deletions
diff --git a/common/charger.c b/common/charger.c
index 7ee80a9c23..e2f6112ed7 100644
--- a/common/charger.c
+++ b/common/charger.c
@@ -143,23 +143,20 @@ void print_charger_debug(void)
/* charge voltage limit */
print_item_name("V_batt:");
if (check_print_error(charger_get_voltage(&d)))
- ccprintf("%5d (%4d - %5d, %3d)\n", d,
- info->voltage_min, info->voltage_max,
- info->voltage_step);
+ ccprintf("%5d (%4d - %5d, %3d)\n", d, info->voltage_min,
+ info->voltage_max, info->voltage_step);
/* charge current limit */
print_item_name("I_batt:");
if (check_print_error(charger_get_current(&d)))
- ccprintf("%5d (%4d - %5d, %3d)\n", d,
- info->current_min, info->current_max,
- info->current_step);
+ ccprintf("%5d (%4d - %5d, %3d)\n", d, info->current_min,
+ info->current_max, info->current_step);
/* input current limit */
print_item_name("I_in:");
if (check_print_error(charger_get_input_current(&d)))
- ccprintf("%5d (%4d - %5d, %3d)\n", d,
- info->input_current_min, info->input_current_max,
- info->input_current_step);
+ ccprintf("%5d (%4d - %5d, %3d)\n", d, info->input_current_min,
+ info->input_current_max, info->input_current_step);
/* dptf current limit */
print_item_name("I_dptf:");
@@ -209,3 +206,431 @@ static int command_charger(int argc, char **argv)
DECLARE_CONSOLE_COMMAND(charger, command_charger,
"[input | current | voltage | dptf] [newval]",
"Get or set charger param(s)");
+
+/* Driver wrapper functions */
+
+/*
+ * TODO(b/147672225): boards should define their own charger structures
+ * Drivers cannot be included together, as they define some of the same items.
+ * This will need to be addressed if we want to support different types of
+ * charger chips on a board
+ */
+#if defined(CONFIG_CHARGER_BD9995X)
+#include "driver/charger/bd9995x.h"
+#elif defined(CONFIG_CHARGER_BQ24715)
+#include "driver/charger/bq24715.h"
+#elif defined(CONFIG_CHARGER_BQ24770) || defined(CONFIG_CHARGER_BQ24773)
+#include "driver/charger/bq24773.h"
+#elif defined(CONFIG_CHARGER_BQ25710)
+#include "driver/charger/bq25710.h"
+#elif defined(CONFIG_CHARGER_ISL9237) || defined(CONFIG_CHARGER_ISL9238)
+#include "driver/charger/isl923x.h"
+#elif defined(CONFIG_CHARGER_ISL9241)
+#include "driver/charger/isl9241.h"
+#elif defined(CONFIG_CHARGER_MT6370) || defined(CONFIG_CHARGER_RT9466) \
+ || defined(CONFIG_CHARGER_RT9467)
+#include "driver/charger/rt946x.h"
+#endif
+
+#if !defined(CONFIG_CHARGER_RUNTIME_CONFIG) && !defined(TEST_BUILD)
+const struct charger_config_t chg_chips[] = {
+ {
+ .i2c_port = I2C_PORT_CHARGER,
+#if defined(CONFIG_CHARGER_BD9995X)
+ .i2c_addr_flags = BD9995X_ADDR_FLAGS,
+ .drv = &bd9995x_drv,
+#elif defined(CONFIG_CHARGER_BQ24715)
+ .i2c_addr_flags = CHARGER_ADDR_FLAGS,
+ .drv = &bq24715_drv,
+#elif defined(CONFIG_CHARGER_BQ24770) || defined(CONFIG_CHARGER_BQ24773)
+ .i2c_addr_flags = I2C_ADDR_CHARGER_FLAGS,
+ .drv = &bq2477x_drv,
+#elif defined(CONFIG_CHARGER_BQ25710)
+ .i2c_addr_flags = BQ25710_SMBUS_ADDR1_FLAGS,
+ .drv = &bq25710_drv,
+#elif defined(CONFIG_CHARGER_ISL9237) || defined(CONFIG_CHARGER_ISL9238)
+ .i2c_addr_flags = ISL923X_ADDR_FLAGS,
+ .drv = &isl923x_drv,
+#elif defined(CONFIG_CHARGER_ISL9241)
+ .i2c_addr_flags = ISL9241_ADDR_FLAGS,
+ .drv = &isl9241_drv,
+#elif defined(CONFIG_CHARGER_MT6370) || defined(CONFIG_CHARGER_RT9466) \
+ || defined(CONFIG_CHARGER_RT9467)
+ .i2c_addr_flags = RT946X_ADDR_FLAGS,
+ .drv = &rt946x_drv,
+#endif
+ },
+};
+
+const unsigned int chg_cnt = ARRAY_SIZE(chg_chips);
+#endif /* CONFIG_CHARGER_RUNTIME_CONFIG */
+
+
+static void charger_chips_init(void)
+{
+ int chip;
+
+ for (chip = 0; chip < chg_cnt; chip++) {
+ if (chg_chips[chip].drv->init)
+ chg_chips[chip].drv->init(chip);
+ }
+}
+DECLARE_HOOK(HOOK_INIT, charger_chips_init, HOOK_PRIO_INIT_I2C + 1);
+
+enum ec_error_list charger_post_init(void)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->post_init)
+ rv = chg_chips[chgnum].drv->post_init(chgnum);
+
+ return rv;
+}
+
+const struct charger_info *charger_get_info(void)
+{
+ int chgnum = 0;
+ const struct charger_info *ret = NULL;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return NULL;
+ }
+
+ if (chg_chips[chgnum].drv->get_info)
+ ret = chg_chips[chgnum].drv->get_info(chgnum);
+
+ return ret;
+}
+
+enum ec_error_list charger_get_status(int *status)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->get_status)
+ rv = chg_chips[chgnum].drv->get_status(chgnum, status);
+
+ return rv;
+}
+
+enum ec_error_list charger_set_mode(int mode)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->set_mode)
+ rv = chg_chips[chgnum].drv->set_mode(chgnum, mode);
+
+ return rv;
+}
+
+enum ec_error_list charger_enable_otg_power(int enabled)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->enable_otg_power)
+ rv = chg_chips[chgnum].drv->enable_otg_power(chgnum, enabled);
+
+ return rv;
+}
+
+enum ec_error_list charger_set_otg_current_voltage(int output_current,
+ int output_voltage)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->set_otg_current_voltage)
+ rv = chg_chips[chgnum].drv->set_otg_current_voltage(chgnum,
+ output_current, output_voltage);
+
+ return rv;
+}
+
+enum ec_error_list charger_get_current(int *current)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->get_current)
+ rv = chg_chips[chgnum].drv->get_current(chgnum, current);
+
+ return rv;
+}
+
+enum ec_error_list charger_set_current(int current)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->set_current)
+ rv = chg_chips[chgnum].drv->set_current(chgnum, current);
+
+ return rv;
+}
+
+enum ec_error_list charger_get_voltage(int *voltage)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->get_voltage)
+ rv = chg_chips[chgnum].drv->get_voltage(chgnum, voltage);
+
+ return rv;
+}
+
+enum ec_error_list charger_set_voltage(int voltage)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->set_voltage)
+ rv = chg_chips[chgnum].drv->set_voltage(chgnum, voltage);
+
+ return rv;
+}
+
+enum ec_error_list charger_discharge_on_ac(int enable)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->discharge_on_ac)
+ rv = chg_chips[chgnum].drv->discharge_on_ac(chgnum, enable);
+
+ return rv;
+}
+
+int charger_get_vbus_voltage(int port)
+{
+ int chgnum = 0;
+ int rv = 0;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return 0;
+ }
+
+ if (chg_chips[chgnum].drv->get_vbus_voltage)
+ rv = chg_chips[chgnum].drv->get_vbus_voltage(chgnum, port);
+
+ return rv;
+}
+
+enum ec_error_list charger_set_input_current(int input_current)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->set_input_current)
+ rv = chg_chips[chgnum].drv->set_input_current(chgnum,
+ input_current);
+
+ return rv;
+}
+
+enum ec_error_list charger_get_input_current(int *input_current)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->get_input_current)
+ rv = chg_chips[chgnum].drv->get_input_current(chgnum,
+ input_current);
+
+ return rv;
+}
+
+enum ec_error_list charger_manufacturer_id(int *id)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->manufacturer_id)
+ rv = chg_chips[chgnum].drv->manufacturer_id(chgnum, id);
+
+ return rv;
+}
+
+enum ec_error_list charger_device_id(int *id)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->device_id)
+ rv = chg_chips[chgnum].drv->device_id(chgnum, id);
+
+ return rv;
+}
+
+enum ec_error_list charger_get_option(int *option)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->get_option)
+ rv = chg_chips[chgnum].drv->get_option(chgnum, option);
+
+ return rv;
+}
+
+enum ec_error_list charger_set_option(int option)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->set_option)
+ rv = chg_chips[chgnum].drv->set_option(chgnum, option);
+
+ return rv;
+}
+
+enum ec_error_list charger_set_hw_ramp(int enable)
+{
+ int chgnum = 0;
+ int rv = EC_ERROR_UNIMPLEMENTED;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return EC_ERROR_INVAL;
+ }
+
+ if (chg_chips[chgnum].drv->set_hw_ramp)
+ rv = chg_chips[chgnum].drv->set_hw_ramp(chgnum, enable);
+
+ return rv;
+}
+
+#ifdef CONFIG_CHARGE_RAMP_HW
+int chg_ramp_is_stable(void)
+{
+ int chgnum = 0;
+ int rv = 0;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return 0;
+ }
+
+ if (chg_chips[chgnum].drv->ramp_is_stable)
+ rv = chg_chips[chgnum].drv->ramp_is_stable(chgnum);
+
+ return rv;
+}
+
+int chg_ramp_is_detected(void)
+{
+ int chgnum = 0;
+ int rv = 0;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return 0;
+ }
+
+ if (chg_chips[chgnum].drv->ramp_is_detected)
+ rv = chg_chips[chgnum].drv->ramp_is_detected(chgnum);
+
+ return rv;
+}
+
+int chg_ramp_get_current_limit(void)
+{
+ int chgnum = 0;
+ int rv = 0;
+
+ if ((chgnum < 0) || (chgnum >= chg_cnt)) {
+ CPRINTS("%s(%d) Invalid charger!", __func__, chgnum);
+ return 0;
+ }
+
+ if (chg_chips[chgnum].drv->ramp_get_current_limit)
+ rv = chg_chips[chgnum].drv->ramp_get_current_limit(chgnum);
+
+ return rv;
+}
+#endif