summaryrefslogtreecommitdiff
path: root/driver/ln9310.c
diff options
context:
space:
mode:
Diffstat (limited to 'driver/ln9310.c')
-rw-r--r--driver/ln9310.c573
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