diff options
Diffstat (limited to 'driver/ln9310.c')
-rw-r--r-- | driver/ln9310.c | 573 |
1 files changed, 0 insertions, 573 deletions
diff --git a/driver/ln9310.c b/driver/ln9310.c deleted file mode 100644 index 3464cf46a2..0000000000 --- a/driver/ln9310.c +++ /dev/null @@ -1,573 +0,0 @@ -/* Copyright 2020 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. - * - * LION Semiconductor LN-9310 switched capacitor converter. - */ - -#include "common.h" -#include "console.h" -#include "driver/ln9310.h" -#include "hooks.h" -#include "i2c.h" -#include "util.h" -#include "timer.h" - -#define CPUTS(outstr) cputs(CC_I2C, outstr) -#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args) -#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args) - -static int power_good; -static int startup_workaround_required; - -int ln9310_power_good(void) -{ - return power_good; -} - -static inline int raw_read8(int offset, int *value) -{ - return i2c_read8(ln9310_config.i2c_port, - ln9310_config.i2c_addr_flags, - offset, - value); -} - -static inline int field_update8(int offset, int mask, int value) -{ - /* Clear mask and then set value in i2c reg value */ - return i2c_field_update8(ln9310_config.i2c_port, - ln9310_config.i2c_addr_flags, - offset, - mask, - value); -} - -static void ln9310_irq_deferred(void) -{ - int status, val, pg_2to1, pg_3to1; - - status = raw_read8(LN9310_REG_INT1, &val); - if (status) { - CPRINTS("LN9310 reading INT1 failed"); - return; - } - - CPRINTS("LN9310 received interrupt: 0x%x", val); - /* Don't care other interrupts except mode change */ - if (!(val & LN9310_INT1_MODE)) - return; - - /* Check if the device is active in 2:1 or 3:1 switching mode */ - status = raw_read8(LN9310_REG_SYS_STS, &val); - if (status) { - CPRINTS("LN9310 reading SYS_STS failed"); - return; - } - CPRINTS("LN9310 system status: 0x%x", val); - - /* Either 2:1 or 3:1 mode active is treated as PGOOD */ - pg_2to1 = !!(val & LN9310_SYS_SWITCHING21_ACTIVE); - pg_3to1 = !!(val & LN9310_SYS_SWITCHING31_ACTIVE); - power_good = pg_2to1 || pg_3to1; -} -DECLARE_DEFERRED(ln9310_irq_deferred); - -void ln9310_interrupt(enum gpio_signal signal) -{ - hook_call_deferred(&ln9310_irq_deferred_data, 0); -} - -static int is_battery_gt_10v(bool *out) -{ - int status, val; - - CPRINTS("LN9310 checking input voltage, threshold=10V"); - /* - * Turn on INFET_OUT_SWITCH_OK comparator; - * configure INFET_OUT_SWITCH_OK to 10V. - */ - status = field_update8(LN9310_REG_TRACK_CTRL, - LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_MASK | - LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG_MASK, - LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_ON | - LN9310_TRACK_INFET_OUT_SWITCH_OK_CFG_10V); - if (status != EC_SUCCESS) - return status; - - /* Read INFET_OUT_SWITCH_OK comparator */ - status = raw_read8(LN9310_REG_BC_STS_B, &val); - if (status != EC_SUCCESS) { - CPRINTS("LN9310 reading BC_STS_B failed"); - return status; - } - CPRINTS("LN9310 BC_STS_B: 0x%x", val); - - /* - * If INFET_OUT_SWITCH_OK=0, VIN < 10V - * If INFET_OUT_SWITCH_OK=1, VIN > 10V - */ - *out = !!(val & LN9310_BC_STS_B_INFET_OUT_SWITCH_OK); - CPRINTS("LN9310 battery %s 10V", (*out) ? ">" : "<"); - - /* Turn off INFET_OUT_SWITCH_OK comparator */ - status = field_update8(LN9310_REG_TRACK_CTRL, - LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_MASK, - LN9310_TRACK_INFET_OUT_SWITCH_OK_EN_OFF); - - return status; -} - -static int ln9310_reset_detected(void) -{ - /* - * Check LN9310_REG_LION_CTRL to see if it has been reset to 0x0. - * ln9310_init() and all other functions will set this register - * to a non-zero value so it should only become 0 again if LN9310 - * is reset. - */ - int val, status, reset_detected; - - status = raw_read8(LN9310_REG_LION_CTRL, &val); - if (status) { - CPRINTS("LN9310 reading LN9310_REG_LION_CTRL failed"); - /* If read fails, safest to assume reset has occurred */ - return 1; - } - reset_detected = (val == 0x0); - if (reset_detected) { - CPRINTS("LN9310 was reset (possibly in error)"); - } - return reset_detected; -} - -static int ln9310_update_startup_seq(void) -{ - int rc; - - CPRINTS("LN9310 update startup sequence"); - - /* - * Startup sequence instruction swap to hold Cfly - * bottom plate low during startup - */ - rc = field_update8(LN9310_REG_LION_CTRL, LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_UNLOCK_AND_EN_TM); - - rc |= field_update8(LN9310_REG_SWAP_CTRL_0, 0xff, 0x52); - - rc |= field_update8(LN9310_REG_SWAP_CTRL_1, 0xff, 0x54); - - rc |= field_update8(LN9310_REG_SWAP_CTRL_2, 0xff, 0xCC); - - rc |= field_update8(LN9310_REG_SWAP_CTRL_3, 0xff, 0x02); - - /* Startup sequence settings */ - rc |= field_update8( - LN9310_REG_CFG_4, - LN9310_CFG_4_SC_OUT_PRECHARGE_EN_TIME_CFG_MASK | - LN9310_CFG_4_SW1_VGS_SHORT_EN_MSK_MASK | - LN9310_CFG_4_BSTH_BSTL_HIGH_ROUT_CFG_MASK, - LN9310_CFG_4_SC_OUT_PRECHARGE_EN_TIME_CFG_ON | - LN9310_CFG_4_SW1_VGS_SHORT_EN_MSK_OFF | - LN9310_CFG_4_BSTH_BSTL_HIGH_ROUT_CFG_LOWEST); - - /* SW4 before BSTH_BSTL */ - rc |= field_update8(LN9310_REG_SPARE_0, - LN9310_SPARE_0_SW4_BEFORE_BSTH_BSTL_EN_CFG_MASK, - LN9310_SPARE_0_SW4_BEFORE_BSTH_BSTL_EN_CFG_ON); - - rc |= field_update8(LN9310_REG_LION_CTRL, LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_LOCK); - - return rc == EC_SUCCESS ? EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -static int ln9310_init_3to1(void) -{ - int rc; - - CPRINTS("LN9310 init (3:1 operation)"); - - /* Enable track protection and SC_OUT configs for 3:1 switching */ - rc = field_update8(LN9310_REG_MODE_CHANGE_CFG, - LN9310_MODE_TM_TRACK_MASK | - LN9310_MODE_TM_SC_OUT_PRECHG_MASK | - LN9310_MODE_TM_VIN_OV_CFG_MASK, - LN9310_MODE_TM_TRACK_SWITCH31 | - LN9310_MODE_TM_SC_OUT_PRECHG_SWITCH31 | - LN9310_MODE_TM_VIN_OV_CFG_3S); - - /* Enable 3:1 operation mode */ - rc |= field_update8(LN9310_REG_PWR_CTRL, LN9310_PWR_OP_MODE_MASK, - LN9310_PWR_OP_MODE_SWITCH31); - - /* 3S lower bound delta configurations */ - rc |= field_update8(LN9310_REG_LB_CTRL, LN9310_LB_DELTA_MASK, - LN9310_LB_DELTA_3S); - - /* - * TODO(waihong): The LN9310_REG_SYS_CTR was set to a wrong value - * accidentally. Override it to 0. This may not need. - */ - rc |= field_update8(LN9310_REG_SYS_CTRL, 0xff, 0); - - return rc == EC_SUCCESS ? EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -static int ln9310_init_2to1(void) -{ - int rc; - bool battery_gt_10v; - - CPRINTS("LN9310 init (2:1 operation)"); - - rc = is_battery_gt_10v(&battery_gt_10v); - if (rc != EC_SUCCESS || battery_gt_10v) { - CPRINTS("LN9310 init stop. Input voltage is too high."); - return EC_ERROR_UNKNOWN; - } - - /* Enable track protection and SC_OUT configs for 2:1 switching */ - rc = field_update8(LN9310_REG_MODE_CHANGE_CFG, - LN9310_MODE_TM_TRACK_MASK | - LN9310_MODE_TM_SC_OUT_PRECHG_MASK, - LN9310_MODE_TM_TRACK_SWITCH21 | - LN9310_MODE_TM_SC_OUT_PRECHG_SWITCH21); - - /* Enable 2:1 operation mode */ - rc |= field_update8(LN9310_REG_PWR_CTRL, LN9310_PWR_OP_MODE_MASK, - LN9310_PWR_OP_MODE_SWITCH21); - - /* 2S lower bound delta configurations */ - rc |= field_update8(LN9310_REG_LB_CTRL, LN9310_LB_DELTA_MASK, - LN9310_LB_DELTA_2S); - - /* - * TODO(waihong): The LN9310_REG_SYS_CTR was set to a wrong value - * accidentally. Override it to 0. This may not need. - */ - rc |= field_update8(LN9310_REG_SYS_CTRL, 0xff, 0); - - return rc == EC_SUCCESS ? EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -static int ln9310_update_infet(void) -{ - int rc; - - CPRINTS("LN9310 update infet configuration"); - - rc = field_update8(LN9310_REG_LION_CTRL, LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_UNLOCK_AND_EN_TM); - - /* Update Infet register settings */ - rc |= field_update8(LN9310_REG_CFG_5, LN9310_CFG_5_INGATE_PD_EN_MASK, - LN9310_CFG_5_INGATE_PD_EN_OFF); - - rc |= field_update8(LN9310_REG_CFG_5, - LN9310_CFG_5_INFET_CP_PD_BIAS_CFG_MASK, - LN9310_CFG_5_INFET_CP_PD_BIAS_CFG_LOWEST); - - /* enable automatic infet control */ - rc |= field_update8(LN9310_REG_PWR_CTRL, LN9310_PWR_INFET_AUTO_MODE_MASK, - LN9310_PWR_INFET_AUTO_MODE_ON); - - /* disable LS_HELPER during IDLE by setting MSK bit high */ - rc |= field_update8(LN9310_REG_CFG_0, - LN9310_CFG_0_LS_HELPER_IDLE_MSK_MASK, - LN9310_CFG_0_LS_HELPER_IDLE_MSK_ON); - - rc |= field_update8(LN9310_REG_LION_CTRL, LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_LOCK); - - return rc == EC_SUCCESS ? EC_SUCCESS : EC_ERROR_UNKNOWN; -} - -static int ln9310_precharge_cfly(uint64_t *precharge_timeout) -{ - int status = 0; - CPRINTS("LN9310 precharge cfly"); - - /* Unlock registers and enable test mode */ - status |= field_update8(LN9310_REG_LION_CTRL, - LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_UNLOCK_AND_EN_TM); - - /* disable test mode overrides */ - status |= field_update8(LN9310_REG_FORCE_SC21_CTRL_2, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_MASK, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_OFF); - - /* Configure test mode target values for precharge ckts. */ - status |= field_update8(LN9310_REG_FORCE_SC21_CTRL_1, - LN9310_FORCE_SC21_CTRL_1_TM_SC_OUT_CFLY_PRECHARGE_MASK, - LN9310_FORCE_SC21_CTRL_1_TM_SC_OUT_CFLY_PRECHARGE_ON); - - /* Force SCOUT precharge/predischarge overrides */ - status |= field_update8(LN9310_REG_TEST_MODE_CTRL, - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PRECHARGE_MASK | - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PREDISCHARGE_MASK, - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PRECHARGE_ON | - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PREDISCHARGE_ON); - - /* Force enable CFLY precharge overrides */ - status |= field_update8(LN9310_REG_FORCE_SC21_CTRL_2, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_MASK, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_ON); - - /* delay long enough to ensure CFLY has time to fully precharge */ - usleep(LN9310_CFLY_PRECHARGE_DELAY); - - /* locking and leaving test mode will stop CFLY precharge */ - *precharge_timeout = get_time().val + LN9310_CFLY_PRECHARGE_TIMEOUT; - status |= field_update8(LN9310_REG_LION_CTRL, - LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_LOCK); - - return status; -} - -static int ln9310_precharge_cfly_reset(void) -{ - int status = 0; - CPRINTS("LN9310 precharge cfly reset"); - - /* set known initial state for config bits related to cfly precharge */ - status |= field_update8(LN9310_REG_LION_CTRL, - LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_UNLOCK); - - /* Force off SCOUT precharge/predischarge overrides */ - status |= field_update8(LN9310_REG_TEST_MODE_CTRL, - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PRECHARGE_MASK | - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PREDISCHARGE_MASK, - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PRECHARGE_OFF | - LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PREDISCHARGE_OFF); - - /* disable test mode overrides */ - status |= field_update8(LN9310_REG_FORCE_SC21_CTRL_2, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_MASK, - LN9310_FORCE_SC21_CTRL_2_FORCE_SW_CTRL_REQ_OFF); - - /* disable CFLY and SC_OUT precharge control */ - status |= field_update8(LN9310_REG_FORCE_SC21_CTRL_1, - LN9310_FORCE_SC21_CTRL_1_TM_SC_OUT_CFLY_PRECHARGE_MASK, - LN9310_FORCE_SC21_CTRL_1_TM_SC_OUT_CFLY_PRECHARGE_OFF); - - status |= field_update8(LN9310_REG_LION_CTRL, - LN9310_LION_CTRL_MASK, - LN9310_LION_CTRL_LOCK); - - return status; -} - -int ln9310_init(void) -{ - int status, val, chip_revision; - enum battery_cell_type batt; - - /* Make sure initial state of LN9310 is STANDBY (i.e. output is off) */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_STANDBY_EN, - 1); - - /* - * LN9310 software startup is only required for earlier silicon revs. - * LN9310 hardware revisions after LN9310_BC_STS_C_CHIP_REV_FIXED - * should not use the software startup sequence. - */ - status = raw_read8(LN9310_REG_BC_STS_C, &val); - if (status != EC_SUCCESS) { - CPRINTS("LN9310 reading BC_STS_C failed: %d", status); - return status; - } - chip_revision = val & LN9310_BC_STS_C_CHIP_REV_MASK; - startup_workaround_required = chip_revision < LN9310_BC_STS_C_CHIP_REV_FIXED; - - /* Update INFET configuration */ - status = ln9310_update_infet(); - - if (status != EC_SUCCESS) - return status; - - /* - * Set OPERATION_MODE update method - * - OP_MODE_MANUAL_UPDATE = 0 - * - OP_MODE_SELF_SYNC_EN = 1 - */ - field_update8(LN9310_REG_PWR_CTRL, - LN9310_PWR_OP_MODE_MANUAL_UPDATE_MASK, - LN9310_PWR_OP_MODE_MANUAL_UPDATE_OFF); - - field_update8(LN9310_REG_TIMER_CTRL, - LN9310_TIMER_OP_SELF_SYNC_EN_MASK, - LN9310_TIMER_OP_SELF_SYNC_EN_ON); - - /* - * Use VIN for VDR, not EXT_5V. The following usleep will give - * circuit time to settle. - */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_SELECT_EXT_5V_FOR_VDR, - 0); - - field_update8(LN9310_REG_LB_CTRL, - LN9310_LB_MIN_FREQ_EN, - LN9310_LB_MIN_FREQ_EN); - - /* Set minimum switching frequency to 25 kHz */ - field_update8(LN9310_REG_SPARE_0, - LN9310_SPARE_0_LB_MIN_FREQ_SEL_MASK, - LN9310_SPARE_0_LB_MIN_FREQ_SEL_ON); - - usleep(LN9310_CDC_DELAY); - CPRINTS("LN9310 OP_MODE Update method: Self-sync"); - - if (startup_workaround_required) { - /* Update Startup sequence */ - status = ln9310_update_startup_seq(); - if (status != EC_SUCCESS) - return status; - } - - batt = board_get_battery_cell_type(); - if (batt == BATTERY_CELL_TYPE_3S) { - status = ln9310_init_3to1(); - } else if (batt == BATTERY_CELL_TYPE_2S) { - status = ln9310_init_2to1(); - } else { - CPRINTS("LN9310 not supported battery type: %d", batt); - return EC_ERROR_INVAL; - } - - if (status != EC_SUCCESS) - return status; - - /* Unmask the MODE change interrupt */ - field_update8(LN9310_REG_INT1_MSK, - LN9310_INT1_MODE, - 0); - return EC_SUCCESS; -} - -void ln9310_software_enable(int enable) -{ - int status, val, retry_count; - uint64_t precharge_timeout; - bool ln9310_init_completed = false; - - /* - * LN9310 startup requires (nEN=0 AND STANDBY_EN=0) where nEN is a pin - * and STANDBY_EN is a register bit. Previous EC firmware set - * STANDBY_EN=1 in ln9310_init and toggled nEN to startup/shutdown. This - * function implements an alternate software (i.e. controlled by EC - * through I2C commands) startup sequence so one option is to set nEN=1 - * and just used ln9310_software_enable to startup/shutdown. - * ln9310_software_enable can also be used in conjunction w/ the nEN pin - * (in case nEN pin is desired as visible signal ) as follows: - * - * Initial battery insertion: - * nEN=1 - * ln9310_init() - initial condition is STANDBY_EN=1 - * - * Power up LN9310: - * nEN=0 - STANDBY_EN should be 1 so this doesn't trigger startup - * ln9310_software_enable(1) - triggers alternate software-based startup - * - * Power down LN9310: - * nEN=1 - shutdown LN9310 (shutdown seq. does not require modification) - * ln9310_software_enable(0) - reset LN9310 register to state necessary - * for subsequent startups - */ - if (ln9310_reset_detected()) - ln9310_init(); - - /* Dummy clear all interrupts */ - status = raw_read8(LN9310_REG_INT1, &val); - if (status) { - CPRINTS("LN9310 reading INT1 failed"); - return; - } - CPRINTS("LN9310 cleared interrupts: 0x%x", val); - - if (startup_workaround_required) { - if (enable) { - /* - * Software modification of LN9310 startup sequence w/ retry - * loop. - * - * (1) Clear interrupts - * (2) Precharge Cfly w/ overrides of internal LN9310 signals - * (3) disable overrides -> stop precharging Cfly - * (4.1) if < 100 ms elapsed since (2) -> trigger LN9310 internal - * startup seq. - * (4.2) else -> abort and optionally retry from step 2 - */ - retry_count = 0; - while (!ln9310_init_completed && retry_count < LN9310_INIT_RETRY_COUNT) { - /* Precharge CFLY before starting up */ - status = ln9310_precharge_cfly(&precharge_timeout); - if (status != EC_SUCCESS) { - CPRINTS("LN9310 failed to run Cfly precharge sequence"); - status = ln9310_precharge_cfly_reset(); - retry_count++; - continue; - } - - /* - * Only start the SC if the cfly precharge - * hasn't timed out (i.e. ended too long ago) - */ - if (get_time().val < precharge_timeout) { - /* Clear the STANDBY_EN bit to enable the SC */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_STANDBY_EN, - 0); - if (get_time().val > precharge_timeout ) { - /* - * if timed out during previous I2C command, abort - * startup attempt - */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_STANDBY_EN, - 1); - } else { - /* all other paths should reattempt startup */ - ln9310_init_completed = true; - } - } - /* Reset to known state for config bits related to cfly precharge */ - ln9310_precharge_cfly_reset(); - retry_count++; - } - - if (!ln9310_init_completed) { - CPRINTS("LN9310 failed to start after %d retry attempts", - retry_count); - } - } else { - /* - * Internal LN9310 shutdown sequence is ok as is, so just reset - * the state to prepare for subsequent startup sequences. - * - * (1) set STANDBY_EN=1 to be sure the part turns off even if nEN=0 - * (2) reset cfly precharge related registers to known initial state - */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_STANDBY_EN, - 1); - - ln9310_precharge_cfly_reset(); - } - } else { - /* - * for newer LN9310 revsisions, the startup workaround is not required - * so the STANDBY_EN bit can just be set directly - */ - field_update8(LN9310_REG_STARTUP_CTRL, - LN9310_STARTUP_STANDBY_EN, - !enable); - } - return; -}
\ No newline at end of file |