power: supply: qcom: Add snapshot of SMB5 charger driver

Add snapshot of qpnp-smb5 charger driver from msm-4.19
as of commit 1bb7bbeb1d09("sched: Fix compilation errors
with !WALT").

Change-Id: Ie7c99bea8887dcb97244e43e7984e2a82d1e5526
Signed-off-by: Jishnu Prakash <jprakash@codeaurora.org>
This commit is contained in:
Jishnu Prakash 2020-04-30 18:00:24 +05:30 • committed by Gerrit - the friendly Code Review server
commit 58bfbabe9e
14 changed files with 16889 additions and 0 deletions

View file

@ -15,4 +15,17 @@ config QPNP_QG
to determine the battery state-of-charge (SOC) and supports other
battery management features.
config QPNP_SMB5
tristate "SMB5 Battery Charger"
depends on MFD_SPMI_PMIC
help
Say Y to enables support for the SMB5 charging peripheral.
The QPNP SMB5 charger driver supports the charger peripheral
present in the chip.
The power supply framework is used to communicate battery and
usb properties to userspace and other driver consumers such
as fuel gauge, USB, and USB-PD.
VBUS and VCONN regulators are registered for supporting OTG,
and powered Type-C cables respectively.
endif

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_QPNP_QG) += qpnp-qg.o battery-profile-loader.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o fg-alg.o
obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017, 2019-2020 The Linux Foundation. All rights reserved.
*/
#ifndef __BATTERY_H
#define __BATTERY_H
struct charger_param {
u32 fcc_step_delay_ms;
u32 fcc_step_size_ua;
u32 smb_version;
u32 hvdcp2_max_icl_ua;
u32 hvdcp3_max_icl_ua;
u32 forced_main_fcc;
};
int qcom_batt_init(struct charger_param *param);
void qcom_batt_deinit(void);
#endif /* __BATTERY_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,239 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "SCHG-FLASH: %s: " fmt, __func__
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/power_supply.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/printk.h>
#include <linux/pmic-voter.h>
#include "smb5-lib.h"
#include "schgm-flash.h"
#define IS_BETWEEN(left, right, value) \
(((left) >= (right) && (left) >= (value) \
&& (value) >= (right)) \
|| ((left) <= (right) && (left) <= (value) \
&& (value) <= (right)))
irqreturn_t schgm_flash_default_irq_handler(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
pr_debug("IRQ: %s\n", irq_data->name);
return IRQ_HANDLED;
}
irqreturn_t schgm_flash_ilim2_irq_handler(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
int rc;
rc = smblib_write(chg, SCHGM_FLASH_S2_LATCH_RESET_CMD_REG,
FLASH_S2_LATCH_RESET_BIT);
if (rc < 0)
pr_err("Couldn't reset S2_LATCH reset rc=%d\n", rc);
return IRQ_HANDLED;
}
irqreturn_t schgm_flash_state_change_irq_handler(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
int rc;
u8 reg;
rc = smblib_read(chg, SCHGM_FLASH_STATUS_3_REG, &reg);
if (rc < 0)
pr_err("Couldn't read flash status_3 rc=%d\n", rc);
else
pr_debug("Flash status changed state=[%x]\n",
(reg && FLASH_STATE_MASK));
return IRQ_HANDLED;
}
#define FIXED_MODE 0
#define ADAPTIVE_MODE 1
static void schgm_flash_parse_dt(struct smb_charger *chg)
{
struct device_node *node = chg->dev->of_node;
u32 val;
int rc;
chg->flash_derating_soc = -EINVAL;
rc = of_property_read_u32(node, "qcom,flash-derating-soc", &val);
if (!rc) {
if (IS_BETWEEN(0, 100, val))
chg->flash_derating_soc = (val * 255) / 100;
}
chg->flash_disable_soc = -EINVAL;
rc = of_property_read_u32(node, "qcom,flash-disable-soc", &val);
if (!rc) {
if (IS_BETWEEN(0, 100, val))
chg->flash_disable_soc = (val * 255) / 100;
}
chg->headroom_mode = -EINVAL;
rc = of_property_read_u32(node, "qcom,headroom-mode", &val);
if (!rc) {
if (IS_BETWEEN(FIXED_MODE, ADAPTIVE_MODE, val))
chg->headroom_mode = val;
}
}
bool is_flash_active(struct smb_charger *chg)
{
return chg->flash_active ? true : false;
}
int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val)
{
int rc, vreg_state;
u8 stat = 0;
if (!chg->flash_init_done)
return -EPERM;
rc = smblib_read(chg, SCHGM_FLASH_STATUS_2_REG, &stat);
if (rc < 0) {
pr_err("Couldn't read FLASH STATUS_2 rc=%d\n", rc);
return rc;
}
vreg_state = !!(stat & VREG_OK_BIT);
/* If VREG_OK is not set check for flash error */
if (!vreg_state) {
rc = smblib_read(chg, SCHGM_FLASH_STATUS_3_REG, &stat);
if (rc < 0) {
pr_err("Couldn't read FLASH_STATUS_3 rc=%d\n", rc);
return rc;
}
if ((stat & FLASH_STATE_MASK) == FLASH_ERROR_VAL) {
vreg_state = -EFAULT;
rc = smblib_read(chg, SCHGM_FLASH_STATUS_5_REG,
&stat);
if (rc < 0) {
pr_err("Couldn't read FLASH_STATUS_5 rc=%d\n",
rc);
return rc;
}
pr_debug("Flash error: status=%x\n", stat);
}
}
/*
* val can be one of the following:
* 1 - VREG_OK is set.
* 0 - VREG_OK is 0 but no Flash error.
* -EFAULT - Flash Error is set.
*/
*val = vreg_state;
return 0;
}
void schgm_flash_torch_priority(struct smb_charger *chg, enum torch_mode mode)
{
int rc;
u8 reg;
/*
* If torch is configured in default BOOST mode, skip any update in the
* mode configuration.
*/
if (chg->headroom_mode == FIXED_MODE)
return;
if ((mode != TORCH_BOOST_MODE) && (mode != TORCH_BUCK_MODE))
return;
reg = mode;
rc = smblib_masked_write(chg, SCHGM_TORCH_PRIORITY_CONTROL_REG,
TORCH_PRIORITY_CONTROL_BIT, reg);
if (rc < 0)
pr_err("Couldn't configure Torch priority control rc=%d\n",
rc);
pr_debug("Torch priority changed to: %d\n", mode);
}
int schgm_flash_init(struct smb_charger *chg)
{
int rc;
u8 reg;
schgm_flash_parse_dt(chg);
if (chg->flash_derating_soc != -EINVAL) {
rc = smblib_write(chg, SCHGM_SOC_BASED_FLASH_DERATE_TH_CFG_REG,
chg->flash_derating_soc);
if (rc < 0) {
pr_err("Couldn't configure SOC for flash derating rc=%d\n",
rc);
return rc;
}
}
if (chg->flash_disable_soc != -EINVAL) {
rc = smblib_write(chg, SCHGM_SOC_BASED_FLASH_DISABLE_TH_CFG_REG,
chg->flash_disable_soc);
if (rc < 0) {
pr_err("Couldn't configure SOC for flash disable rc=%d\n",
rc);
return rc;
}
}
if (chg->headroom_mode != -EINVAL) {
/*
* configure headroom management policy for
* flash and torch mode.
*/
reg = (chg->headroom_mode == FIXED_MODE)
? FORCE_FLASH_BOOST_5V_BIT : 0;
rc = smblib_write(chg, SCHGM_FORCE_BOOST_CONTROL, reg);
if (rc < 0) {
pr_err("Couldn't write force boost control reg rc=%d\n",
rc);
return rc;
}
reg = (chg->headroom_mode == FIXED_MODE)
? TORCH_PRIORITY_CONTROL_BIT : 0;
rc = smblib_write(chg, SCHGM_TORCH_PRIORITY_CONTROL_REG, reg);
if (rc < 0) {
pr_err("Couldn't force 5V boost in torch mode rc=%d\n",
rc);
return rc;
}
}
if ((chg->flash_derating_soc != -EINVAL)
|| (chg->flash_disable_soc != -EINVAL)) {
/* Check if SOC based derating/disable is enabled */
rc = smblib_read(chg, SCHGM_FLASH_CONTROL_REG, &reg);
if (rc < 0) {
pr_err("Couldn't read flash control reg rc=%d\n", rc);
return rc;
}
if (!(reg & SOC_LOW_FOR_FLASH_EN_BIT))
pr_warn("Soc based flash derating not enabled\n");
}
chg->flash_init_done = true;
return 0;
}

View file

@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018, 2020 The Linux Foundation. All rights reserved.
*/
#ifndef __SCHGM_FLASH_H__
#define __SCHGM_FLASH_H__
#include <linux/bitops.h>
#define SCHGM_FLASH_BASE 0xA600
#define SCHGM_FLASH_STATUS_2_REG (SCHGM_FLASH_BASE + 0x07)
#define VREG_OK_BIT BIT(4)
#define SCHGM_FLASH_STATUS_3_REG (SCHGM_FLASH_BASE + 0x08)
#define FLASH_STATE_MASK GENMASK(2, 0)
#define FLASH_ERROR_VAL 0x7
#define SCHGM_FLASH_INT_RT_STS_REG (SCHGM_FLASH_BASE + 0x10)
#define SCHGM_FLASH_STATUS_5_REG (SCHGM_FLASH_BASE + 0x0B)
#define SCHGM_FORCE_BOOST_CONTROL (SCHGM_FLASH_BASE + 0x41)
#define FORCE_FLASH_BOOST_5V_BIT BIT(0)
#define SCHGM_FLASH_S2_LATCH_RESET_CMD_REG (SCHGM_FLASH_BASE + 0x44)
#define FLASH_S2_LATCH_RESET_BIT BIT(0)
#define SCHGM_FLASH_CONTROL_REG (SCHGM_FLASH_BASE + 0x60)
#define SOC_LOW_FOR_FLASH_EN_BIT BIT(7)
#define SCHGM_TORCH_PRIORITY_CONTROL_REG (SCHGM_FLASH_BASE + 0x63)
#define TORCH_PRIORITY_CONTROL_BIT BIT(0)
#define SCHGM_SOC_BASED_FLASH_DERATE_TH_CFG_REG (SCHGM_FLASH_BASE + 0x67)
#define SCHGM_SOC_BASED_FLASH_DISABLE_TH_CFG_REG \
(SCHGM_FLASH_BASE + 0x68)
enum torch_mode {
TORCH_BUCK_MODE = 0,
TORCH_BOOST_MODE,
};
int schgm_flash_get_vreg_ok(struct smb_charger *chg, int *val);
void schgm_flash_torch_priority(struct smb_charger *chg, enum torch_mode mode);
int schgm_flash_init(struct smb_charger *chg);
bool is_flash_active(struct smb_charger *chg);
irqreturn_t schgm_flash_default_irq_handler(int irq, void *data);
irqreturn_t schgm_flash_ilim2_irq_handler(int irq, void *data);
irqreturn_t schgm_flash_state_change_irq_handler(int irq, void *data);
#endif /* __SCHGM_FLASH_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,841 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
*/
#ifndef __SMB5_CHARGER_H
#define __SMB5_CHARGER_H
#include <linux/alarmtimer.h>
#include <linux/ktime.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/consumer.h>
#include <linux/extcon-provider.h>
#include <linux/usb/typec.h>
#include "storm-watch.h"
#include "battery.h"
enum print_reason {
PR_INTERRUPT = BIT(0),
PR_REGISTER = BIT(1),
PR_MISC = BIT(2),
PR_PARALLEL = BIT(3),
PR_OTG = BIT(4),
PR_WLS = BIT(5),
};
#define DEFAULT_VOTER "DEFAULT_VOTER"
#define USER_VOTER "USER_VOTER"
#define PD_VOTER "PD_VOTER"
#define DCP_VOTER "DCP_VOTER"
#define QC_VOTER "QC_VOTER"
#define USB_PSY_VOTER "USB_PSY_VOTER"
#define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER"
#define USBIN_V_VOTER "USBIN_V_VOTER"
#define CHG_STATE_VOTER "CHG_STATE_VOTER"
#define TAPER_END_VOTER "TAPER_END_VOTER"
#define THERMAL_DAEMON_VOTER "THERMAL_DAEMON_VOTER"
#define DIE_TEMP_VOTER "DIE_TEMP_VOTER"
#define BOOST_BACK_VOTER "BOOST_BACK_VOTER"
#define MICRO_USB_VOTER "MICRO_USB_VOTER"
#define DEBUG_BOARD_VOTER "DEBUG_BOARD_VOTER"
#define PD_SUSPEND_SUPPORTED_VOTER "PD_SUSPEND_SUPPORTED_VOTER"
#define PL_DELAY_VOTER "PL_DELAY_VOTER"
#define CTM_VOTER "CTM_VOTER"
#define SW_QC3_VOTER "SW_QC3_VOTER"
#define AICL_RERUN_VOTER "AICL_RERUN_VOTER"
#define SW_ICL_MAX_VOTER "SW_ICL_MAX_VOTER"
#define PL_QNOVO_VOTER "PL_QNOVO_VOTER"
#define QNOVO_VOTER "QNOVO_VOTER"
#define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER"
#define OTG_DELAY_VOTER "OTG_DELAY_VOTER"
#define USBIN_I_VOTER "USBIN_I_VOTER"
#define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER"
#define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER"
#define WBC_VOTER "WBC_VOTER"
#define HW_LIMIT_VOTER "HW_LIMIT_VOTER"
#define PL_SMB_EN_VOTER "PL_SMB_EN_VOTER"
#define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER"
#define LPD_VOTER "LPD_VOTER"
#define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER"
#define SW_THERM_REGULATION_VOTER "SW_THERM_REGULATION_VOTER"
#define JEITA_ARB_VOTER "JEITA_ARB_VOTER"
#define MOISTURE_VOTER "MOISTURE_VOTER"
#define HVDCP2_ICL_VOTER "HVDCP2_ICL_VOTER"
#define AICL_THRESHOLD_VOTER "AICL_THRESHOLD_VOTER"
#define USBOV_DBC_VOTER "USBOV_DBC_VOTER"
#define CHG_TERMINATION_VOTER "CHG_TERMINATION_VOTER"
#define THERMAL_THROTTLE_VOTER "THERMAL_THROTTLE_VOTER"
#define VOUT_VOTER "VOUT_VOTER"
#define USB_SUSPEND_VOTER "USB_SUSPEND_VOTER"
#define CHARGER_TYPE_VOTER "CHARGER_TYPE_VOTER"
#define HDC_IRQ_VOTER "HDC_IRQ_VOTER"
#define DETACH_DETECT_VOTER "DETACH_DETECT_VOTER"
#define CC_MODE_VOTER "CC_MODE_VOTER"
#define MAIN_FCC_VOTER "MAIN_FCC_VOTER"
#define DCIN_AICL_VOTER "DCIN_AICL_VOTER"
#define WLS_PL_CHARGING_VOTER "WLS_PL_CHARGING_VOTER"
#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER"
#define OVERHEAT_LIMIT_VOTER "OVERHEAT_LIMIT_VOTER"
#define TYPEC_SWAP_VOTER "TYPEC_SWAP_VOTER"
#define BOOST_BACK_STORM_COUNT 3
#define WEAK_CHG_STORM_COUNT 8
#define VBAT_TO_VRAW_ADC(v) div_u64((u64)v * 1000000UL, 194637UL)
#define ITERM_LIMITS_PMI632_MA 5000
#define ITERM_LIMITS_PM8150B_MA 10000
#define ADC_CHG_ITERM_MASK 32767
#define SDP_100_MA 100000
#define SDP_CURRENT_UA 500000
#define CDP_CURRENT_UA 1500000
#define DCP_CURRENT_UA 1500000
#define HVDCP_CURRENT_UA 3000000
#define TYPEC_DEFAULT_CURRENT_UA 900000
#define TYPEC_MEDIUM_CURRENT_UA 1500000
#define TYPEC_HIGH_CURRENT_UA 3000000
#define DCIN_ICL_MIN_UA 100000
#define DCIN_ICL_MAX_UA 1500000
#define DCIN_ICL_STEP_UA 100000
#define ROLE_REVERSAL_DELAY_MS 500
enum smb_mode {
PARALLEL_MASTER = 0,
PARALLEL_SLAVE,
NUM_MODES,
};
enum sink_src_mode {
SINK_MODE,
SRC_MODE,
AUDIO_ACCESS_MODE,
UNATTACHED_MODE,
};
enum qc2_non_comp_voltage {
QC2_COMPLIANT,
QC2_NON_COMPLIANT_9V,
QC2_NON_COMPLIANT_12V
};
enum {
BOOST_BACK_WA = BIT(0),
SW_THERM_REGULATION_WA = BIT(1),
WEAK_ADAPTER_WA = BIT(2),
USBIN_OV_WA = BIT(3),
CHG_TERMINATION_WA = BIT(4),
USBIN_ADC_WA = BIT(5),
SKIP_MISC_PBS_IRQ_WA = BIT(6),
};
enum jeita_cfg_stat {
JEITA_CFG_NONE = 0,
JEITA_CFG_FAILURE,
JEITA_CFG_COMPLETE,
};
enum {
RERUN_AICL = 0,
RESTART_AICL,
};
enum smb_irq_index {
/* CHGR */
CHGR_ERROR_IRQ = 0,
CHG_STATE_CHANGE_IRQ,
STEP_CHG_STATE_CHANGE_IRQ,
STEP_CHG_SOC_UPDATE_FAIL_IRQ,
STEP_CHG_SOC_UPDATE_REQ_IRQ,
FG_FVCAL_QUALIFIED_IRQ,
VPH_ALARM_IRQ,
VPH_DROP_PRECHG_IRQ,
/* DCDC */
OTG_FAIL_IRQ,
OTG_OC_DISABLE_SW_IRQ,
OTG_OC_HICCUP_IRQ,
BSM_ACTIVE_IRQ,
HIGH_DUTY_CYCLE_IRQ,
INPUT_CURRENT_LIMITING_IRQ,
CONCURRENT_MODE_DISABLE_IRQ,
SWITCHER_POWER_OK_IRQ,
/* BATIF */
BAT_TEMP_IRQ,
ALL_CHNL_CONV_DONE_IRQ,
BAT_OV_IRQ,
BAT_LOW_IRQ,
BAT_THERM_OR_ID_MISSING_IRQ,
BAT_TERMINAL_MISSING_IRQ,
BUCK_OC_IRQ,
VPH_OV_IRQ,
/* USB */
USBIN_COLLAPSE_IRQ,
USBIN_VASHDN_IRQ,
USBIN_UV_IRQ,
USBIN_OV_IRQ,
USBIN_PLUGIN_IRQ,
USBIN_REVI_CHANGE_IRQ,
USBIN_SRC_CHANGE_IRQ,
USBIN_ICL_CHANGE_IRQ,
/* DC */
DCIN_VASHDN_IRQ,
DCIN_UV_IRQ,
DCIN_OV_IRQ,
DCIN_PLUGIN_IRQ,
DCIN_REVI_IRQ,
DCIN_PON_IRQ,
DCIN_EN_IRQ,
/* TYPEC */
TYPEC_OR_RID_DETECTION_CHANGE_IRQ,
TYPEC_VPD_DETECT_IRQ,
TYPEC_CC_STATE_CHANGE_IRQ,
TYPEC_VCONN_OC_IRQ,
TYPEC_VBUS_CHANGE_IRQ,
TYPEC_ATTACH_DETACH_IRQ,
TYPEC_LEGACY_CABLE_DETECT_IRQ,
TYPEC_TRY_SNK_SRC_DETECT_IRQ,
/* MISC */
WDOG_SNARL_IRQ,
WDOG_BARK_IRQ,
AICL_FAIL_IRQ,
AICL_DONE_IRQ,
SMB_EN_IRQ,
IMP_TRIGGER_IRQ,
TEMP_CHANGE_IRQ,
TEMP_CHANGE_SMB_IRQ,
/* FLASH */
VREG_OK_IRQ,
ILIM_S2_IRQ,
ILIM_S1_IRQ,
VOUT_DOWN_IRQ,
VOUT_UP_IRQ,
FLASH_STATE_CHANGE_IRQ,
TORCH_REQ_IRQ,
FLASH_EN_IRQ,
SDAM_STS_IRQ,
/* END */
SMB_IRQ_MAX,
};
enum float_options {
FLOAT_DCP = 1,
FLOAT_SDP = 2,
DISABLE_CHARGING = 3,
SUSPEND_INPUT = 4,
};
enum chg_term_config_src {
ITERM_SRC_UNSPECIFIED,
ITERM_SRC_ADC,
ITERM_SRC_ANALOG
};
enum comp_clamp_levels {
CLAMP_LEVEL_DEFAULT = 0,
CLAMP_LEVEL_1,
MAX_CLAMP_LEVEL,
};
struct clamp_config {
u16 reg[3];
u16 val[3];
};
struct smb_irq_info {
const char *name;
const irq_handler_t handler;
const bool wake;
const struct storm_watch storm_data;
struct smb_irq_data *irq_data;
int irq;
bool enabled;
};
static const unsigned int smblib_extcon_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
EXTCON_NONE,
};
enum lpd_reason {
LPD_NONE,
LPD_MOISTURE_DETECTED,
LPD_FLOATING_CABLE,
};
/* Following states are applicable only for floating cable during LPD */
enum lpd_stage {
/* initial stage */
LPD_STAGE_NONE,
/* started and ongoing */
LPD_STAGE_FLOAT,
/* cancel if started, or don't start */
LPD_STAGE_FLOAT_CANCEL,
/* confirmed and mitigation measures taken for 60 s */
LPD_STAGE_COMMIT,
};
enum thermal_status_levels {
TEMP_SHUT_DOWN = 0,
TEMP_SHUT_DOWN_SMB,
TEMP_ALERT_LEVEL,
TEMP_ABOVE_RANGE,
TEMP_WITHIN_RANGE,
TEMP_BELOW_RANGE,
};
enum icl_override_mode {
/* APSD/Type-C/QC auto */
HW_AUTO_MODE,
/* 100/150/500/900mA */
SW_OVERRIDE_USB51_MODE,
/* ICL other than USB51 */
SW_OVERRIDE_HC_MODE,
};
/* EXTCON_USB and EXTCON_USB_HOST are mutually exclusive */
static const u32 smblib_extcon_exclusive[] = {0x3, 0};
struct smb_regulator {
struct regulator_dev *rdev;
struct regulator_desc rdesc;
};
struct smb_irq_data {
void *parent_data;
const char *name;
struct storm_watch storm_data;
};
struct smb_chg_param {
const char *name;
u16 reg;
int min_u;
int max_u;
int step_u;
int (*get_proc)(struct smb_chg_param *param,
u8 val_raw);
int (*set_proc)(struct smb_chg_param *param,
int val_u,
u8 *val_raw);
};
struct buck_boost_freq {
int freq_khz;
u8 val;
};
struct smb_chg_freq {
unsigned int freq_5V;
unsigned int freq_6V_8V;
unsigned int freq_9V;
unsigned int freq_12V;
unsigned int freq_removal;
unsigned int freq_below_otg_threshold;
unsigned int freq_above_otg_threshold;
};
struct smb_params {
struct smb_chg_param fcc;
struct smb_chg_param fv;
struct smb_chg_param usb_icl;
struct smb_chg_param icl_max_stat;
struct smb_chg_param icl_stat;
struct smb_chg_param otg_cl;
struct smb_chg_param dc_icl;
struct smb_chg_param jeita_cc_comp_hot;
struct smb_chg_param jeita_cc_comp_cold;
struct smb_chg_param freq_switcher;
struct smb_chg_param aicl_5v_threshold;
struct smb_chg_param aicl_cont_threshold;
};
struct parallel_params {
struct power_supply *psy;
};
struct smb_iio {
struct iio_channel *temp_chan;
struct iio_channel *usbin_i_chan;
struct iio_channel *usbin_v_chan;
struct iio_channel *mid_chan;
struct iio_channel *batt_i_chan;
struct iio_channel *connector_temp_chan;
struct iio_channel *sbux_chan;
struct iio_channel *vph_v_chan;
struct iio_channel *die_temp_chan;
struct iio_channel *skin_temp_chan;
struct iio_channel *smb_temp_chan;
};
struct smb_charger {
struct device *dev;
char *name;
struct regmap *regmap;
struct smb_irq_info *irq_info;
struct smb_params param;
struct smb_iio iio;
int *debug_mask;
int pd_disabled;
enum smb_mode mode;
struct smb_chg_freq chg_freq;
int otg_delay_ms;
int weak_chg_icl_ua;
u32 sdam_base;
bool pd_not_supported;
/* locks */
struct mutex smb_lock;
struct mutex ps_change_lock;
struct mutex irq_status_lock;
struct mutex dcin_aicl_lock;
spinlock_t typec_pr_lock;
struct mutex adc_lock;
struct mutex dpdm_lock;
struct mutex typec_lock;
/* power supplies */
struct power_supply *batt_psy;
struct power_supply *usb_psy;
struct power_supply *dc_psy;
struct power_supply *bms_psy;
struct power_supply *usb_main_psy;
struct power_supply *usb_port_psy;
struct power_supply *wls_psy;
struct power_supply *cp_psy;
enum power_supply_type real_charger_type;
/* notifiers */
struct notifier_block nb;
/* parallel charging */
struct parallel_params pl;
/* CC Mode */
int adapter_cc_mode;
int thermal_overheat;
/* regulators */
struct smb_regulator *vbus_vreg;
struct smb_regulator *vconn_vreg;
struct regulator *dpdm_reg;
/* typec */
struct typec_port *typec_port;
struct typec_capability typec_caps;
struct typec_partner *typec_partner;
struct typec_partner_desc typec_partner_desc;
/* votables */
struct votable *dc_suspend_votable;
struct votable *fcc_votable;
struct votable *fcc_main_votable;
struct votable *fv_votable;
struct votable *usb_icl_votable;
struct votable *awake_votable;
struct votable *pl_disable_votable;
struct votable *chg_disable_votable;
struct votable *pl_enable_votable_indirect;
struct votable *cp_disable_votable;
struct votable *cp_ilim_votable;
struct votable *smb_override_votable;
struct votable *icl_irq_disable_votable;
struct votable *limited_irq_disable_votable;
struct votable *hdc_irq_disable_votable;
struct votable *temp_change_irq_disable_votable;
struct votable *qnovo_disable_votable;
/* work */
struct work_struct bms_update_work;
struct work_struct pl_update_work;
struct work_struct jeita_update_work;
struct work_struct moisture_protection_work;
struct work_struct chg_termination_work;
struct work_struct dcin_aicl_work;
struct work_struct cp_status_change_work;
struct delayed_work ps_change_timeout_work;
struct delayed_work clear_hdc_work;
struct delayed_work icl_change_work;
struct delayed_work pl_enable_work;
struct delayed_work uusb_otg_work;
struct delayed_work bb_removal_work;
struct delayed_work lpd_ra_open_work;
struct delayed_work lpd_detach_work;
struct delayed_work thermal_regulation_work;
struct delayed_work usbov_dbc_work;
struct delayed_work pr_swap_detach_work;
struct delayed_work pr_lock_clear_work;
struct delayed_work role_reversal_check;
struct alarm lpd_recheck_timer;
struct alarm moisture_protection_alarm;
struct alarm chg_termination_alarm;
struct alarm dcin_aicl_alarm;
struct timer_list apsd_timer;
struct charger_param chg_param;
/* secondary charger config */
bool sec_pl_present;
bool sec_cp_present;
int sec_chg_selected;
int cp_reason;
int cp_topo;
/* pd */
int voltage_min_uv;
int voltage_max_uv;
int pd_active;
bool pd_hard_reset;
bool pr_lock_in_progress;
bool pr_swap_in_progress;
bool early_usb_attach;
bool ok_to_pd;
bool typec_legacy;
bool typec_irq_en;
bool typec_role_swap_failed;
/* cached status */
bool system_suspend_supported;
int boost_threshold_ua;
int system_temp_level;
int thermal_levels;
int *thermal_mitigation;
int dcp_icl_ua;
int fake_capacity;
int fake_batt_status;
bool step_chg_enabled;
bool sw_jeita_enabled;
bool typec_legacy_use_rp_icl;
bool is_hdc;
bool chg_done;
int connector_type;
bool otg_en;
bool suspend_input_on_debug_batt;
bool fake_chg_status_on_debug_batt;
int default_icl_ua;
int otg_cl_ua;
bool uusb_apsd_rerun_done;
bool typec_present;
int fake_input_current_limited;
int typec_mode;
int dr_mode;
int usb_icl_change_irq_enabled;
u32 jeita_status;
u8 float_cfg;
bool jeita_arb_flag;
bool use_extcon;
bool otg_present;
bool hvdcp_disable;
int hw_max_icl_ua;
int auto_recharge_soc;
enum sink_src_mode sink_src_mode;
enum power_supply_typec_power_role power_role;
enum jeita_cfg_stat jeita_configured;
int charger_temp_max;
int smb_temp_max;
u8 typec_try_mode;
enum lpd_stage lpd_stage;
bool lpd_disabled;
enum lpd_reason lpd_reason;
bool fcc_stepper_enable;
int die_temp;
int smb_temp;
int skin_temp;
int connector_temp;
int thermal_status;
int main_fcc_max;
u32 jeita_soft_thlds[2];
u32 jeita_soft_hys_thlds[2];
int jeita_soft_fcc[2];
int jeita_soft_fv[2];
bool moisture_present;
bool uusb_moisture_protection_capable;
bool uusb_moisture_protection_enabled;
bool hw_die_temp_mitigation;
bool hw_connector_mitigation;
bool hw_skin_temp_mitigation;
bool en_skin_therm_mitigation;
int connector_pull_up;
int smb_pull_up;
int aicl_5v_threshold_mv;
int default_aicl_5v_threshold_mv;
int aicl_cont_threshold_mv;
int default_aicl_cont_threshold_mv;
bool aicl_max_reached;
int charge_full_cc;
int cc_soc_ref;
int last_cc_soc;
int term_vbat_uv;
int usbin_forced_max_uv;
int init_thermal_ua;
u32 comp_clamp_level;
int wls_icl_ua;
int cutoff_count;
bool dcin_aicl_done;
bool hvdcp3_standalone_config;
bool dcin_icl_user_set;
bool dpdm_enabled;
bool apsd_ext_timeout;
bool qc3p5_detected;
/* workaround flag */
u32 wa_flags;
int boost_current_ua;
int qc2_max_pulses;
enum qc2_non_comp_voltage qc2_unsupported_voltage;
bool dbc_usbov;
/* extcon for VBUS / ID notification to USB for uUSB */
struct extcon_dev *extcon;
/* battery profile */
int batt_profile_fcc_ua;
int batt_profile_fv_uv;
int usb_icl_delta_ua;
int pulse_cnt;
int die_health;
int connector_health;
/* flash */
u32 flash_derating_soc;
u32 flash_disable_soc;
u32 headroom_mode;
bool flash_init_done;
bool flash_active;
u32 irq_status;
/* wireless */
int dcin_uv_count;
ktime_t dcin_uv_last_time;
int last_wls_vout;
};
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
int smblib_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val);
int smblib_write(struct smb_charger *chg, u16 addr, u8 val);
int smblib_batch_write(struct smb_charger *chg, u16 addr, u8 *val, int count);
int smblib_batch_read(struct smb_charger *chg, u16 addr, u8 *val, int count);
int smblib_get_charge_param(struct smb_charger *chg,
struct smb_chg_param *param, int *val_u);
int smblib_get_usb_suspend(struct smb_charger *chg, int *suspend);
int smblib_get_aicl_cont_threshold(struct smb_chg_param *param, u8 val_raw);
int smblib_enable_charging(struct smb_charger *chg, bool enable);
int smblib_set_charge_param(struct smb_charger *chg,
struct smb_chg_param *param, int val_u);
int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend);
int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend);
int smblib_mapping_soc_from_field_value(struct smb_chg_param *param,
int val_u, u8 *val_raw);
int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param,
u8 val_raw);
int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param,
int val_u, u8 *val_raw);
int smblib_set_chg_freq(struct smb_chg_param *param,
int val_u, u8 *val_raw);
int smblib_set_prop_boost_current(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_aicl_cont_threshold(struct smb_chg_param *param,
int val_u, u8 *val_raw);
int smblib_vbus_regulator_enable(struct regulator_dev *rdev);
int smblib_vbus_regulator_disable(struct regulator_dev *rdev);
int smblib_vbus_regulator_is_enabled(struct regulator_dev *rdev);
int smblib_vconn_regulator_enable(struct regulator_dev *rdev);
int smblib_vconn_regulator_disable(struct regulator_dev *rdev);
int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev);
irqreturn_t default_irq_handler(int irq, void *data);
irqreturn_t smb_en_irq_handler(int irq, void *data);
irqreturn_t chg_state_change_irq_handler(int irq, void *data);
irqreturn_t batt_temp_changed_irq_handler(int irq, void *data);
irqreturn_t batt_psy_changed_irq_handler(int irq, void *data);
irqreturn_t usbin_uv_irq_handler(int irq, void *data);
irqreturn_t usb_plugin_irq_handler(int irq, void *data);
irqreturn_t usb_source_change_irq_handler(int irq, void *data);
irqreturn_t icl_change_irq_handler(int irq, void *data);
irqreturn_t typec_state_change_irq_handler(int irq, void *data);
irqreturn_t typec_attach_detach_irq_handler(int irq, void *data);
irqreturn_t dcin_uv_irq_handler(int irq, void *data);
irqreturn_t dc_plugin_irq_handler(int irq, void *data);
irqreturn_t high_duty_cycle_irq_handler(int irq, void *data);
irqreturn_t switcher_power_ok_irq_handler(int irq, void *data);
irqreturn_t wdog_snarl_irq_handler(int irq, void *data);
irqreturn_t wdog_bark_irq_handler(int irq, void *data);
irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data);
irqreturn_t temp_change_irq_handler(int irq, void *data);
irqreturn_t usbin_ov_irq_handler(int irq, void *data);
irqreturn_t sdam_sts_change_irq_handler(int irq, void *data);
int smblib_get_prop_input_suspend(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_present(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_capacity(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_status(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_charge_type(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_charge_done(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_batt_current_now(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_health(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_system_temp_level(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_system_temp_level_max(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_input_current_limited(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_batt_iterm(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_input_suspend(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_batt_capacity(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_batt_status(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_system_temp_level(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_input_current_limited(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_get_prop_dc_present(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_dc_online(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_dc_current_max(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_dc_current_max(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_get_prop_dc_voltage_now(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_dc_voltage_max(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_voltage_wls_output(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_voltage_wls_output(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_dc_reset(struct smb_charger *chg);
int smblib_get_prop_usb_present(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_usb_online(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_usb_online(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_usb_suspend(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_usb_voltage_max(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_usb_voltage_max_design(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_usb_voltage_max_limit(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_get_prop_usb_voltage_now(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_low_power(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_usb_current_now(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_usb_prop_typec_mode(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_scope(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_typec_select_rp(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_typec_power_role(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_input_current_settled(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_pe_start(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_charger_temp(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_die_health(struct smb_charger *chg);
int smblib_get_die_health(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_smb_health(struct smb_charger *chg);
int smblib_get_prop_connector_health(struct smb_charger *chg);
int smblib_set_prop_thermal_overheat(struct smb_charger *chg,
int therm_overheat);
int smblib_get_skin_temp_status(struct smb_charger *chg);
int smblib_get_prop_vph_voltage_now(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_pd_current_max(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_sdp_current_max(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_pd_voltage_max(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_pd_voltage_min(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_typec_power_role(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_typec_select_rp(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_pd_active(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_ship_mode(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_set_prop_rechg_soc_thresh(struct smb_charger *chg,
const union power_supply_propval *val);
void smblib_suspend_on_debug_battery(struct smb_charger *chg);
int smblib_rerun_apsd_if_required(struct smb_charger *chg);
void smblib_rerun_apsd(struct smb_charger *chg);
int smblib_get_prop_fcc_delta(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_thermal_threshold(struct smb_charger *chg, u16 addr, int *val);
int smblib_dp_dm(struct smb_charger *chg, int val);
int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable);
int smblib_run_aicl(struct smb_charger *chg, int type);
int smblib_set_icl_current(struct smb_charger *chg, int icl_ua);
int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua);
int smblib_get_charge_current(struct smb_charger *chg, int *total_current_ua);
int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
const union power_supply_propval *val);
int smblib_typec_port_type_set(const struct typec_capability *cap,
enum typec_port_type type);
int smblib_get_prop_from_bms(struct smb_charger *chg,
enum power_supply_property psp,
union power_supply_propval *val);
int smblib_get_iio_channel(struct smb_charger *chg, const char *propname,
struct iio_channel **chan);
int smblib_read_iio_channel(struct smb_charger *chg, struct iio_channel *chan,
int div, int *data);
int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable);
int smblib_icl_override(struct smb_charger *chg, enum icl_override_mode mode);
enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm,
ktime_t time);
int smblib_toggle_smb_en(struct smb_charger *chg, int toggle);
void smblib_hvdcp_detect_enable(struct smb_charger *chg, bool enable);
void smblib_hvdcp_hw_inov_enable(struct smb_charger *chg, bool enable);
void smblib_hvdcp_exit_config(struct smb_charger *chg);
void smblib_apsd_enable(struct smb_charger *chg, bool enable);
int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val);
int smblib_get_irq_status(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_qc3_main_icl_offset(struct smb_charger *chg, int *offset_ua);
int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
#endif /* __SMB5_CHARGER_H */

View file

@ -0,0 +1,557 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
*/
#ifndef __SMB5_CHARGER_REG_H
#define __SMB5_CHARGER_REG_H
#include <linux/bitops.h>
#define CHGR_BASE 0x1000
#define DCDC_BASE 0x1100
#define BATIF_BASE 0x1200
#define USBIN_BASE 0x1300
#define DCIN_BASE 0x1400
#define TYPEC_BASE 0X1500
#define MISC_BASE 0x1600
#define MISC_PBS_BASE 0x7500
#define PERPH_TYPE_OFFSET 0x04
#define TYPE_MASK GENMASK(7, 0)
#define PERPH_SUBTYPE_OFFSET 0x05
#define SUBTYPE_MASK GENMASK(7, 0)
#define INT_RT_STS_OFFSET 0x10
#define SDAM_TYPE 0x2E
/********************************
* CHGR Peripheral Registers *
********************************/
#define BATTERY_CHARGER_STATUS_1_REG (CHGR_BASE + 0x06)
#define BATTERY_CHARGER_STATUS_MASK GENMASK(2, 0)
enum {
INHIBIT_CHARGE = 0,
TRICKLE_CHARGE,
PRE_CHARGE,
FULLON_CHARGE,
TAPER_CHARGE,
TERMINATE_CHARGE,
PAUSE_CHARGE,
DISABLE_CHARGE,
};
#define BATTERY_CHARGER_STATUS_2_REG (CHGR_BASE + 0x07)
#define CHARGER_ERROR_STATUS_BAT_OV_BIT BIT(1)
#define BATTERY_CHARGER_STATUS_5_REG (CHGR_BASE + 0x0B)
#define ENABLE_TRICKLE_BIT BIT(2)
#define ENABLE_PRE_CHARGING_BIT BIT(1)
#define ENABLE_FULLON_MODE_BIT BIT(0)
#define BATTERY_CHARGER_STATUS_7_REG (CHGR_BASE + 0x0D)
#define BAT_TEMP_STATUS_SOFT_LIMIT_MASK GENMASK(5, 4)
#define BAT_TEMP_STATUS_HOT_SOFT_BIT BIT(5)
#define BAT_TEMP_STATUS_COLD_SOFT_BIT BIT(4)
#define BAT_TEMP_STATUS_HARD_LIMIT_MASK GENMASK(3, 2)
#define BAT_TEMP_STATUS_TOO_HOT_BIT BIT(3)
#define BAT_TEMP_STATUS_TOO_COLD_BIT BIT(2)
#define BAT_TEMP_STATUS_TOO_HOT_AFP_BIT BIT(1)
#define BAT_TEMP_STATUS_TOO_COLD_AFP_BIT BIT(0)
#define CHARGING_ENABLE_CMD_REG (CHGR_BASE + 0x42)
#define CHARGING_ENABLE_CMD_BIT BIT(0)
#define CHARGING_PAUSE_CMD_REG (CHGR_BASE + 0x43)
#define CHARGING_PAUSE_CMD_BIT BIT(0)
#define CHGR_CFG2_REG (CHGR_BASE + 0x51)
#define RECHG_MASK GENMASK(2, 1)
#define VBAT_BASED_RECHG_BIT BIT(2)
#define SOC_BASED_RECHG_BIT GENMASK(2, 1)
#define CHARGER_INHIBIT_BIT BIT(0)
#define CHGR_FAST_CHARGE_CURRENT_CFG_REG (CHGR_BASE + 0x61)
#define CHGR_ADC_ITERM_UP_THD_MSB_REG (CHGR_BASE + 0x67)
#define CHGR_ADC_ITERM_UP_THD_LSB_REG (CHGR_BASE + 0x68)
#define CHGR_ADC_ITERM_LO_THD_MSB_REG (CHGR_BASE + 0x69)
#define CHGR_ADC_ITERM_LO_THD_LSB_REG (CHGR_BASE + 0x6A)
#define CHGR_NO_SAMPLE_TERM_RCHG_CFG_REG (CHGR_BASE + 0x6B)
#define NO_OF_SAMPLE_FOR_RCHG_SHIFT 2
#define NO_OF_SAMPLE_FOR_RCHG GENMASK(3, 2)
#define CHGR_ADC_TERM_CFG_REG (CHGR_BASE + 0x6C)
#define TERM_BASED_ON_SYNC_CONV_OR_SAMPLE_CNT BIT(0)
#define TERM_BASED_ON_SYNC_CONV 0
#define TERM_BASED_ON_SAMPLE_CNT 1
#define CHGR_FLOAT_VOLTAGE_CFG_REG (CHGR_BASE + 0x70)
#define CHARGE_INHIBIT_THRESHOLD_CFG_REG (CHGR_BASE + 0x72)
#define CHARGE_INHIBIT_THRESHOLD_MASK GENMASK(1, 0)
#define INHIBIT_ANALOG_VFLT_MINUS_50MV 0
#define INHIBIT_ANALOG_VFLT_MINUS_100MV 1
#define INHIBIT_ANALOG_VFLT_MINUS_200MV 2
#define INHIBIT_ANALOG_VFLT_MINUS_300MV 3
#define CHARGE_RCHG_SOC_THRESHOLD_CFG_REG (CHGR_BASE + 0x7D)
#define CHGR_ADC_RECHARGE_THRESHOLD_MSB_REG (CHGR_BASE + 0x7E)
#define CHGR_ADC_RECHARGE_THRESHOLD_LSB_REG (CHGR_BASE + 0x7F)
#define JEITA_EN_CFG_REG (CHGR_BASE + 0x90)
#define JEITA_EN_HOT_SL_FCV_BIT BIT(3)
#define JEITA_EN_COLD_SL_FCV_BIT BIT(2)
#define JEITA_EN_HOT_SL_CCC_BIT BIT(1)
#define JEITA_EN_COLD_SL_CCC_BIT BIT(0)
#define JEITA_CCCOMP_CFG_HOT_REG (CHGR_BASE + 0x92)
#define JEITA_CCCOMP_CFG_COLD_REG (CHGR_BASE + 0x93)
#define CHGR_JEITA_THRESHOLD_BASE_REG(i) (CHGR_BASE + 0x94 + (i * 4))
#define CHGR_JEITA_HOT_THRESHOLD_MSB_REG CHGR_JEITA_THRESHOLD_BASE_REG(0)
#define CHGR_FAST_CHARGE_SAFETY_TIMER_CFG_REG (CHGR_BASE + 0xA2)
#define FAST_CHARGE_SAFETY_TIMER_192_MIN 0x0
#define FAST_CHARGE_SAFETY_TIMER_384_MIN 0x1
#define FAST_CHARGE_SAFETY_TIMER_768_MIN 0x2
#define FAST_CHARGE_SAFETY_TIMER_1536_MIN 0x3
#define CHGR_ENG_CHARGING_CFG_REG (CHGR_BASE + 0xC0)
#define CHGR_ITERM_USE_ANALOG_BIT BIT(3)
/********************************
* DCDC Peripheral Registers *
********************************/
#define ICL_MAX_STATUS_REG (DCDC_BASE + 0x06)
#define ICL_STATUS_REG (DCDC_BASE + 0x07)
#define AICL_ICL_STATUS_REG (DCDC_BASE + 0x08)
#define AICL_STATUS_REG (DCDC_BASE + 0x0A)
#define SOFT_ILIMIT_BIT BIT(6)
#define AICL_DONE_BIT BIT(0)
#define POWER_PATH_STATUS_REG (DCDC_BASE + 0x0B)
#define USBIN_SUSPEND_STS_BIT BIT(6)
#define USE_USBIN_BIT BIT(4)
#define USE_DCIN_BIT BIT(3)
#define POWER_PATH_MASK GENMASK(2, 1)
#define VALID_INPUT_POWER_SOURCE_STS_BIT BIT(0)
#define DCDC_CMD_OTG_REG (DCDC_BASE + 0x40)
#define OTG_EN_BIT BIT(0)
#define DCDC_FSW_SEL_REG (DCDC_BASE + 0x50)
#define DCDC_OTG_CURRENT_LIMIT_CFG_REG (DCDC_BASE + 0x52)
#define DCDC_OTG_CFG_REG (DCDC_BASE + 0x53)
#define OTG_EN_SRC_CFG_BIT BIT(1)
#define OTG_FAULT_CONDITION_CFG_REG (DCDC_BASE + 0x56)
#define USBIN_MID_COMP_FAULT_EN_BIT BIT(5)
#define USBIN_COLLAPSE_FAULT_EN_BIT BIT(4)
#define DCDC_CFG_REF_MAX_PSNS_REG (DCDC_BASE + 0x8C)
#define DCDC_ENG_SDCDC_CFG5_REG (DCDC_BASE + 0xC4)
#define ENG_SDCDC_BAT_HPWR_MASK GENMASK(7, 6)
enum {
BOOST_MODE_THRESH_3P3_V,
BOOST_MODE_THRESH_3P4_V = 0x40,
BOOST_MODE_THRESH_3P5_V = 0x80,
BOOST_MODE_THRESH_3P6_V = 0xC0
};
/********************************
* BATIF Peripheral Registers *
********************************/
/* BATIF Interrupt Bits */
#define VPH_OV_RT_STS_BIT BIT(7)
#define BUCK_OC_RT_STS_BIT BIT(6)
#define BAT_TERMINAL_MISSING_RT_STS_BIT BIT(5)
#define BAT_THERM_OR_ID_MISSING_RT_STS_BIT BIT(4)
#define BAT_LOW_RT_STS_BIT BIT(3)
#define BAT_OV_RT_STS_BIT BIT(2)
#define ALL_CHNL_CONV_DONE_RT_STS BIT(1)
#define BAT_TEMP_RT_STS_BIT BIT(0)
#define SHIP_MODE_REG (BATIF_BASE + 0x40)
#define SHIP_MODE_EN_BIT BIT(0)
#define BATIF_ADC_CHANNEL_EN_REG (BATIF_BASE + 0x82)
#define IBATT_CHANNEL_EN_BIT BIT(6)
#define CONN_THM_CHANNEL_EN_BIT BIT(4)
#define DIE_TEMP_CHANNEL_EN_BIT BIT(2)
#define MISC_THM_CHANNEL_EN_BIT BIT(1)
#define BATIF_ADC_INTERNAL_PULL_UP_REG (BATIF_BASE + 0x86)
#define INTERNAL_PULL_UP_CONN_THM_MASK GENMASK(5, 4)
#define CONN_THM_SHIFT 4
#define INTERNAL_PULL_NO_PULL 0x00
#define INTERNAL_PULL_30K_PULL 0x01
#define INTERNAL_PULL_100K_PULL 0x02
#define INTERNAL_PULL_400K_PULL 0x03
/********************************
* USBIN Peripheral Registers *
********************************/
#define APSD_STATUS_REG (USBIN_BASE + 0x07)
#define APSD_STATUS_7_BIT BIT(7)
#define HVDCP_CHECK_TIMEOUT_BIT BIT(6)
#define SLOW_PLUGIN_TIMEOUT_BIT BIT(5)
#define ENUMERATION_DONE_BIT BIT(4)
#define VADP_CHANGE_DONE_AFTER_AUTH_BIT BIT(3)
#define QC_AUTH_DONE_STATUS_BIT BIT(2)
#define QC_CHARGER_BIT BIT(1)
#define APSD_DTC_STATUS_DONE_BIT BIT(0)
#define APSD_RESULT_STATUS_REG (USBIN_BASE + 0x08)
#define APSD_RESULT_STATUS_7_BIT BIT(7)
#define APSD_RESULT_STATUS_MASK GENMASK(6, 0)
#define QC_3P0_BIT BIT(6)
#define QC_2P0_BIT BIT(5)
#define FLOAT_CHARGER_BIT BIT(4)
#define DCP_CHARGER_BIT BIT(3)
#define CDP_CHARGER_BIT BIT(2)
#define OCP_CHARGER_BIT BIT(1)
#define SDP_CHARGER_BIT BIT(0)
#define QC_CHANGE_STATUS_REG (USBIN_BASE + 0x09)
#define QC_12V_BIT BIT(2)
#define QC_9V_BIT BIT(1)
#define QC_5V_BIT BIT(0)
#define QC_2P0_STATUS_MASK GENMASK(2, 0)
/* USBIN Interrupt Bits */
#define USBIN_ICL_CHANGE_RT_STS_BIT BIT(7)
#define USBIN_SOURCE_CHANGE_RT_STS_BIT BIT(6)
#define USBIN_REVI_RT_STS_BIT BIT(5)
#define USBIN_PLUGIN_RT_STS_BIT BIT(4)
#define USBIN_OV_RT_STS_BIT BIT(3)
#define USBIN_UV_RT_STS_BIT BIT(2)
#define USBIN_VASHDN_RT_STS_BIT BIT(1)
#define USBIN_COLLAPSE_RT_STS_BIT BIT(0)
#define USBIN_CMD_IL_REG (USBIN_BASE + 0x40)
#define USBIN_SUSPEND_BIT BIT(0)
#define CMD_APSD_REG (USBIN_BASE + 0x41)
#define APSD_RERUN_BIT BIT(0)
#define CMD_ICL_OVERRIDE_REG (USBIN_BASE + 0x42)
#define ICL_OVERRIDE_BIT BIT(0)
#define CMD_HVDCP_2_REG (USBIN_BASE + 0x43)
#define FORCE_12V_BIT BIT(5)
#define FORCE_9V_BIT BIT(4)
#define FORCE_5V_BIT BIT(3)
#define IDLE_BIT BIT(2)
#define SINGLE_DECREMENT_BIT BIT(1)
#define SINGLE_INCREMENT_BIT BIT(0)
#define USBIN_ADAPTER_ALLOW_OVERRIDE_REG (USBIN_BASE + 0x44)
#define CONTINUOUS BIT(3)
#define FORCE_12V BIT(2)
#define FORCE_9V BIT(1)
#define FORCE_5V BIT(0)
#define FORCE_NULL 0
#define USB_CMD_PULLDOWN_REG (USBIN_BASE + 0x45)
#define EN_PULLDOWN_USB_IN_BIT BIT(0)
#define TYPE_C_CFG_REG (USBIN_BASE + 0x58)
#define BC1P2_START_ON_CC_BIT BIT(7)
#define HVDCP_PULSE_COUNT_MAX_REG (USBIN_BASE + 0x5B)
#define HVDCP_PULSE_COUNT_MAX_QC2_MASK GENMASK(7, 6)
enum {
HVDCP_PULSE_COUNT_MAX_QC2_5V = 0,
HVDCP_PULSE_COUNT_MAX_QC2_9V = 0x40,
HVDCP_PULSE_COUNT_MAX_QC2_12V = 0x80,
HVDCP_PULSE_COUNT_MAX_QC2_INVALID = 0xC0
};
#define USBIN_OPTIONS_1_CFG_REG (USBIN_BASE + 0x62)
#define HVDCP_AUTH_ALG_EN_CFG_BIT BIT(6)
#define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT BIT(5)
#define BC1P2_SRC_DETECT_BIT BIT(3)
#define HVDCP_EN_BIT BIT(2)
#define USBIN_OPTIONS_2_CFG_REG (USBIN_BASE + 0x63)
#define DCD_TIMEOUT_SEL_BIT BIT(5)
#define FLOAT_OPTIONS_MASK GENMASK(2, 0)
#define FLOAT_DIS_CHGING_CFG_BIT BIT(2)
#define SUSPEND_FLOAT_CFG_BIT BIT(1)
#define FORCE_FLOAT_SDP_CFG_BIT BIT(0)
#define USBIN_LOAD_CFG_REG (USBIN_BASE + 0x65)
#define ICL_OVERRIDE_AFTER_APSD_BIT BIT(4)
#define USBIN_AICL_STEP_TIMING_SEL_MASK GENMASK(3, 2)
#define USBIN_IN_COLLAPSE_GF_SEL_MASK GENMASK(1, 0)
#define USBIN_ICL_OPTIONS_REG (USBIN_BASE + 0x66)
#define CFG_USB3P0_SEL_BIT BIT(2)
#define USB51_MODE_BIT BIT(1)
#define USBIN_MODE_CHG_BIT BIT(0)
#define USBIN_CURRENT_LIMIT_CFG_REG (USBIN_BASE + 0x70)
#define USBIN_AICL_OPTIONS_CFG_REG (USBIN_BASE + 0x80)
#define SUSPEND_ON_COLLAPSE_USBIN_BIT BIT(7)
#define USBIN_AICL_PERIODIC_RERUN_EN_BIT BIT(4)
#define USBIN_AICL_ADC_EN_BIT BIT(3)
#define USBIN_AICL_EN_BIT BIT(2)
#define USB_ENG_SSUPPLY_USB2_REG (USBIN_BASE + 0xC0)
#define ENG_SSUPPLY_12V_OV_OPT_BIT BIT(1)
#define USBIN_5V_AICL_THRESHOLD_REG (USBIN_BASE + 0x81)
#define USBIN_CONT_AICL_THRESHOLD_REG (USBIN_BASE + 0x84)
/********************************
* DCIN Peripheral Registers *
********************************/
/* DCIN Interrupt Bits */
#define DCIN_PLUGIN_RT_STS_BIT BIT(4)
#define DCIN_CMD_IL_REG (DCIN_BASE + 0x40)
#define DCIN_SUSPEND_BIT BIT(0)
#define DCIN_EN_OVERRIDE_BIT BIT(1)
#define DCIN_EN_MASK GENMASK(2, 1)
#define DCIN_CMD_PON_REG (DCIN_BASE + 0x45)
#define DCIN_PON_BIT BIT(0)
#define MID_CHG_BIT BIT(1)
#define DCIN_LOAD_CFG_REG (DCIN_BASE + 0x65)
#define INPUT_MISS_POLL_EN_BIT BIT(5)
/********************************
* TYPEC Peripheral Registers *
********************************/
#define TYPE_C_SNK_STATUS_REG (TYPEC_BASE + 0x06)
#define DETECTED_SRC_TYPE_MASK GENMASK(6, 0)
#define SNK_DAM_500MA_BIT BIT(6)
#define SNK_DAM_1500MA_BIT BIT(5)
#define SNK_DAM_3000MA_BIT BIT(4)
#define SNK_RP_STD_BIT BIT(3)
#define SNK_RP_1P5_BIT BIT(2)
#define SNK_RP_3P0_BIT BIT(1)
#define SNK_RP_SHORT_BIT BIT(0)
#define TYPE_C_SRC_STATUS_REG (TYPEC_BASE + 0x08)
#define DETECTED_SNK_TYPE_MASK GENMASK(4, 0)
#define SRC_HIGH_BATT_BIT BIT(5)
#define SRC_DEBUG_ACCESS_BIT BIT(4)
#define SRC_RD_OPEN_BIT BIT(3)
#define SRC_RD_RA_VCONN_BIT BIT(2)
#define SRC_RA_OPEN_BIT BIT(1)
#define AUDIO_ACCESS_RA_RA_BIT BIT(0)
#define TYPE_C_STATE_MACHINE_STATUS_REG (TYPEC_BASE + 0x09)
#define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5)
#define TYPE_C_MISC_STATUS_REG (TYPEC_BASE + 0x0B)
#define TYPEC_WATER_DETECTION_STATUS_BIT BIT(7)
#define SNK_SRC_MODE_BIT BIT(6)
#define TYPEC_VBUS_ERROR_STATUS_BIT BIT(4)
#define TYPEC_TCCDEBOUNCE_DONE_STATUS_BIT BIT(3)
#define CC_ORIENTATION_BIT BIT(1)
#define CC_ATTACHED_BIT BIT(0)
#define LEGACY_CABLE_STATUS_REG (TYPEC_BASE + 0x0D)
#define TYPEC_LEGACY_CABLE_STATUS_BIT BIT(1)
#define TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT BIT(0)
#define TYPEC_U_USB_STATUS_REG (TYPEC_BASE + 0x0F)
#define U_USB_GROUND_NOVBUS_BIT BIT(6)
#define U_USB_GROUND_BIT BIT(4)
#define U_USB_FMB1_BIT BIT(3)
#define U_USB_FLOAT1_BIT BIT(2)
#define U_USB_FMB2_BIT BIT(1)
#define U_USB_FLOAT2_BIT BIT(0)
#define TYPE_C_MODE_CFG_REG (TYPEC_BASE + 0x44)
#define TYPEC_TRY_MODE_MASK GENMASK(4, 3)
#define EN_TRY_SNK_BIT BIT(4)
#define EN_TRY_SRC_BIT BIT(3)
#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 0)
#define EN_SRC_ONLY_BIT BIT(2)
#define EN_SNK_ONLY_BIT BIT(1)
#define TYPEC_DISABLE_CMD_BIT BIT(0)
#define TYPE_C_VCONN_CONTROL_REG (TYPEC_BASE + 0x46)
#define VCONN_EN_ORIENTATION_BIT BIT(2)
#define VCONN_EN_VALUE_BIT BIT(1)
#define VCONN_EN_SRC_BIT BIT(0)
#define TYPE_C_CCOUT_CONTROL_REG (TYPEC_BASE + 0x48)
#define TYPEC_CCOUT_BUFFER_EN_BIT BIT(2)
#define TYPEC_CCOUT_VALUE_BIT BIT(1)
#define TYPEC_CCOUT_SRC_BIT BIT(0)
#define DEBUG_ACCESS_SRC_CFG_REG (TYPEC_BASE + 0x4C)
#define EN_UNORIENTED_DEBUG_ACCESS_SRC_BIT BIT(0)
#define TYPE_C_CRUDE_SENSOR_CFG_REG (TYPEC_BASE + 0x4e)
#define EN_SRC_CRUDE_SENSOR_BIT BIT(1)
#define EN_SNK_CRUDE_SENSOR_BIT BIT(0)
#define TYPE_C_EXIT_STATE_CFG_REG (TYPEC_BASE + 0x50)
#define BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT BIT(3)
#define SEL_SRC_UPPER_REF_BIT BIT(2)
#define EXIT_SNK_BASED_ON_CC_BIT BIT(0)
#define TYPE_C_CURRSRC_CFG_REG (TYPEC_BASE + 0x52)
#define TYPEC_SRC_RP_SEL_MASK GENMASK(1, 0)
enum {
TYPEC_SRC_RP_STD,
TYPEC_SRC_RP_1P5A,
TYPEC_SRC_RP_3A,
TYPEC_SRC_RP_3A_DUPLICATE,
TYPEC_SRC_RP_MAX_ELEMENTS
};
#define TYPE_C_INTERRUPT_EN_CFG_1_REG (TYPEC_BASE + 0x5E)
#define TYPEC_LEGACY_CABLE_INT_EN_BIT BIT(7)
#define TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN_BIT BIT(6)
#define TYPEC_TRYSOURCE_DETECT_INT_EN_BIT BIT(5)
#define TYPEC_TRYSINK_DETECT_INT_EN_BIT BIT(4)
#define TYPEC_CCOUT_DETACH_INT_EN_BIT BIT(3)
#define TYPEC_CCOUT_ATTACH_INT_EN_BIT BIT(2)
#define TYPEC_VBUS_DEASSERT_INT_EN_BIT BIT(1)
#define TYPEC_VBUS_ASSERT_INT_EN_BIT BIT(0)
#define TYPE_C_INTERRUPT_EN_CFG_2_REG (TYPEC_BASE + 0x60)
#define TYPEC_SRC_BATT_HPWR_INT_EN_BIT BIT(6)
#define MICRO_USB_STATE_CHANGE_INT_EN_BIT BIT(5)
#define TYPEC_STATE_MACHINE_CHANGE_INT_EN_BIT BIT(4)
#define TYPEC_DEBUG_ACCESS_DETECT_INT_EN_BIT BIT(3)
#define TYPEC_WATER_DETECTION_INT_EN_BIT BIT(2)
#define TYPEC_VBUS_ERROR_INT_EN_BIT BIT(1)
#define TYPEC_DEBOUNCE_DONE_INT_EN_BIT BIT(0)
#define TYPE_C_DEBOUNCE_OPTION_REG (TYPEC_BASE + 0x62)
#define REDUCE_TCCDEBOUNCE_TO_2MS_BIT BIT(2)
#define TYPE_C_SBU_CFG_REG (TYPEC_BASE + 0x6A)
#define SEL_SBU1_ISRC_VAL 0x04
#define SEL_SBU2_ISRC_VAL 0x01
#define TYPEC_U_USB_CFG_REG (TYPEC_BASE + 0x70)
#define EN_MICRO_USB_FACTORY_MODE_BIT BIT(1)
#define EN_MICRO_USB_MODE_BIT BIT(0)
#define PMI632_TYPEC_U_USB_WATER_PROTECTION_CFG_REG (TYPEC_BASE + 0x72)
#define TYPEC_U_USB_WATER_PROTECTION_CFG_REG (TYPEC_BASE + 0x73)
#define EN_MICRO_USB_WATER_PROTECTION_BIT BIT(4)
#define MICRO_USB_DETECTION_ON_TIME_CFG_MASK GENMASK(3, 2)
#define MICRO_USB_DETECTION_PERIOD_CFG_MASK GENMASK(1, 0)
#define PMI632_TYPEC_MICRO_USB_MODE_REG (TYPEC_BASE + 0x73)
#define MICRO_USB_MODE_ONLY_BIT BIT(0)
/********************************
* MISC Peripheral Registers *
********************************/
#define TEMP_RANGE_STATUS_REG (MISC_BASE + 0x06)
#define THERM_REG_ACTIVE_BIT BIT(6)
#define TLIM_BIT BIT(5)
#define TEMP_RANGE_MASK GENMASK(4, 1)
#define ALERT_LEVEL_BIT BIT(4)
#define TEMP_ABOVE_RANGE_BIT BIT(3)
#define TEMP_WITHIN_RANGE_BIT BIT(2)
#define TEMP_BELOW_RANGE_BIT BIT(1)
#define THERMREG_DISABLED_BIT BIT(0)
#define DIE_TEMP_STATUS_REG (MISC_BASE + 0x07)
#define DIE_TEMP_SHDN_BIT BIT(3)
#define DIE_TEMP_RST_BIT BIT(2)
#define DIE_TEMP_UB_BIT BIT(1)
#define DIE_TEMP_LB_BIT BIT(0)
#define SKIN_TEMP_STATUS_REG (MISC_BASE + 0x08)
#define SKIN_TEMP_SHDN_BIT BIT(3)
#define SKIN_TEMP_RST_BIT BIT(2)
#define SKIN_TEMP_UB_BIT BIT(1)
#define SKIN_TEMP_LB_BIT BIT(0)
#define CONNECTOR_TEMP_STATUS_REG (MISC_BASE + 0x09)
#define CONNECTOR_TEMP_SHDN_BIT BIT(3)
#define CONNECTOR_TEMP_RST_BIT BIT(2)
#define CONNECTOR_TEMP_UB_BIT BIT(1)
#define CONNECTOR_TEMP_LB_BIT BIT(0)
#define SMB_TEMP_STATUS_REG (MISC_BASE + 0x0A)
#define SMB_TEMP_SHDN_BIT BIT(3)
#define SMB_TEMP_RST_BIT BIT(2)
#define SMB_TEMP_UB_BIT BIT(1)
#define SMB_TEMP_LB_BIT BIT(0)
#define BARK_BITE_WDOG_PET_REG (MISC_BASE + 0x43)
#define BARK_BITE_WDOG_PET_BIT BIT(0)
#define AICL_CMD_REG (MISC_BASE + 0x44)
#define RESTART_AICL_BIT BIT(1)
#define RERUN_AICL_BIT BIT(0)
#define MISC_SMB_EN_CMD_REG (MISC_BASE + 0x48)
#define SMB_EN_OVERRIDE_VALUE_BIT BIT(4)
#define SMB_EN_OVERRIDE_BIT BIT(3)
#define EN_STAT_CMD_BIT BIT(2)
#define EN_CP_FPF_CMD_BIT BIT(1)
#define EN_CP_CMD_BIT BIT(0)
#define WD_CFG_REG (MISC_BASE + 0x51)
#define WATCHDOG_TRIGGER_AFP_EN_BIT BIT(7)
#define BARK_WDOG_INT_EN_BIT BIT(6)
#define WDOG_TIMER_EN_ON_PLUGIN_BIT BIT(1)
#define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53)
#define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7)
#define SNARL_WDOG_TIMEOUT_MASK GENMASK(6, 4)
#define SNARL_WDOG_TIMEOUT_SHIFT 4
#define SNARL_WDOG_TMOUT_62P5MS 0x00
#define SNARL_WDOG_TMOUT_1S 0x40
#define SNARL_WDOG_TMOUT_8S 0x70
#define BARK_WDOG_TIMEOUT_MASK GENMASK(3, 2)
#define BARK_WDOG_TIMEOUT_SHIFT 2
#define BITE_WDOG_TIMEOUT_MASK GENMASK(1, 0)
#define BITE_WDOG_TIMEOUT_8S 0x3
#define MIN_WD_BARK_TIME 16
#define AICL_RERUN_TIME_CFG_REG (MISC_BASE + 0x61)
#define AICL_RERUN_TIME_12S_VAL 0x01
#define MISC_THERMREG_SRC_CFG_REG (MISC_BASE + 0x70)
#define THERMREG_SW_ICL_ADJUST_BIT BIT(7)
#define DIE_ADC_SEL_BIT BIT(6)
#define THERMREG_SMB_ADC_SRC_EN_BIT BIT(5)
#define THERMREG_CONNECTOR_ADC_SRC_EN_BIT BIT(4)
#define SKIN_ADC_CFG_BIT BIT(3)
#define THERMREG_SKIN_ADC_SRC_EN_BIT BIT(2)
#define THERMREG_DIE_ADC_SRC_EN_BIT BIT(1)
#define THERMREG_DIE_CMP_SRC_EN_BIT BIT(0)
#define MISC_SMB_CFG_REG (MISC_BASE + 0x90)
#define SMB_EN_SEL_BIT BIT(4)
#define CP_EN_POLARITY_CFG_BIT BIT(3)
#define STAT_POLARITY_CFG_BIT BIT(2)
#define STAT_FUNCTION_CFG_BIT BIT(1)
#define STAT_IRQ_PULSING_EN_BIT BIT(0)
#define DIE_REG_H_THRESHOLD_MSB_REG (MISC_BASE + 0xA0)
#define SMB_REG_H_THRESHOLD_MSB_REG (MISC_BASE + 0XBC)
/* SDAM regs */
#define MISC_PBS_RT_STS_REG (MISC_PBS_BASE + 0x10)
#define PULSE_SKIP_IRQ_BIT BIT(4)
#define SDAM_QC_DET_STATUS_REG 0x58
#define SDAM_QC_ADC_LSB_REG 0x54
#endif /* __SMB5_CHARGER_REG_H */

View file

@ -0,0 +1,914 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "QCOM-STEPCHG: %s: " fmt, __func__
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/pmic-voter.h>
#include "step-chg-jeita.h"
#include "battery-profile-loader.h"
#define STEP_CHG_VOTER "STEP_CHG_VOTER"
#define JEITA_VOTER "JEITA_VOTER"
#define is_between(left, right, value) \
(((left) >= (right) && (left) >= (value) \
&& (value) >= (right)) \
|| ((left) <= (right) && (left) <= (value) \
&& (value) <= (right)))
struct step_chg_cfg {
struct step_chg_jeita_param param;
struct range_data fcc_cfg[MAX_STEP_CHG_ENTRIES];
};
struct jeita_fcc_cfg {
struct step_chg_jeita_param param;
struct range_data fcc_cfg[MAX_STEP_CHG_ENTRIES];
};
struct jeita_fv_cfg {
struct step_chg_jeita_param param;
struct range_data fv_cfg[MAX_STEP_CHG_ENTRIES];
};
struct step_chg_info {
struct device *dev;
ktime_t step_last_update_time;
ktime_t jeita_last_update_time;
bool step_chg_enable;
bool sw_jeita_enable;
bool jeita_arb_en;
bool config_is_read;
bool step_chg_cfg_valid;
bool sw_jeita_cfg_valid;
bool soc_based_step_chg;
bool ocv_based_step_chg;
bool vbat_avg_based_step_chg;
bool batt_missing;
bool taper_fcc;
int jeita_fcc_index;
int jeita_fv_index;
int step_index;
int get_config_retry_count;
struct step_chg_cfg *step_chg_config;
struct jeita_fcc_cfg *jeita_fcc_config;
struct jeita_fv_cfg *jeita_fv_config;
struct votable *fcc_votable;
struct votable *fv_votable;
struct votable *usb_icl_votable;
struct wakeup_source *step_chg_ws;
struct power_supply *batt_psy;
struct power_supply *bms_psy;
struct power_supply *usb_psy;
struct power_supply *dc_psy;
struct delayed_work status_change_work;
struct delayed_work get_config_work;
struct notifier_block nb;
};
static struct step_chg_info *the_chip;
#define STEP_CHG_HYSTERISIS_DELAY_US 5000000 /* 5 secs */
#define BATT_HOT_DECIDEGREE_MAX 600
#define GET_CONFIG_DELAY_MS 2000
#define GET_CONFIG_RETRY_COUNT 50
#define WAIT_BATT_ID_READY_MS 200
static bool is_batt_available(struct step_chg_info *chip)
{
if (!chip->batt_psy)
chip->batt_psy = power_supply_get_by_name("battery");
if (!chip->batt_psy)
return false;
return true;
}
static bool is_bms_available(struct step_chg_info *chip)
{
if (!chip->bms_psy)
chip->bms_psy = power_supply_get_by_name("bms");
if (!chip->bms_psy)
return false;
return true;
}
static bool is_usb_available(struct step_chg_info *chip)
{
if (!chip->usb_psy)
chip->usb_psy = power_supply_get_by_name("usb");
if (!chip->usb_psy)
return false;
return true;
}
static bool is_input_present(struct step_chg_info *chip)
{
int rc = 0, input_present = 0;
union power_supply_propval pval = {0, };
if (!chip->usb_psy)
chip->usb_psy = power_supply_get_by_name("usb");
if (chip->usb_psy) {
rc = power_supply_get_property(chip->usb_psy,
POWER_SUPPLY_PROP_PRESENT, &pval);
if (rc < 0)
pr_err("Couldn't read USB Present status, rc=%d\n", rc);
else
input_present |= pval.intval;
}
if (!chip->dc_psy)
chip->dc_psy = power_supply_get_by_name("dc");
if (chip->dc_psy) {
rc = power_supply_get_property(chip->dc_psy,
POWER_SUPPLY_PROP_PRESENT, &pval);
if (rc < 0)
pr_err("Couldn't read DC Present status, rc=%d\n", rc);
else
input_present |= pval.intval;
}
if (input_present)
return true;
return false;
}
int read_range_data_from_node(struct device_node *node,
const char *prop_str, struct range_data *ranges,
int max_threshold, u32 max_value)
{
int rc = 0, i, length, per_tuple_length, tuples;
if (!node || !prop_str || !ranges) {
pr_err("Invalid parameters passed\n");
return -EINVAL;
}
rc = of_property_count_elems_of_size(node, prop_str, sizeof(u32));
if (rc < 0) {
pr_err("Count %s failed, rc=%d\n", prop_str, rc);
return rc;
}
length = rc;
per_tuple_length = sizeof(struct range_data) / sizeof(u32);
if (length % per_tuple_length) {
pr_err("%s length (%d) should be multiple of %d\n",
prop_str, length, per_tuple_length);
return -EINVAL;
}
tuples = length / per_tuple_length;
if (tuples > MAX_STEP_CHG_ENTRIES) {
pr_err("too many entries(%d), only %d allowed\n",
tuples, MAX_STEP_CHG_ENTRIES);
return -EINVAL;
}
rc = of_property_read_u32_array(node, prop_str,
(u32 *)ranges, length);
if (rc) {
pr_err("Read %s failed, rc=%d\n", prop_str, rc);
return rc;
}
for (i = 0; i < tuples; i++) {
if (ranges[i].low_threshold >
ranges[i].high_threshold) {
pr_err("%s thresholds should be in ascendant ranges\n",
prop_str);
rc = -EINVAL;
goto clean;
}
if (i != 0) {
if (ranges[i - 1].high_threshold >
ranges[i].low_threshold) {
pr_err("%s thresholds should be in ascendant ranges\n",
prop_str);
rc = -EINVAL;
goto clean;
}
}
if (ranges[i].low_threshold > max_threshold)
ranges[i].low_threshold = max_threshold;
if (ranges[i].high_threshold > max_threshold)
ranges[i].high_threshold = max_threshold;
if (ranges[i].value > max_value)
ranges[i].value = max_value;
}
return rc;
clean:
memset(ranges, 0, tuples * sizeof(struct range_data));
return rc;
}
EXPORT_SYMBOL(read_range_data_from_node);
static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip)
{
struct device_node *batt_node, *profile_node;
u32 max_fv_uv, max_fcc_ma;
const char *batt_type_str;
const __be32 *handle;
int batt_id_ohms, rc;
union power_supply_propval prop = {0, };
handle = of_get_property(chip->dev->of_node,
"qcom,battery-data", NULL);
if (!handle) {
pr_debug("ignore getting sw-jeita/step charging settings from profile\n");
return 0;
}
batt_node = of_find_node_by_phandle(be32_to_cpup(handle));
if (!batt_node) {
pr_err("Get battery data node failed\n");
return -EINVAL;
}
if (!is_bms_available(chip))
return -ENODEV;
power_supply_get_property(chip->bms_psy,
POWER_SUPPLY_PROP_RESISTANCE_ID, &prop);
batt_id_ohms = prop.intval;
/* bms_psy has not yet read the batt_id */
if (batt_id_ohms < 0)
return -EBUSY;
profile_node = of_batterydata_get_best_profile(batt_node,
batt_id_ohms / 1000, NULL);
if (IS_ERR(profile_node))
return PTR_ERR(profile_node);
if (!profile_node) {
pr_err("Couldn't find profile\n");
return -ENODATA;
}
rc = of_property_read_string(profile_node, "qcom,battery-type",
&batt_type_str);
if (rc < 0) {
pr_err("battery type unavailable, rc:%d\n", rc);
return rc;
}
pr_debug("battery: %s detected, getting sw-jeita/step charging settings\n",
batt_type_str);
rc = of_property_read_u32(profile_node, "qcom,max-voltage-uv",
&max_fv_uv);
if (rc < 0) {
pr_err("max-voltage_uv reading failed, rc=%d\n", rc);
return rc;
}
rc = of_property_read_u32(profile_node, "qcom,fastchg-current-ma",
&max_fcc_ma);
if (rc < 0) {
pr_err("max-fastchg-current-ma reading failed, rc=%d\n", rc);
return rc;
}
chip->taper_fcc = of_property_read_bool(profile_node, "qcom,taper-fcc");
chip->soc_based_step_chg =
of_property_read_bool(profile_node, "qcom,soc-based-step-chg");
if (chip->soc_based_step_chg) {
chip->step_chg_config->param.psy_prop =
POWER_SUPPLY_PROP_CAPACITY;
chip->step_chg_config->param.prop_name = "SOC";
chip->step_chg_config->param.hysteresis = 0;
}
chip->ocv_based_step_chg =
of_property_read_bool(profile_node, "qcom,ocv-based-step-chg");
if (chip->ocv_based_step_chg) {
chip->step_chg_config->param.psy_prop =
POWER_SUPPLY_PROP_VOLTAGE_OCV;
chip->step_chg_config->param.prop_name = "OCV";
chip->step_chg_config->param.hysteresis = 0;
chip->step_chg_config->param.use_bms = true;
}
chip->vbat_avg_based_step_chg =
of_property_read_bool(profile_node,
"qcom,vbat-avg-based-step-chg");
if (chip->vbat_avg_based_step_chg) {
chip->step_chg_config->param.psy_prop =
POWER_SUPPLY_PROP_VOLTAGE_AVG;
chip->step_chg_config->param.prop_name = "VBAT_AVG";
chip->step_chg_config->param.hysteresis = 0;
chip->step_chg_config->param.use_bms = true;
}
chip->step_chg_cfg_valid = true;
rc = read_range_data_from_node(profile_node,
"qcom,step-chg-ranges",
chip->step_chg_config->fcc_cfg,
chip->soc_based_step_chg ? 100 : max_fv_uv,
max_fcc_ma * 1000);
if (rc < 0) {
pr_debug("Read qcom,step-chg-ranges failed from battery profile, rc=%d\n",
rc);
chip->step_chg_cfg_valid = false;
}
chip->sw_jeita_cfg_valid = true;
rc = read_range_data_from_node(profile_node,
"qcom,jeita-fcc-ranges",
chip->jeita_fcc_config->fcc_cfg,
BATT_HOT_DECIDEGREE_MAX, max_fcc_ma * 1000);
if (rc < 0) {
pr_debug("Read qcom,jeita-fcc-ranges failed from battery profile, rc=%d\n",
rc);
chip->sw_jeita_cfg_valid = false;
}
rc = read_range_data_from_node(profile_node,
"qcom,jeita-fv-ranges",
chip->jeita_fv_config->fv_cfg,
BATT_HOT_DECIDEGREE_MAX, max_fv_uv);
if (rc < 0) {
pr_debug("Read qcom,jeita-fv-ranges failed from battery profile, rc=%d\n",
rc);
chip->sw_jeita_cfg_valid = false;
}
return rc;
}
static void get_config_work(struct work_struct *work)
{
struct step_chg_info *chip = container_of(work,
struct step_chg_info, get_config_work.work);
int i, rc;
chip->config_is_read = false;
rc = get_step_chg_jeita_setting_from_profile(chip);
if (rc < 0) {
if (rc == -ENODEV || rc == -EBUSY) {
if (chip->get_config_retry_count++
< GET_CONFIG_RETRY_COUNT) {
pr_debug("bms_psy is not ready, retry: %d\n",
chip->get_config_retry_count);
goto reschedule;
}
}
}
chip->config_is_read = true;
for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
pr_debug("step-chg-cfg: %duV(SoC) ~ %duV(SoC), %duA\n",
chip->step_chg_config->fcc_cfg[i].low_threshold,
chip->step_chg_config->fcc_cfg[i].high_threshold,
chip->step_chg_config->fcc_cfg[i].value);
for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
pr_debug("jeita-fcc-cfg: %ddecidegree ~ %ddecidegre, %duA\n",
chip->jeita_fcc_config->fcc_cfg[i].low_threshold,
chip->jeita_fcc_config->fcc_cfg[i].high_threshold,
chip->jeita_fcc_config->fcc_cfg[i].value);
for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++)
pr_debug("jeita-fv-cfg: %ddecidegree ~ %ddecidegre, %duV\n",
chip->jeita_fv_config->fv_cfg[i].low_threshold,
chip->jeita_fv_config->fv_cfg[i].high_threshold,
chip->jeita_fv_config->fv_cfg[i].value);
return;
reschedule:
schedule_delayed_work(&chip->get_config_work,
msecs_to_jiffies(GET_CONFIG_DELAY_MS));
}
static int get_val(struct range_data *range, int hysteresis, int current_index,
int threshold,
int *new_index, int *val)
{
int i;
*new_index = -EINVAL;
/*
* If the threshold is lesser than the minimum allowed range,
* return -ENODATA.
*/
if (threshold < range[0].low_threshold)
return -ENODATA;
/* First try to find the matching index without hysteresis */
for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++) {
if (!range[i].high_threshold && !range[i].low_threshold) {
/* First invalid table entry; exit loop */
break;
}
if (is_between(range[i].low_threshold,
range[i].high_threshold, threshold)) {
*new_index = i;
*val = range[i].value;
break;
}
}
/*
* If nothing was found, the threshold exceeds the max range for sure
* as the other case where it is lesser than the min range is handled
* at the very beginning of this function. Therefore, clip it to the
* max allowed range value, which is the one corresponding to the last
* valid entry in the battery profile data array.
*/
if (*new_index == -EINVAL) {
if (i == 0) {
/* Battery profile data array is completely invalid */
return -ENODATA;
}
*new_index = (i - 1);
*val = range[*new_index].value;
}
/*
* If we don't have a current_index return this
* newfound value. There is no hysterisis from out of range
* to in range transition
*/
if (current_index == -EINVAL)
return 0;
/*
* Check for hysteresis if it in the neighbourhood
* of our current index.
*/
if (*new_index == current_index + 1) {
if (threshold < range[*new_index].low_threshold + hysteresis) {
/*
* Stay in the current index, threshold is not higher
* by hysteresis amount
*/
*new_index = current_index;
*val = range[current_index].value;
}
} else if (*new_index == current_index - 1) {
if (threshold > range[*new_index].high_threshold - hysteresis) {
/*
* stay in the current index, threshold is not lower
* by hysteresis amount
*/
*new_index = current_index;
*val = range[current_index].value;
}
}
return 0;
}
#define TAPERED_STEP_CHG_FCC_REDUCTION_STEP_MA 50000 /* 50 mA */
static void taper_fcc_step_chg(struct step_chg_info *chip, int index,
int current_voltage)
{
u32 current_fcc, target_fcc;
if (index < 0) {
pr_err("Invalid STEP CHG index\n");
return;
}
current_fcc = get_effective_result(chip->fcc_votable);
target_fcc = chip->step_chg_config->fcc_cfg[index].value;
if (index == 0) {
vote(chip->fcc_votable, STEP_CHG_VOTER, true, target_fcc);
} else if (current_voltage >
(chip->step_chg_config->fcc_cfg[index - 1].high_threshold +
chip->step_chg_config->param.hysteresis)) {
/*
* Ramp down FCC in pre-configured steps till the current index
* FCC configuration is reached, whenever the step charging
* control parameter exceeds the high threshold of previous
* step charging index configuration.
*/
vote(chip->fcc_votable, STEP_CHG_VOTER, true, max(target_fcc,
current_fcc - TAPERED_STEP_CHG_FCC_REDUCTION_STEP_MA));
} else if ((current_fcc >
chip->step_chg_config->fcc_cfg[index - 1].value) &&
(current_voltage >
chip->step_chg_config->fcc_cfg[index - 1].low_threshold +
chip->step_chg_config->param.hysteresis)) {
/*
* In case the step charging index switch to the next higher
* index without FCCs saturation for the previous index, ramp
* down FCC till previous index FCC configuration is reached.
*/
vote(chip->fcc_votable, STEP_CHG_VOTER, true,
max(chip->step_chg_config->fcc_cfg[index - 1].value,
current_fcc - TAPERED_STEP_CHG_FCC_REDUCTION_STEP_MA));
}
}
static int handle_step_chg_config(struct step_chg_info *chip)
{
union power_supply_propval pval = {0, };
int rc = 0, fcc_ua = 0, current_index;
u64 elapsed_us;
elapsed_us = ktime_us_delta(ktime_get(), chip->step_last_update_time);
/* skip processing, event too early */
if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
return 0;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED, &pval);
if (rc < 0)
chip->step_chg_enable = false;
else
chip->step_chg_enable = pval.intval;
if (!chip->step_chg_enable || !chip->step_chg_cfg_valid) {
if (chip->fcc_votable)
vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
goto update_time;
}
if (chip->step_chg_config->param.use_bms)
rc = power_supply_get_property(chip->bms_psy,
chip->step_chg_config->param.psy_prop, &pval);
else
rc = power_supply_get_property(chip->batt_psy,
chip->step_chg_config->param.psy_prop, &pval);
if (rc < 0) {
pr_err("Couldn't read %s property rc=%d\n",
chip->step_chg_config->param.prop_name, rc);
return rc;
}
current_index = chip->step_index;
rc = get_val(chip->step_chg_config->fcc_cfg,
chip->step_chg_config->param.hysteresis,
chip->step_index,
pval.intval,
&chip->step_index,
&fcc_ua);
if (rc < 0) {
/* remove the vote if no step-based fcc is found */
if (chip->fcc_votable)
vote(chip->fcc_votable, STEP_CHG_VOTER, false, 0);
goto update_time;
}
/* Do not drop step-chg index, if input supply is present */
if (is_input_present(chip)) {
if (chip->step_index < current_index)
chip->step_index = current_index;
} else {
chip->step_index = 0;
}
if (!chip->fcc_votable)
chip->fcc_votable = find_votable("FCC");
if (!chip->fcc_votable)
return -EINVAL;
if (chip->taper_fcc) {
taper_fcc_step_chg(chip, chip->step_index, pval.intval);
} else {
fcc_ua = chip->step_chg_config->fcc_cfg[chip->step_index].value;
vote(chip->fcc_votable, STEP_CHG_VOTER, true, fcc_ua);
}
pr_debug("%s = %d Step-FCC = %duA taper-fcc: %d\n",
chip->step_chg_config->param.prop_name, pval.intval,
get_client_vote(chip->fcc_votable, STEP_CHG_VOTER),
chip->taper_fcc);
update_time:
chip->step_last_update_time = ktime_get();
return 0;
}
#define JEITA_SUSPEND_HYST_UV 50000
static int handle_jeita(struct step_chg_info *chip)
{
union power_supply_propval pval = {0, };
int rc = 0, fcc_ua = 0, fv_uv = 0;
u64 elapsed_us;
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_SW_JEITA_ENABLED, &pval);
if (rc < 0)
chip->sw_jeita_enable = false;
else
chip->sw_jeita_enable = pval.intval;
if (!chip->sw_jeita_enable || !chip->sw_jeita_cfg_valid) {
if (chip->fcc_votable)
vote(chip->fcc_votable, JEITA_VOTER, false, 0);
if (chip->fv_votable)
vote(chip->fv_votable, JEITA_VOTER, false, 0);
if (chip->usb_icl_votable)
vote(chip->usb_icl_votable, JEITA_VOTER, false, 0);
return 0;
}
elapsed_us = ktime_us_delta(ktime_get(), chip->jeita_last_update_time);
/* skip processing, event too early */
if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US)
return 0;
if (chip->jeita_fcc_config->param.use_bms)
rc = power_supply_get_property(chip->bms_psy,
chip->jeita_fcc_config->param.psy_prop, &pval);
else
rc = power_supply_get_property(chip->batt_psy,
chip->jeita_fcc_config->param.psy_prop, &pval);
if (rc < 0) {
pr_err("Couldn't read %s property rc=%d\n",
chip->jeita_fcc_config->param.prop_name, rc);
return rc;
}
rc = get_val(chip->jeita_fcc_config->fcc_cfg,
chip->jeita_fcc_config->param.hysteresis,
chip->jeita_fcc_index,
pval.intval,
&chip->jeita_fcc_index,
&fcc_ua);
if (rc < 0)
fcc_ua = 0;
if (!chip->fcc_votable)
chip->fcc_votable = find_votable("FCC");
if (!chip->fcc_votable)
/* changing FCC is a must */
return -EINVAL;
vote(chip->fcc_votable, JEITA_VOTER, fcc_ua ? true : false, fcc_ua);
rc = get_val(chip->jeita_fv_config->fv_cfg,
chip->jeita_fv_config->param.hysteresis,
chip->jeita_fv_index,
pval.intval,
&chip->jeita_fv_index,
&fv_uv);
if (rc < 0)
fv_uv = 0;
chip->fv_votable = find_votable("FV");
if (!chip->fv_votable)
goto update_time;
if (!chip->usb_icl_votable)
chip->usb_icl_votable = find_votable("USB_ICL");
if (!chip->usb_icl_votable)
goto set_jeita_fv;
/*
* If JEITA float voltage is same as max-vfloat of battery then
* skip any further VBAT specific checks.
*/
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
if (rc || (pval.intval == fv_uv)) {
vote(chip->usb_icl_votable, JEITA_VOTER, false, 0);
goto set_jeita_fv;
}
/*
* Suspend USB input path if battery voltage is above
* JEITA VFLOAT threshold.
*/
if (chip->jeita_arb_en && fv_uv > 0) {
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval);
if (!rc && (pval.intval > fv_uv))
vote(chip->usb_icl_votable, JEITA_VOTER, true, 0);
else if (pval.intval < (fv_uv - JEITA_SUSPEND_HYST_UV))
vote(chip->usb_icl_votable, JEITA_VOTER, false, 0);
}
set_jeita_fv:
vote(chip->fv_votable, JEITA_VOTER, fv_uv ? true : false, fv_uv);
update_time:
chip->jeita_last_update_time = ktime_get();
return 0;
}
static int handle_battery_insertion(struct step_chg_info *chip)
{
int rc;
union power_supply_propval pval = {0, };
rc = power_supply_get_property(chip->batt_psy,
POWER_SUPPLY_PROP_PRESENT, &pval);
if (rc < 0) {
pr_err("Get battery present status failed, rc=%d\n", rc);
return rc;
}
if (chip->batt_missing != (!pval.intval)) {
chip->batt_missing = !pval.intval;
pr_debug("battery %s detected\n",
chip->batt_missing ? "removal" : "insertion");
if (chip->batt_missing) {
chip->step_chg_cfg_valid = false;
chip->sw_jeita_cfg_valid = false;
chip->get_config_retry_count = 0;
} else {
/*
* Get config for the new inserted battery, delay
* to make sure BMS has read out the batt_id.
*/
schedule_delayed_work(&chip->get_config_work,
msecs_to_jiffies(WAIT_BATT_ID_READY_MS));
}
}
return rc;
}
static void status_change_work(struct work_struct *work)
{
struct step_chg_info *chip = container_of(work,
struct step_chg_info, status_change_work.work);
int rc = 0;
union power_supply_propval prop = {0, };
if (!is_batt_available(chip) || !is_bms_available(chip))
goto exit_work;
handle_battery_insertion(chip);
/* skip elapsed_us debounce for handling battery temperature */
rc = handle_jeita(chip);
if (rc < 0)
pr_err("Couldn't handle sw jeita rc = %d\n", rc);
rc = handle_step_chg_config(chip);
if (rc < 0)
pr_err("Couldn't handle step rc = %d\n", rc);
/* Remove stale votes on USB removal */
if (is_usb_available(chip)) {
prop.intval = 0;
power_supply_get_property(chip->usb_psy,
POWER_SUPPLY_PROP_PRESENT, &prop);
if (!prop.intval) {
if (chip->usb_icl_votable)
vote(chip->usb_icl_votable, JEITA_VOTER,
false, 0);
}
}
exit_work:
__pm_relax(chip->step_chg_ws);
}
static int step_chg_notifier_call(struct notifier_block *nb,
unsigned long ev, void *v)
{
struct power_supply *psy = v;
struct step_chg_info *chip = container_of(nb, struct step_chg_info, nb);
if (ev != PSY_EVENT_PROP_CHANGED)
return NOTIFY_OK;
if ((strcmp(psy->desc->name, "battery") == 0)
|| (strcmp(psy->desc->name, "usb") == 0)) {
__pm_stay_awake(chip->step_chg_ws);
schedule_delayed_work(&chip->status_change_work, 0);
}
if ((strcmp(psy->desc->name, "bms") == 0)) {
if (chip->bms_psy == NULL)
chip->bms_psy = psy;
if (!chip->config_is_read)
schedule_delayed_work(&chip->get_config_work, 0);
}
return NOTIFY_OK;
}
static int step_chg_register_notifier(struct step_chg_info *chip)
{
int rc;
chip->nb.notifier_call = step_chg_notifier_call;
rc = power_supply_reg_notifier(&chip->nb);
if (rc < 0) {
pr_err("Couldn't register psy notifier rc = %d\n", rc);
return rc;
}
return 0;
}
int qcom_step_chg_init(struct device *dev,
bool step_chg_enable, bool sw_jeita_enable, bool jeita_arb_en)
{
int rc;
struct step_chg_info *chip;
if (the_chip) {
pr_err("Already initialized\n");
return -EINVAL;
}
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->step_chg_ws = wakeup_source_register("qcom-step-chg");
if (!chip->step_chg_ws)
return -EINVAL;
chip->dev = dev;
chip->step_chg_enable = step_chg_enable;
chip->sw_jeita_enable = sw_jeita_enable;
chip->jeita_arb_en = jeita_arb_en;
chip->step_index = -EINVAL;
chip->jeita_fcc_index = -EINVAL;
chip->jeita_fv_index = -EINVAL;
chip->step_chg_config = devm_kzalloc(dev,
sizeof(struct step_chg_cfg), GFP_KERNEL);
if (!chip->step_chg_config)
return -ENOMEM;
chip->step_chg_config->param.psy_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
chip->step_chg_config->param.prop_name = "VBATT";
chip->step_chg_config->param.hysteresis = 100000;
chip->jeita_fcc_config = devm_kzalloc(dev,
sizeof(struct jeita_fcc_cfg), GFP_KERNEL);
chip->jeita_fv_config = devm_kzalloc(dev,
sizeof(struct jeita_fv_cfg), GFP_KERNEL);
if (!chip->jeita_fcc_config || !chip->jeita_fv_config)
return -ENOMEM;
chip->jeita_fcc_config->param.psy_prop = POWER_SUPPLY_PROP_TEMP;
chip->jeita_fcc_config->param.prop_name = "BATT_TEMP";
chip->jeita_fcc_config->param.hysteresis = 10;
chip->jeita_fv_config->param.psy_prop = POWER_SUPPLY_PROP_TEMP;
chip->jeita_fv_config->param.prop_name = "BATT_TEMP";
chip->jeita_fv_config->param.hysteresis = 10;
INIT_DELAYED_WORK(&chip->status_change_work, status_change_work);
INIT_DELAYED_WORK(&chip->get_config_work, get_config_work);
rc = step_chg_register_notifier(chip);
if (rc < 0) {
pr_err("Couldn't register psy notifier rc = %d\n", rc);
goto release_wakeup_source;
}
schedule_delayed_work(&chip->get_config_work,
msecs_to_jiffies(GET_CONFIG_DELAY_MS));
the_chip = chip;
return 0;
release_wakeup_source:
wakeup_source_unregister(chip->step_chg_ws);
return rc;
}
void qcom_step_chg_deinit(void)
{
struct step_chg_info *chip = the_chip;
if (!chip)
return;
cancel_delayed_work_sync(&chip->status_change_work);
cancel_delayed_work_sync(&chip->get_config_work);
power_supply_unreg_notifier(&chip->nb);
wakeup_source_unregister(chip->step_chg_ws);
the_chip = NULL;
}

View file

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
*/
#ifndef __STEP_CHG_H__
#define __STEP_CHG_H__
#define MAX_STEP_CHG_ENTRIES 8
struct step_chg_jeita_param {
u32 psy_prop;
char *prop_name;
int hysteresis;
bool use_bms;
};
struct range_data {
int low_threshold;
int high_threshold;
u32 value;
};
int qcom_step_chg_init(struct device *dev,
bool step_chg_enable, bool sw_jeita_enable, bool jeita_arb_en);
void qcom_step_chg_deinit(void);
int read_range_data_from_node(struct device_node *node,
const char *prop_str, struct range_data *ranges,
int max_threshold, u32 max_value);
#endif /* __STEP_CHG_H__ */

View file

@ -0,0 +1,69 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
*/
#include "storm-watch.h"
/**
* is_storming(): Check if an event is storming
*
* @data: Data for tracking an event storm
*
* The return value will be true if a storm has been detected and
* false if a storm was not detected.
*/
bool is_storming(struct storm_watch *data)
{
ktime_t curr_kt, delta_kt;
bool is_storming = false;
if (!data)
return false;
if (!data->enabled)
return false;
/* max storm count must be greater than 0 */
if (data->max_storm_count <= 0)
return false;
/* the period threshold must be greater than 0ms */
if (data->storm_period_ms <= 0)
return false;
mutex_lock(&data->storm_lock);
curr_kt = ktime_get_boottime();
delta_kt = ktime_sub(curr_kt, data->last_kt);
if (ktime_to_ms(delta_kt) < data->storm_period_ms)
data->storm_count++;
else
data->storm_count = 0;
if (data->storm_count > data->max_storm_count) {
is_storming = true;
data->storm_count = 0;
}
data->last_kt = curr_kt;
mutex_unlock(&data->storm_lock);
return is_storming;
}
void reset_storm_count(struct storm_watch *data)
{
mutex_lock(&data->storm_lock);
data->storm_count = 0;
mutex_unlock(&data->storm_lock);
}
void update_storm_count(struct storm_watch *data, int max_count)
{
if (!data)
return;
mutex_lock(&data->storm_lock);
data->max_storm_count = max_count;
mutex_unlock(&data->storm_lock);
}

View file

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2016-2017, 2020 The Linux Foundation. All rights reserved.
*/
#ifndef __STORM_WATCH_H
#define __STORM_WATCH_H
#include <linux/ktime.h>
#include <linux/mutex.h>
/**
* Data used to track an event storm.
*
* @storm_period_ms: The maximum time interval between two events. If this limit
* is exceeded then the event chain will be broken and removed
* from consideration for a storm.
* @max_storm_count: The number of chained events required to trigger a storm.
* @storm_count: The current number of chained events.
* @last_kt: Kernel time of the last event seen.
* @storm_lock: Mutex lock to protect storm_watch data.
*/
struct storm_watch {
bool enabled;
int storm_period_ms;
int max_storm_count;
int storm_count;
ktime_t last_kt;
struct mutex storm_lock;
};
bool is_storming(struct storm_watch *data);
void reset_storm_count(struct storm_watch *data);
void update_storm_count(struct storm_watch *data, int max_count);
#endif