diff options
Diffstat (limited to 'driver/charger/isl9241.c')
-rw-r--r-- | driver/charger/isl9241.c | 599 |
1 files changed, 0 insertions, 599 deletions
diff --git a/driver/charger/isl9241.c b/driver/charger/isl9241.c deleted file mode 100644 index 794ea0b342..0000000000 --- a/driver/charger/isl9241.c +++ /dev/null @@ -1,599 +0,0 @@ -/* 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. - */ - -/* TODO(b/175881324) */ -#ifndef CONFIG_ZEPHYR -#include "adc.h" -#endif -#include "battery.h" -#include "battery_smart.h" -#include "charger.h" -#include "charge_state.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. */ -K_MUTEX_DEFINE(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 = CHARGE_I_MAX, - .current_min = CHARGE_I_MIN, - .current_step = CHARGE_I_STEP, - .input_current_max = INPUT_I_MAX, - .input_current_min = INPUT_I_MIN, - .input_current_step = INPUT_I_STEP, -}; - -static enum ec_error_list isl9241_discharge_on_ac(int chgnum, int enable); - -static inline enum ec_error_list isl9241_read(int chgnum, int offset, - int *value) -{ - return i2c_read16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list isl9241_write(int chgnum, int offset, - int value) -{ - return i2c_write16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, value); -} - -static inline enum ec_error_list isl9241_update(int chgnum, int offset, - uint16_t mask, - enum mask_update_action action) -{ - return i2c_update16(chg_chips[chgnum].i2c_port, - chg_chips[chgnum].i2c_addr_flags, - offset, mask, action); -} - -/* chip specific interfaces */ - -/*****************************************************************************/ -/* Charger interfaces */ -static enum ec_error_list isl9241_set_input_current_limit(int chgnum, - int input_current) -{ - int rv; - uint16_t reg = AC_CURRENT_TO_REG(input_current); - - rv = isl9241_write(chgnum, ISL9241_REG_ADAPTER_CUR_LIMIT1, reg); - if (rv) - return rv; - - return isl9241_write(chgnum, ISL9241_REG_ADAPTER_CUR_LIMIT2, reg); -} - -static enum ec_error_list isl9241_get_input_current_limit(int chgnum, - int *input_current) -{ - int rv; - - rv = isl9241_read(chgnum, ISL9241_REG_ADAPTER_CUR_LIMIT1, - input_current); - if (rv) - return rv; - - *input_current = AC_REG_TO_CURRENT(*input_current); - return EC_SUCCESS; -} - -static enum ec_error_list isl9241_manufacturer_id(int chgnum, int *id) -{ - return isl9241_read(chgnum, ISL9241_REG_MANUFACTURER_ID, id); -} - -static enum ec_error_list isl9241_device_id(int chgnum, int *id) -{ - return isl9241_read(chgnum, ISL9241_REG_DEVICE_ID, id); -} - -static enum ec_error_list isl9241_get_option(int chgnum, int *option) -{ - int rv; - uint32_t controls; - int reg; - - rv = isl9241_read(chgnum, ISL9241_REG_CONTROL0, ®); - if (rv) - return rv; - - controls = reg; - rv = isl9241_read(chgnum, ISL9241_REG_CONTROL1, ®); - if (rv) - return rv; - - controls |= reg << 16; - *option = controls; - return EC_SUCCESS; -} - -static enum ec_error_list isl9241_set_option(int chgnum, int option) -{ - int rv; - - rv = isl9241_write(chgnum, ISL9241_REG_CONTROL0, option & 0xFFFF); - if (rv) - return rv; - - return isl9241_write(chgnum, ISL9241_REG_CONTROL1, - (option >> 16) & 0xFFFF); -} - -static const struct charger_info *isl9241_get_info(int chgnum) -{ - return &isl9241_charger_info; -} - -static enum ec_error_list isl9241_get_status(int chgnum, int *status) -{ - int rv; - int reg; - - /* Level 2 charger */ - *status = CHARGER_LEVEL_2; - - /* Charge inhibit status */ - rv = isl9241_read(chgnum, ISL9241_REG_MIN_SYSTEM_VOLTAGE, ®); - if (rv) - return rv; - if (!reg) - *status |= CHARGER_CHARGE_INHIBITED; - - /* Battery present & AC present status */ - rv = isl9241_read(chgnum, 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; -} - -static enum ec_error_list isl9241_set_mode(int chgnum, int mode) -{ - int rv; - - /* - * See crosbug.com/p/51196. Always disable learn mode unless it was set - * explicitly. - */ - if (!learn_mode) { - rv = isl9241_discharge_on_ac(chgnum, 0); - if (rv) - return rv; - } - - /* - * Charger inhibit - * MinSystemVoltage 0x00h = disables all battery charging - */ - rv = isl9241_write(chgnum, 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(chgnum, ISL9241_REG_CONTROL3, - ISL9241_CONTROL3_DIGITAL_RESET); - } - - return rv; -} - -static enum ec_error_list isl9241_get_current(int chgnum, int *current) -{ - int rv; - - rv = isl9241_read(chgnum, ISL9241_REG_CHG_CURRENT_LIMIT, current); - if (rv) - return rv; - - *current = BC_REG_TO_CURRENT(*current); - return EC_SUCCESS; -} - -static enum ec_error_list isl9241_set_current(int chgnum, int current) -{ - return isl9241_write(chgnum, ISL9241_REG_CHG_CURRENT_LIMIT, - BC_CURRENT_TO_REG(current)); -} - -static enum ec_error_list isl9241_get_voltage(int chgnum, int *voltage) -{ - return isl9241_read(chgnum, ISL9241_REG_MAX_SYSTEM_VOLTAGE, voltage); -} - -static enum ec_error_list isl9241_set_voltage(int chgnum, int voltage) -{ - return isl9241_write(chgnum, ISL9241_REG_MAX_SYSTEM_VOLTAGE, voltage); -} - -static enum ec_error_list isl9241_get_vbus_voltage(int chgnum, int port, - int *voltage) -{ - int adc_val = 0; - int ctl3_val; - int rv; - - /* Get current Control3 value */ - rv = isl9241_read(chgnum, ISL9241_REG_CONTROL3, &ctl3_val); - if (rv) - goto error; - - /* Enable ADC */ - if (!(ctl3_val & ISL9241_CONTROL3_ENABLE_ADC)) { - rv = isl9241_write(chgnum, ISL9241_REG_CONTROL3, - ctl3_val | ISL9241_CONTROL3_ENABLE_ADC); - if (rv) - goto error; - } - - /* Read voltage ADC value */ - rv = isl9241_read(chgnum, ISL9241_REG_VIN_ADC_RESULTS, &adc_val); - if (rv) - goto error_restore_ctl3; - - /* - * Adjust adc_val - * - * raw adc_val has VIN_ADC in bits [13:6], so shift this down - * this puts adc_val in the range of 0..255, which maps to 0..24.48V - * each step in adc_val is 96mv - */ - adc_val >>= ISL9241_VIN_ADC_BIT_OFFSET; - adc_val *= ISL9241_VIN_ADC_STEP_MV; - *voltage = adc_val; - -error_restore_ctl3: - /* Restore Control3 value */ - if (!(ctl3_val & ISL9241_CONTROL3_ENABLE_ADC)) - (void)isl9241_write(chgnum, ISL9241_REG_CONTROL3, ctl3_val); - -error: - if (rv) - CPRINTF("Could not read VBUS ADC! Error: %d\n", rv); - - return rv; -} - -static enum ec_error_list isl9241_post_init(int chgnum) -{ - return EC_SUCCESS; -} - -static enum ec_error_list isl9241_discharge_on_ac(int chgnum, int enable) -{ - int rv; - - mutex_lock(&control1_mutex); - - rv = isl9241_update(chgnum, ISL9241_REG_CONTROL1, - ISL9241_CONTROL1_LEARN_MODE, - (enable) ? MASK_SET : MASK_CLR); - if (!rv) - learn_mode = enable; - - mutex_unlock(&control1_mutex); - return rv; -} - -int isl9241_set_ac_prochot(int chgnum, int ma) -{ - int rv; - uint16_t reg; - - /* - * The register reserves bits [6:0] and bits [15:13]. - * This routine should ensure these bits are not set - * before writing the register. - */ - if (ma > AC_REG_TO_CURRENT(ISL9241_AC_PROCHOT_CURRENT_MAX)) - reg = ISL9241_AC_PROCHOT_CURRENT_MAX; - else if (ma < AC_REG_TO_CURRENT(ISL9241_AC_PROCHOT_CURRENT_MIN)) - reg = ISL9241_AC_PROCHOT_CURRENT_MIN; - else - reg = AC_CURRENT_TO_REG(ma); - - rv = isl9241_write(chgnum, ISL9241_REG_AC_PROCHOT, reg); - if (rv) - CPRINTF("set_ac_prochot failed (%d)\n", rv); - - return rv; -} - -int isl9241_set_dc_prochot(int chgnum, int ma) -{ - int rv; - - /* - * The register reserves bits [7:0] and bits [15:14]. - * This routine should ensure these bits are not set - * before writing the register. - */ - if (ma > ISL9241_DC_PROCHOT_CURRENT_MAX) - ma = ISL9241_DC_PROCHOT_CURRENT_MAX; - else if (ma < ISL9241_DC_PROCHOT_CURRENT_MIN) - ma = ISL9241_DC_PROCHOT_CURRENT_MIN; - - rv = isl9241_write(chgnum, ISL9241_REG_DC_PROCHOT, ma); - if (rv) - CPRINTF("set_dc_prochot failed (%d)\n", rv); - - return rv; -} - -/*****************************************************************************/ -/* ISL-9241 initialization */ -static void isl9241_init(int chgnum) -{ -#ifdef CONFIG_ISL9241_SWITCHING_FREQ - int ctl_val; -#endif - - const struct battery_info *bi = battery_get_info(); - - /* - * Set the MaxSystemVoltage to battery maximum, - * 0x00=disables switching charger states - */ - if (isl9241_write(chgnum, 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(chgnum, ISL9241_REG_MIN_SYSTEM_VOLTAGE, - bi->voltage_min)) - goto init_fail; - - /* - * Set control2 register to - * [15:13]: Trickle Charging Current (battery pre-charge current) - * [10:9] : Prochot# Debounce time (1000us) - */ - if (isl9241_update(chgnum, ISL9241_REG_CONTROL2, - (ISL9241_CONTROL2_TRICKLE_CHG_CURR( - bi->precharge_current) | - ISL9241_CONTROL2_PROCHOT_DEBOUNCE_1000), - MASK_SET)) - goto init_fail; - - /* - * Set control3 register to - * [14]: ACLIM Reload (Do not reload) - */ - if (isl9241_update(chgnum, ISL9241_REG_CONTROL3, - ISL9241_CONTROL3_ACLIM_RELOAD, - MASK_SET)) - goto init_fail; - - /* - * Set control4 register to - * [13]: Slew rate control enable (sets VSYS ramp to 8mV/us) - */ - if (isl9241_update(chgnum, ISL9241_REG_CONTROL4, - ISL9241_CONTROL4_SLEW_RATE_CTRL, - MASK_SET)) - goto init_fail; - -#ifndef CONFIG_CHARGE_RAMP_HW - if (isl9241_update(chgnum, ISL9241_REG_CONTROL0, - ISL9241_CONTROL0_INPUT_VTG_REGULATION, - MASK_SET)) - goto init_fail; -#endif - -#ifdef CONFIG_ISL9241_SWITCHING_FREQ - if (isl9241_read(chgnum, ISL9241_REG_CONTROL1, &ctl_val)) - goto init_fail; - ctl_val &= ~ISL9241_CONTROL1_SWITCHING_FREQ_MASK; - ctl_val |= ((CONFIG_ISL9241_SWITCHING_FREQ << 7) & - ISL9241_CONTROL1_SWITCHING_FREQ_MASK); - if (isl9241_write(chgnum, ISL9241_REG_CONTROL1, ctl_val)) - goto init_fail; -#endif - - /* - * 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_late()) - return; - - /* Initialize the input current limit to the board's default. */ - if (isl9241_set_input_current_limit(chgnum, - CONFIG_CHARGER_INPUT_CURRENT)) - goto init_fail; - - return; - -init_fail: - CPRINTF("ISL9241_init failed!\n"); -} - -/*****************************************************************************/ -/* Hardware current ramping */ - -#ifdef CONFIG_CHARGE_RAMP_HW -static enum ec_error_list isl9241_set_hw_ramp(int chgnum, int enable) -{ - /* HW ramp is controlled by input voltage regulation reference bits */ - return isl9241_update(chgnum, ISL9241_REG_CONTROL0, - ISL9241_CONTROL0_INPUT_VTG_REGULATION, - (enable) ? MASK_CLR : MASK_SET); -} - -static int isl9241_ramp_is_stable(int chgnum) -{ - /* - * Since ISL cannot read the current limit that the ramp has settled - * on, then we can never consider the ramp stable, because we never - * know what the stable limit is. - */ - return 0; -} - -static int isl9241_ramp_is_detected(int chgnum) -{ - return 1; -} - -static int isl9241_ramp_get_current_limit(int chgnum) -{ - int reg; - - if (isl9241_read(chgnum, ISL9241_REG_IADP_ADC_RESULTS, ®)) - return 0; - - /* LSB value of register = 22.2mA */ - return (reg * 222) / 10; -} -#endif /* CONFIG_CHARGE_RAMP_HW */ - -/* - * When fully charged in a low-power state, the ISL9241 may get stuck - * in CCM. Toggle learning mode for 50 ms to enter DCM and save power. - * This is a workaround provided by Renesas. See b/183771327. - * Note: the charger_get_state() returns the last known charge value, - * so need to check the battery is not disconnected when the system - * comes from the battery cutoff. - */ -static void isl9241_restart_charge_voltage_when_full(void) -{ - if (!chipset_in_or_transitioning_to_state(CHIPSET_STATE_ON) - && charge_get_state() == PWR_STATE_CHARGE_NEAR_FULL - && battery_get_disconnect_state() == BATTERY_NOT_DISCONNECTED) { - charger_discharge_on_ac(1); - msleep(50); - charger_discharge_on_ac(0); - } -} -DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, - isl9241_restart_charge_voltage_when_full, - HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, - isl9241_restart_charge_voltage_when_full, - HOOK_PRIO_DEFAULT); -DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, - isl9241_restart_charge_voltage_when_full, - HOOK_PRIO_DEFAULT); - -/*****************************************************************************/ -#ifdef CONFIG_CMD_CHARGER_DUMP -static void dump_reg_range(int chgnum, int low, int high) -{ - int reg; - int regval; - int rv; - - for (reg = low; reg <= high; reg++) { - CPRINTF("[%Xh] = ", reg); - rv = isl9241_read(chgnum, 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) -{ - char *e; - int chgnum = 0; - - if (argc >= 2) { - chgnum = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - } - - dump_reg_range(chgnum, 0x14, 0x15); - dump_reg_range(chgnum, 0x38, 0x40); - dump_reg_range(chgnum, 0x43, 0x43); - dump_reg_range(chgnum, 0x47, 0x4F); - dump_reg_range(chgnum, 0x80, 0x87); - dump_reg_range(chgnum, 0x90, 0x91); - dump_reg_range(chgnum, 0xFE, 0xFF); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(charger_dump, command_isl9241_dump, - "charger_dump <chgnum>", - "Dumps ISL9241 registers"); -#endif /* CONFIG_CMD_CHARGER_DUMP */ - -const struct charger_drv isl9241_drv = { - .init = &isl9241_init, - .post_init = &isl9241_post_init, - .get_info = &isl9241_get_info, - .get_status = &isl9241_get_status, - .set_mode = &isl9241_set_mode, - .get_current = &isl9241_get_current, - .set_current = &isl9241_set_current, - .get_voltage = &isl9241_get_voltage, - .set_voltage = &isl9241_set_voltage, - .discharge_on_ac = &isl9241_discharge_on_ac, - .get_vbus_voltage = &isl9241_get_vbus_voltage, - .set_input_current_limit = &isl9241_set_input_current_limit, - .get_input_current_limit = &isl9241_get_input_current_limit, - .manufacturer_id = &isl9241_manufacturer_id, - .device_id = &isl9241_device_id, - .get_option = &isl9241_get_option, - .set_option = &isl9241_set_option, -#ifdef CONFIG_CHARGE_RAMP_HW - .set_hw_ramp = &isl9241_set_hw_ramp, - .ramp_is_stable = &isl9241_ramp_is_stable, - .ramp_is_detected = &isl9241_ramp_is_detected, - .ramp_get_current_limit = &isl9241_ramp_get_current_limit, -#endif -}; |