diff options
author | Vijay Hiremath <vijay.p.hiremath@intel.com> | 2019-04-12 18:09:33 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-04-26 00:17:34 -0700 |
commit | 663e0baf89e661020ad640d2691177c95abae815 (patch) | |
tree | c2c89ba5ea142eec34f0923feddc718b04161e68 | |
parent | 2362b119299e2122832656aa0a1affda74654ce6 (diff) | |
download | chrome-ec-663e0baf89e661020ad640d2691177c95abae815.tar.gz |
charger: Add basic driver code for ISL9241
The ISL9241 is a digitally configurable buck-boost battery charger
that can support both Narrow Voltage Direct Charging (NVDC) and
Hybrid Power Buck Boost (HPBB/Bypass) charging and switch between
the modes using firmware control.
BUG=b:131123775
BRANCH=none
TEST=Able to boot intelrvp with charger & battery is charging
Change-Id: If0736136778cbe7650ed7f03d04f4e011eedd1f6
Signed-off-by: Vijay Hiremath <vijay.p.hiremath@intel.com>
Reviewed-on: https://chromium-review.googlesource.com/1579241
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Vijay P Hiremath <vijay.p.hiremath@intel.com>
Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r-- | driver/build.mk | 1 | ||||
-rw-r--r-- | driver/charger/isl9241.c | 362 | ||||
-rw-r--r-- | driver/charger/isl9241.h | 105 | ||||
-rw-r--r-- | include/config.h | 4 |
4 files changed, 471 insertions, 1 deletions
diff --git a/driver/build.mk b/driver/build.mk index 40ff37fc13..616bff8ef7 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -64,6 +64,7 @@ driver-$(CONFIG_CHARGER_BQ25892)+=charger/bq2589x.o driver-$(CONFIG_CHARGER_BQ25895)+=charger/bq2589x.o driver-$(CONFIG_CHARGER_ISL9237)+=charger/isl923x.o driver-$(CONFIG_CHARGER_ISL9238)+=charger/isl923x.o +driver-$(CONFIG_CHARGER_ISL9241)+=charger/isl9241.o driver-$(CONFIG_CHARGER_MT6370)+=charger/rt946x.o driver-$(CONFIG_CHARGER_RT9466)+=charger/rt946x.o driver-$(CONFIG_CHARGER_RT9467)+=charger/rt946x.o diff --git a/driver/charger/isl9241.c b/driver/charger/isl9241.c new file mode 100644 index 0000000000..de6110a02b --- /dev/null +++ b/driver/charger/isl9241.c @@ -0,0 +1,362 @@ +/* Copyright 2019 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. + * + * Renesas (Intersil) ISL-9241 battery charger driver. + */ + +#include "adc.h" +#include "battery.h" +#include "battery_smart.h" +#include "charger.h" +#include "console.h" +#include "common.h" +#include "hooks.h" +#include "i2c.h" +#include "isl9241.h" +#include "system.h" +#include "task.h" +#include "timer.h" +#include "util.h" + +#ifndef CONFIG_CHARGER_NARROW_VDC +#error "ISL9241 is a NVDC charger, please enable CONFIG_CHARGER_NARROW_VDC." +#endif + +/* Sense resistor default values in milli Ohm */ +#define ISL9241_DEFAULT_RS1 20 /* Input current sense resistor */ +#define ISL9241_DEFAULT_RS2 10 /* Battery charge current sense resistor */ + +#define BOARD_RS1 CONFIG_CHARGER_SENSE_RESISTOR_AC +#define BOARD_RS2 CONFIG_CHARGER_SENSE_RESISTOR + +#define BC_REG_TO_CURRENT(REG) (((REG) * ISL9241_DEFAULT_RS2) / BOARD_RS2) +#define BC_CURRENT_TO_REG(CUR) (((CUR) * BOARD_RS2) / ISL9241_DEFAULT_RS2) + +#define AC_REG_TO_CURRENT(REG) (((REG) * ISL9241_DEFAULT_RS1) / BOARD_RS1) +#define AC_CURRENT_TO_REG(CUR) (((CUR) * BOARD_RS1) / ISL9241_DEFAULT_RS1) + +/* Console output macros */ +#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) + +static int learn_mode; + +/* Mutex for CONTROL1 register, that can be updated from multiple tasks. */ +static struct mutex control1_mutex; + +/* Charger parameters */ +static const struct charger_info isl9241_charger_info = { + .name = CHARGER_NAME, + .voltage_max = CHARGE_V_MAX, + .voltage_min = CHARGE_V_MIN, + .voltage_step = CHARGE_V_STEP, + .current_max = BC_REG_TO_CURRENT(CHARGE_I_MAX), + .current_min = BC_REG_TO_CURRENT(CHARGE_I_MIN), + .current_step = BC_REG_TO_CURRENT(CHARGE_I_STEP), + .input_current_max = AC_REG_TO_CURRENT(INPUT_I_MAX), + .input_current_min = AC_REG_TO_CURRENT(INPUT_I_MIN), + .input_current_step = AC_REG_TO_CURRENT(INPUT_I_STEP), +}; + +static inline int isl9241_read(int offset, int *value) +{ + return i2c_read16(I2C_PORT_CHARGER, I2C_ADDR_CHARGER, offset, value); +} + +static inline int isl9241_write(int offset, int value) +{ + return i2c_write16(I2C_PORT_CHARGER, I2C_ADDR_CHARGER, offset, value); +} + +/* chip specific interfaces */ + +/*****************************************************************************/ +/* Charger interfaces */ +int charger_set_input_current(int input_current) +{ + int rv; + uint16_t reg = AC_CURRENT_TO_REG(input_current); + + rv = isl9241_write(ISL9241_REG_ADAPTER_CUR_LIMIT1, reg); + if (rv) + return rv; + + return isl9241_write(ISL9241_REG_ADAPTER_CUR_LIMIT2, reg); +} + +int charger_get_input_current(int *input_current) +{ + int rv; + + rv = isl9241_read(ISL9241_REG_ADAPTER_CUR_LIMIT1, input_current); + if (rv) + return rv; + + *input_current = AC_REG_TO_CURRENT(*input_current); + return EC_SUCCESS; +} + +int charger_manufacturer_id(int *id) +{ + return isl9241_read(ISL9241_REG_MANUFACTURER_ID, id); +} + +int charger_device_id(int *id) +{ + return isl9241_read(ISL9241_REG_DEVICE_ID, id); +} + +int charger_get_option(int *option) +{ + int rv; + uint32_t controls; + int reg; + + rv = isl9241_read(ISL9241_REG_CONTROL0, ®); + if (rv) + return rv; + + controls = reg; + rv = isl9241_read(ISL9241_REG_CONTROL1, ®); + if (rv) + return rv; + + controls |= reg << 16; + *option = controls; + return EC_SUCCESS; +} + +int charger_set_option(int option) +{ + int rv; + + rv = isl9241_write(ISL9241_REG_CONTROL0, option & 0xFFFF); + if (rv) + return rv; + + return isl9241_write(ISL9241_REG_CONTROL1, (option >> 16) & 0xFFFF); +} + +const struct charger_info *charger_get_info(void) +{ + return &isl9241_charger_info; +} + +int charger_get_status(int *status) +{ + int rv; + int reg; + + /* Level 2 charger */ + *status = CHARGER_LEVEL_2; + + /* Charge inhibit status */ + rv = isl9241_read(ISL9241_REG_MIN_SYSTEM_VOLTAGE, ®); + if (rv) + return rv; + if (!reg) + *status |= CHARGER_CHARGE_INHIBITED; + + /* Battery present & AC present status */ + rv = isl9241_read(ISL9241_REG_INFORMATION2, ®); + if (rv) + return rv; + if (!(reg & ISL9241_INFORMATION2_BATGONE_PIN)) + *status |= CHARGER_BATTERY_PRESENT; + if (reg & ISL9241_INFORMATION2_ACOK_PIN) + *status |= CHARGER_AC_PRESENT; + + return EC_SUCCESS; +} + +int charger_set_mode(int mode) +{ + int rv; + + /* + * See crosbug.com/p/51196. Always disable learn mode unless it was set + * explicitly. + */ + if (!learn_mode) { + rv = charger_discharge_on_ac(0); + if (rv) + return rv; + } + + /* + * Charger inhibit + * MinSystemVoltage 0x00h = disables all battery charging + */ + rv = isl9241_write(ISL9241_REG_MIN_SYSTEM_VOLTAGE, + mode & CHARGE_FLAG_INHIBIT_CHARGE ? + 0 : battery_get_info()->voltage_min); + if (rv) + return rv; + + /* POR reset */ + if (mode & CHARGE_FLAG_POR_RESET) { + rv = isl9241_write(ISL9241_REG_CONTROL3, + ISL9241_CONTROL3_DIGITAL_RESET); + } + + return rv; +} + +int charger_get_current(int *current) +{ + int rv; + + rv = isl9241_read(ISL9241_REG_CHG_CURRENT_LIMIT, current); + if (rv) + return rv; + + *current = BC_REG_TO_CURRENT(*current); + return EC_SUCCESS; +} + +int charger_set_current(int current) +{ + return isl9241_write(ISL9241_REG_CHG_CURRENT_LIMIT, + BC_CURRENT_TO_REG(current)); +} + +int charger_get_voltage(int *voltage) +{ + return isl9241_read(ISL9241_REG_MAX_SYSTEM_VOLTAGE, voltage); +} + +int charger_set_voltage(int voltage) +{ + return isl9241_write(ISL9241_REG_MAX_SYSTEM_VOLTAGE, voltage); +} + +int charger_post_init(void) +{ + return EC_SUCCESS; +} + +int charger_discharge_on_ac(int enable) +{ + int rv; + int control1; + + mutex_lock(&control1_mutex); + + rv = isl9241_read(ISL9241_REG_CONTROL1, &control1); + if (rv) + goto out; + + if (enable) + control1 |= ISL9241_CONTROL1_LEARN_MODE; + else + control1 &= ~ISL9241_CONTROL1_LEARN_MODE; + + rv = isl9241_write(ISL9241_REG_CONTROL1, control1); + if (!rv) + learn_mode = enable; + +out: + mutex_unlock(&control1_mutex); + return rv; +} + +/*****************************************************************************/ +/* ISL-9241 initialization */ +static void isl9241_init(void) +{ + int reg; + + const struct battery_info *bi = battery_get_info(); + + /* + * Set the MaxSystemVoltage to battery maximum, + * 0x00=disables switching charger states + */ + if (isl9241_write(ISL9241_REG_MAX_SYSTEM_VOLTAGE, bi->voltage_max)) + goto init_fail; + + /* + * Set the MinSystemVoltage to battery minimum, + * 0x00=disables all battery charging + */ + if (isl9241_write(ISL9241_REG_MIN_SYSTEM_VOLTAGE, bi->voltage_min)) + goto init_fail; + + /* + * Set control2 register to + * [15:13]: Trickle Charging Current (battery pre-charge current) + * [12] : Two-Level Adapter Current Limit (enable) + * [10:9] : Prochot# Debounce time (1000us) + */ + if (isl9241_read(ISL9241_REG_CONTROL2, ®)) + goto init_fail; + + if (isl9241_write(ISL9241_REG_CONTROL2, + reg | ISL9241_CONTROL2_TRICKLE_CHG_CURR(bi->precharge_current) | + ISL9241_CONTROL2_TWO_LEVEL_ADP_CURR | + ISL9241_CONTROL2_PROCHOT_DEBOUNCE_1000)) + goto init_fail; + + /* + * Set control3 register to + * [14]: ACLIM Reload (Do not reload) + */ + if (isl9241_read(ISL9241_REG_CONTROL3, ®)) + goto init_fail; + + if (isl9241_write(ISL9241_REG_CONTROL3, + reg | ISL9241_CONTROL3_ACLIM_RELOAD)) + goto init_fail; + + /* + * No need to proceed with the rest of init if we sysjump'd to this + * image as the input current limit has already been set. + */ + if (system_jumped_to_this_image()) + return; + + /* Initialize the input current limit to the board's default. */ + if (charger_set_input_current(CONFIG_CHARGER_INPUT_CURRENT)) + goto init_fail; + + return; + +init_fail: + CPRINTF("ISL9241_init failed!"); +} +DECLARE_HOOK(HOOK_INIT, isl9241_init, HOOK_PRIO_INIT_I2C + 1); + +/*****************************************************************************/ +#ifdef CONFIG_CMD_CHARGER_DUMP +static void dump_reg_range(int low, int high) +{ + int reg; + int regval; + int rv; + + for (reg = low; reg <= high; reg++) { + CPRINTF("[%Xh] = ", reg); + rv = isl9241_read(reg, ®val); + if (!rv) + CPRINTF("0x%04x\n", regval); + else + CPRINTF("ERR (%d)\n", rv); + cflush(); + } +} + +static int command_isl9241_dump(int argc, char **argv) +{ + dump_reg_range(0x14, 0x15); + dump_reg_range(0x38, 0x40); + dump_reg_range(0x43, 0x43); + dump_reg_range(0x47, 0x4F); + dump_reg_range(0x80, 0x87); + dump_reg_range(0x90, 0x91); + dump_reg_range(0xFE, 0xFF); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(charger_dump, command_isl9241_dump, "", + "Dumps ISL9241 registers"); +#endif /* CONFIG_CMD_CHARGER_DUMP */ diff --git a/driver/charger/isl9241.h b/driver/charger/isl9241.h new file mode 100644 index 0000000000..b0be2cb188 --- /dev/null +++ b/driver/charger/isl9241.h @@ -0,0 +1,105 @@ +/* Copyright 2019 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. + * + * Renesas (Intersil) ISL-9241 battery charger driver header. + */ + +#ifndef __CROS_EC_ISL9241_H +#define __CROS_EC_ISL9241_H + +#define ISL9241_ADDR 0x12 /* 7bit address 0001001 */ +#define I2C_ADDR_CHARGER ISL9241_ADDR + +#define CHARGER_NAME "ISL9241" +#define CHARGE_V_MAX 18304 +#define CHARGE_V_MIN 64 +#define CHARGE_V_STEP 8 +#define CHARGE_I_MAX 6140 +#define CHARGE_I_MIN 4 +#define CHARGE_I_STEP 4 +#define INPUT_I_MAX 6140 +#define INPUT_I_MIN 4 +#define INPUT_I_STEP 4 + +/* Registers */ + +/* + * ChargeCurrentLimit [12:2] 11-bit (0x0000h = disables fast charging, + * trickle charging is allowed) + */ +#define ISL9241_REG_CHG_CURRENT_LIMIT 0x14 + +/* MaxSystemVoltage [14:3] 12-bit, (0x0000h = disables switching) */ +#define ISL9241_REG_MAX_SYSTEM_VOLTAGE 0x15 + +#define ISL9241_REG_CONTROL7 0x38 +#define ISL9241_REG_CONTROL0 0x39 +#define ISL9241_REG_INFORMATION1 0x3A +#define ISL9241_REG_ADAPTER_CUR_LIMIT2 0x3B + +/* Configures various charger options */ +#define ISL9241_REG_CONTROL1 0x3C +#define ISL9241_CONTROL1_LEARN_MODE BIT(12) + +/* Configures various charger options */ +#define ISL9241_REG_CONTROL2 0x3D +/* + * 15:13 - Trickle Charging Current + * <000> 32mA (do not use) + * <001> 64mA + * <010> 96mA + * <011> 128mA (default) + * <100> 160mA + * <101> 192mA + * <110> 224mA + * <111> 256mA + */ +#define ISL9241_CONTROL2_TRICKLE_CHG_CURR(curr) ((((curr) >> 5) - 1) << 13) +/* 12 - Two-Level Adapter Current Limit */ +#define ISL9241_CONTROL2_TWO_LEVEL_ADP_CURR BIT(12) +/* 10:9 PROCHOT# debounce time in uS */ +#define ISL9241_CONTROL2_PROCHOT_DEBOUNCE_1000 (3 << 9) + +/* MinSystemVoltage [13:6] 8-bit (0x0000h = disables all battery charging) */ +#define ISL9241_REG_MIN_SYSTEM_VOLTAGE 0x3E + +#define ISL9241_REG_ADAPTER_CUR_LIMIT1 0x3F +#define ISL9241_REG_ACOK_REFERENCE 0x40 +#define ISL9241_REG_CONTROL6 0x43 +#define ISL9241_REG_AC_PROCHOT 0x47 +#define ISL9241_REG_DC_PROCHOT 0x48 +#define ISL9241_REG_OTG_VOLTAGE 0x49 +#define ISL9241_REG_OTG_CURRENT 0x4A +#define ISL9241_REG_VIN_VOLTAGE 0x4B + +/* Configures various charger options */ +#define ISL9241_REG_CONTROL3 0x4C +/* 14: ACLIM Reload (0 - reload, 1 - Do not reload */ +#define ISL9241_CONTROL3_ACLIM_RELOAD BIT(14) +/* 2: Digital Reset (0 - Idle, 1 - Reset */ +#define ISL9241_CONTROL3_DIGITAL_RESET BIT(2) + +/* Indicates various charger status */ +#define ISL9241_REG_INFORMATION2 0x4D +/* 12: BATGONE pin status (0 = Battery is present, 1 = No battery) */ +#define ISL9241_INFORMATION2_BATGONE_PIN BIT(12) +/* 14: ACOK pin status (0 = No adapter, 1 = Adapter is present) */ +#define ISL9241_INFORMATION2_ACOK_PIN BIT(14) + +#define ISL9241_REG_CONTROL4 0x4E +#define ISL9241_REG_CONTROL5 0x4F +#define ISL9241_REG_NTC_ADC_RESULTS 0x80 +#define ISL9241_REG_VBAT_ADC_RESULTS 0x81 +#define ISL9241_REG_TJ_ADC_RESULTS 0x82 +#define ISL9241_REG_IADP_ADC_RESULTS 0x83 +#define ISL9241_REG_DC_ADC_RESULTS 0x84 +#define ISL9241_REG_CC_ADC_RESULTS 0x85 +#define ISL9241_REG_VSYS_ADC_RESULTS 0x86 +#define ISL9241_REG_VIN_ADC_RESULTS 0x87 +#define ISL9241_REG_INFORMATION3 0x90 +#define ISL9241_REG_INFORMATION4 0x91 +#define ISL9241_REG_MANUFACTURER_ID 0xFE +#define ISL9241_REG_DEVICE_ID 0xFF + +#endif /* __CROS_EC_ISL9241_H */ diff --git a/include/config.h b/include/config.h index e7dc4e8da2..294490b3cf 100644 --- a/include/config.h +++ b/include/config.h @@ -685,6 +685,7 @@ #undef CONFIG_CHARGER_BQ25895 #undef CONFIG_CHARGER_ISL9237 #undef CONFIG_CHARGER_ISL9238 +#undef CONFIG_CHARGER_ISL9241 #undef CONFIG_CHARGER_MT6370 #undef CONFIG_CHARGER_RT9466 #undef CONFIG_CHARGER_RT9467 @@ -4149,7 +4150,8 @@ * Define CONFIG_CHARGER_NARROW_VDC for chargers that use a Narrow VDC power * architecture. */ -#if defined(CONFIG_CHARGER_ISL9237) || defined(CONFIG_CHARGER_ISL9238) +#if defined(CONFIG_CHARGER_ISL9237) || defined(CONFIG_CHARGER_ISL9238) || \ + defined(CONFIG_CHARGER_ISL9241) #define CONFIG_CHARGER_NARROW_VDC #endif |