diff --git a/board/kirby/board.h b/board/kirby/board.h index 26e031b7b2..d246622504 100644 --- a/board/kirby/board.h +++ b/board/kirby/board.h @@ -9,6 +9,8 @@ #define __BOARD_H /* Optional features */ +#define CONFIG_CHARGER +#define CONFIG_CHARGER_BQ24192 #define CONFIG_CHIPSET_GAIA #define CONFIG_HOST_COMMAND_STATUS #define CONFIG_I2C diff --git a/common/build.mk b/common/build.mk index a1660ad119..429f27b744 100644 --- a/common/build.mk +++ b/common/build.mk @@ -24,6 +24,7 @@ common-$(CONFIG_BATTERY_BQ20Z453)+=battery_bq20z453.o common-$(CONFIG_BATTERY_MOCK)+=mock_smart_battery_stub.o mock_charger.o common-$(CONFIG_BATTERY_SMART)+=smart_battery.o smart_battery_stub.o common-$(CONFIG_CHARGER)+=charge_state.o charger_common.o +common-$(CONFIG_CHARGER_BQ24192)+=charger_bq24192.o common-$(CONFIG_CHARGER_BQ24715)+=charger_bq24715.o common-$(CONFIG_CHARGER_BQ24725)+=charger_bq24725.o common-$(CONFIG_CHARGER_BQ24707A)+=charger_bq24707a.o diff --git a/common/charger_bq24192.c b/common/charger_bq24192.c new file mode 100644 index 0000000000..8939cc9e71 --- /dev/null +++ b/common/charger_bq24192.c @@ -0,0 +1,243 @@ +/* Copyright (c) 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 "charger.h" +#include "charger_bq24192.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 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}; + +int bq24192_read(int reg, int *value) +{ + return i2c_read8(I2C_PORT_HOST, BQ24192_ADDR, reg, value); +} + +int bq24192_write(int reg, int value) +{ + return i2c_write8(I2C_PORT_HOST, 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 |= (1 << 6); + return bq24192_write(BQ24192_REG_POWER_ON_CFG, val) || + bq24192_write(BQ24192_REG_POWER_ON_CFG, val); +} + +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; + return input_current_steps[value & 0x7]; +} + +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; +} + +/* TODO(victoryang): remove this after enabling charger task on Kirby */ +int charger_closest_current(int current) +{ + return current; +} + +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); +} + + +/*****************************************************************************/ +/* Hooks */ + +static void bq24192_init(void) +{ + int val, rv; + + if (charger_device_id(&val) || val != BQ24192_DEVICE_ID) { + CPRINTF("[%T BQ24192 incorrent ID: 0x%02x]\n", val); + return; + } + + /* + * Disable I2C watchdog timer. + * TODO(victoryang): Re-enable watchdog timer and kick it periodically + * in charger task. + */ + rv = bq24192_read(BQ24192_REG_CHG_TERM_TMR, &val); + if (rv) + return; + val &= ~0x30; + rv = bq24192_write(BQ24192_REG_CHG_TERM_TMR, val); + if (rv) + return; + + if (bq24192_watchdog_reset()) + return; + + CPRINTF("[%T BQ24192 initialized]\n"); +} +DECLARE_HOOK(HOOK_INIT, bq24192_init, HOOK_PRIO_LAST); + +/*****************************************************************************/ +/* Console commands */ + +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, NULL); diff --git a/common/charger_bq24707a.c b/common/charger_bq24707a.c index 9538318997..e6afa629da 100644 --- a/common/charger_bq24707a.c +++ b/common/charger_bq24707a.c @@ -135,25 +135,6 @@ int charger_get_current(int *current) return EC_SUCCESS; } -int charger_closest_current(int current) -{ - const struct charger_info * const info = charger_get_info(); - - /* - * If the requested current is non-zero but below our minimum, - * return the minimum. See crosbug.com/p/8662. - */ - if (current > 0 && current < info->current_min) - return info->current_min; - - /* Clip to max */ - if (current > info->current_max) - return info->current_max; - - /* Otherwise round down to nearest current step */ - return current - (current % info->current_step); -} - int charger_set_current(int current) { current = charger_closest_current(current); diff --git a/common/charger_bq24715.c b/common/charger_bq24715.c index 66d178a4c3..56e8b6ee34 100644 --- a/common/charger_bq24715.c +++ b/common/charger_bq24715.c @@ -129,25 +129,6 @@ int charger_get_current(int *current) return EC_SUCCESS; } -int charger_closest_current(int current) -{ - const struct charger_info * const info = charger_get_info(); - - /* - * If the requested current is non-zero but below our minimum, - * return the minimum. See crosbug.com/p/8662. - */ - if (current > 0 && current < info->current_min) - return info->current_min; - - /* Clip to max */ - if (current > info->current_max) - return info->current_max; - - /* Otherwise round down to nearest current step */ - return current - (current % info->current_step); -} - int charger_set_current(int current) { current = charger_closest_current(current); diff --git a/common/charger_bq24725.c b/common/charger_bq24725.c index d69b3edf13..64eb81400b 100644 --- a/common/charger_bq24725.c +++ b/common/charger_bq24725.c @@ -134,25 +134,6 @@ int charger_get_current(int *current) return EC_SUCCESS; } -int charger_closest_current(int current) -{ - const struct charger_info * const info = charger_get_info(); - - /* - * If the requested current is non-zero but below our minimum, - * return the minimum. See crosbug.com/p/8662. - */ - if (current > 0 && current < info->current_min) - return info->current_min; - - /* Clip to max */ - if (current > info->current_max) - return info->current_max; - - /* Otherwise round down to nearest current step */ - return current - (current % info->current_step); -} - int charger_set_current(int current) { current = charger_closest_current(current); diff --git a/common/charger_bq24738.c b/common/charger_bq24738.c index eaea6495d9..cb5047b5b5 100644 --- a/common/charger_bq24738.c +++ b/common/charger_bq24738.c @@ -134,25 +134,6 @@ int charger_get_current(int *current) return EC_SUCCESS; } -int charger_closest_current(int current) -{ - const struct charger_info * const info = charger_get_info(); - - /* - * If the requested current is non-zero but below our minimum, - * return the minimum. See crosbug.com/p/8662. - */ - if (current > 0 && current < info->current_min) - return info->current_min; - - /* Clip to max */ - if (current > info->current_max) - return info->current_max; - - /* Otherwise round down to nearest current step */ - return current - (current % info->current_step); -} - int charger_set_current(int current) { current = charger_closest_current(current); diff --git a/common/charger_common.c b/common/charger_common.c index bb301c48a5..0c86a73156 100644 --- a/common/charger_common.c +++ b/common/charger_common.c @@ -25,6 +25,25 @@ int charger_closest_voltage(int voltage) return voltage - (voltage % info->voltage_step); } +int charger_closest_current(int current) +{ + const struct charger_info * const info = charger_get_info(); + + /* + * If the requested current is non-zero but below our minimum, + * return the minimum. See crosbug.com/p/8662. + */ + if (current > 0 && current < info->current_min) + return info->current_min; + + /* Clip to max */ + if (current > info->current_max) + return info->current_max; + + /* Otherwise round down to nearest current step */ + return current - (current % info->current_step); +} + static int print_info(void) { int rv; diff --git a/common/mock_charger.c b/common/mock_charger.c index 47b2a96079..ebbf5e87bb 100644 --- a/common/mock_charger.c +++ b/common/mock_charger.c @@ -129,12 +129,6 @@ int charger_set_input_current(int input_current) } -int charger_closest_current(int current) -{ - return current; -} - - int charger_post_init(void) { mock_current = CONFIG_CHARGER_INPUT_CURRENT; diff --git a/include/charger_bq24192.h b/include/charger_bq24192.h new file mode 100644 index 0000000000..4177dc5c2c --- /dev/null +++ b/include/charger_bq24192.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2013 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. + */ + +#ifndef __CROS_EC_CHARGER_BQ24192_H +#define __CROS_EC_CHARGER_BQ24192_H + +#define BQ24192_ADDR 0xd6 + +/* Registers */ +#define BQ24192_REG_INPUT_CTRL 0x0 +#define BQ24192_REG_POWER_ON_CFG 0x1 +#define BQ24192_REG_CHG_CURRENT 0x2 +#define BQ24192_REG_PRE_CHG_CURRENT 0x3 +#define BQ24192_REG_CHG_VOLTAGE 0x4 +#define BQ24192_REG_CHG_TERM_TMR 0x5 +#define BQ24192_REG_IR_COMP 0x6 +#define BQ24192_REG_MISC_OP 0x7 +#define BQ24192_REG_STATUS 0x8 +#define BQ24192_REG_FAULT 0x9 +#define BQ24192_REG_ID 0xa + +#define BQ24192_DEVICE_ID 0x2b + +#endif /* __CROS_EC_CHARGER_BQ24192_H */