summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/power/qcom-charger/qpnp-smb2.c7
-rw-r--r--drivers/power/qcom-charger/smb-lib.c141
-rw-r--r--drivers/power/qcom-charger/smb-lib.h28
-rw-r--r--drivers/power/qcom-charger/smb-reg.h2
4 files changed, 108 insertions, 70 deletions
diff --git a/drivers/power/qcom-charger/qpnp-smb2.c b/drivers/power/qcom-charger/qpnp-smb2.c
index 8fa4fe301676..1b63f51088ee 100644
--- a/drivers/power/qcom-charger/qpnp-smb2.c
+++ b/drivers/power/qcom-charger/qpnp-smb2.c
@@ -983,9 +983,11 @@ static int smb2_init_hw(struct smb2 *chip)
/* votes must be cast before configuring software control */
vote(chg->pl_disable_votable,
- USBIN_ICL_VOTER, true, 0);
+ PL_INDIRECT_VOTER, true, 0);
vote(chg->pl_disable_votable,
CHG_STATE_VOTER, true, 0);
+ vote(chg->pl_disable_votable,
+ PARALLEL_PSY_VOTER, true, 0);
vote(chg->usb_suspend_votable,
DEFAULT_VOTER, chip->dt.no_battery, 0);
vote(chg->dc_suspend_votable,
@@ -1100,6 +1102,7 @@ static int smb2_init_hw(struct smb2 *chip)
static int smb2_setup_wa_flags(struct smb2 *chip)
{
+ struct smb_charger *chg = &chip->chg;
struct pmic_revid_data *pmic_rev_id;
struct device_node *revid_dev_node;
@@ -1122,6 +1125,8 @@ static int smb2_setup_wa_flags(struct smb2 *chip)
switch (pmic_rev_id->pmic_subtype) {
case PMICOBALT_SUBTYPE:
+ if (pmic_rev_id->rev4 == PMICOBALT_V1P1_REV4) /* PMI rev 1.1 */
+ chg->wa_flags |= QC_CHARGER_DETECTION_WA_BIT;
break;
default:
pr_err("PMIC subtype %d not supported\n",
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index a869fc592474..e9c189ae17e7 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -521,7 +521,7 @@ static int smblib_fcc_max_vote_callback(struct votable *votable, void *data,
{
struct smb_charger *chg = data;
- return vote(chg->fcc_votable, FCC_MAX_RESULT, true, fcc_ua);
+ return vote(chg->fcc_votable, FCC_MAX_RESULT_VOTER, true, fcc_ua);
}
static int smblib_fcc_vote_callback(struct votable *votable, void *data,
@@ -731,6 +731,17 @@ static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
return 0;
}
+
+static int smblib_pl_enable_indirect_vote_callback(struct votable *votable,
+ void *data, int chg_enable, const char *client)
+{
+ struct smb_charger *chg = data;
+
+ vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, !chg_enable, 0);
+
+ return 0;
+}
+
/*****************
* OTG REGULATOR *
*****************/
@@ -1144,13 +1155,14 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg,
chg->system_temp_level = val->intval;
if (chg->system_temp_level == chg->thermal_levels)
- return vote(chg->chg_disable_votable, THERMAL_DAEMON, true, 0);
+ return vote(chg->chg_disable_votable,
+ THERMAL_DAEMON_VOTER, true, 0);
- vote(chg->chg_disable_votable, THERMAL_DAEMON, false, 0);
+ vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0);
if (chg->system_temp_level == 0)
- return vote(chg->fcc_votable, THERMAL_DAEMON, false, 0);
+ return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0);
- vote(chg->fcc_votable, THERMAL_DAEMON, true,
+ vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true,
chg->thermal_mitigation[chg->system_temp_level]);
return 0;
}
@@ -1589,7 +1601,11 @@ int smblib_set_prop_usb_voltage_min(struct smb_charger *chg,
return rc;
}
- chg->voltage_min_uv = val->intval;
+ if (chg->mode == PARALLEL_MASTER)
+ vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER,
+ min_uv > MICRO_5V, 0);
+
+ chg->voltage_min_uv = min_uv;
return rc;
}
@@ -1607,7 +1623,7 @@ int smblib_set_prop_usb_voltage_max(struct smb_charger *chg,
return rc;
}
- chg->voltage_max_uv = val->intval;
+ chg->voltage_max_uv = max_uv;
return rc;
}
@@ -1875,49 +1891,23 @@ skip_dpdm_float:
return IRQ_HANDLED;
}
-#define MICRO_5P5V 5500000
-#define USB_WEAK_INPUT_MA 1500000
-static bool is_icl_pl_ready(struct smb_charger *chg)
+#define USB_WEAK_INPUT_MA 1400000
+irqreturn_t smblib_handle_icl_change(int irq, void *data)
{
- union power_supply_propval pval = {0, };
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
int icl_ma;
int rc;
- rc = smblib_get_prop_usb_voltage_now(chg, &pval);
+ rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &icl_ma);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't get prop usb voltage rc=%d\n", rc);
- return false;
- }
-
- if (pval.intval <= MICRO_5P5V) {
- rc = smblib_get_charge_param(chg,
- &chg->param.icl_stat, &icl_ma);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't get ICL status rc=%d\n",
- rc);
- return false;
- }
-
- if (icl_ma < USB_WEAK_INPUT_MA)
- return false;
+ dev_err(chg->dev, "Couldn't get ICL status rc=%d\n", rc);
+ return IRQ_HANDLED;
}
- /*
- * Always enable parallel charging when USB INPUT is higher than 5V
- * regardless of the AICL results. Assume chargers above 5V are strong
- */
-
- return true;
-}
-
-irqreturn_t smblib_handle_icl_change(int irq, void *data)
-{
- struct smb_irq_data *irq_data = data;
- struct smb_charger *chg = irq_data->parent_data;
-
if (chg->mode == PARALLEL_MASTER)
- vote(chg->pl_disable_votable, USBIN_ICL_VOTER,
- !is_icl_pl_ready(chg), 0);
+ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
+ icl_ma >= USB_WEAK_INPUT_MA, 0);
smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
@@ -1954,12 +1944,27 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg,
if (!rising)
return;
+ if (chg->mode == PARALLEL_MASTER)
+ vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
+
/* the APSD done handler will set the USB supply type */
apsd_result = smblib_get_apsd_result(chg);
smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n",
apsd_result->name);
}
+static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
+ bool rising, bool qc_charger)
+{
+ if (rising && !qc_charger) {
+ vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
+ power_supply_changed(chg->usb_psy);
+ }
+
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: smblib_handle_hvdcp_check_timeout %s\n",
+ rising ? "rising" : "falling");
+}
+
/* triggers when HVDCP is detected */
static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
bool rising)
@@ -1991,8 +1996,9 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
vote(chg->pd_allowed_votable, DEFAULT_VOTER, true, 0);
break;
case DCP_CHARGER_BIT:
- schedule_delayed_work(&chg->hvdcp_detect_work,
- msecs_to_jiffies(HVDCP_DET_MS));
+ if (chg->wa_flags & QC_CHARGER_DETECTION_WA_BIT)
+ schedule_delayed_work(&chg->hvdcp_detect_work,
+ msecs_to_jiffies(HVDCP_DET_MS));
break;
default:
break;
@@ -2026,6 +2032,10 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
smblib_handle_hvdcp_detect_done(chg,
(bool)(stat & QC_CHARGER_BIT));
+ smblib_handle_hvdcp_check_timeout(chg,
+ (bool)(stat & HVDCP_CHECK_TIMEOUT_BIT),
+ (bool)(stat & QC_CHARGER_BIT));
+
smblib_handle_hvdcp_3p0_auth_done(chg,
(bool)(stat & QC_AUTH_DONE_STATUS_BIT));
@@ -2079,8 +2089,9 @@ static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
!rising || sink_attached, 0);
if (!rising || sink_attached) {
- /* icl votes to disable parallel charging */
- vote(chg->pl_disable_votable, USBIN_ICL_VOTER, true, 0);
+ /* reset both usbin current and voltage votes */
+ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+ vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
/* reset taper_end voter here */
vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
}
@@ -2105,11 +2116,6 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
}
smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
- if (stat & TYPEC_VBUS_ERROR_STATUS_BIT) {
- dev_err(chg->dev, "IRQ: vbus-error rising\n");
- return IRQ_HANDLED;
- }
-
smblib_handle_typec_cc(chg,
(bool)(stat & CC_ATTACHED_BIT));
smblib_handle_typec_debounce_done(chg,
@@ -2118,6 +2124,10 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
power_supply_changed(chg->usb_psy);
+ if (stat & TYPEC_VBUS_ERROR_STATUS_BIT)
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n",
+ irq_data->name);
+
return IRQ_HANDLED;
}
@@ -2178,8 +2188,7 @@ static void smblib_pl_detect_work(struct work_struct *work)
struct smb_charger *chg = container_of(work, struct smb_charger,
pl_detect_work);
- if (!get_effective_result_locked(chg->pl_disable_votable))
- rerun_election(chg->pl_disable_votable);
+ vote(chg->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);
}
#define MINIMUM_PARALLEL_FCC_UA 500000
@@ -2204,7 +2213,7 @@ static void smblib_pl_taper_work(struct work_struct *work)
}
if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
- vote(chg->awake_votable, PL_VOTER, true, 0);
+ vote(chg->awake_votable, PL_TAPER_WORK_RUNNING_VOTER, true, 0);
/* Reduce the taper percent by 25 percent */
chg->pl.taper_percent = chg->pl.taper_percent
* TAPER_RESIDUAL_PERCENT / 100;
@@ -2218,7 +2227,7 @@ static void smblib_pl_taper_work(struct work_struct *work)
* Master back to Fast Charge, get out of this round of taper reduction
*/
done:
- vote(chg->awake_votable, PL_VOTER, false, 0);
+ vote(chg->awake_votable, PL_TAPER_WORK_RUNNING_VOTER, false, 0);
}
static void clear_hdc_work(struct work_struct *work)
@@ -2320,6 +2329,15 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
+ chg->pl_enable_votable_indirect = create_votable("PL_ENABLE_INDIRECT",
+ VOTE_SET_ANY,
+ smblib_pl_enable_indirect_vote_callback,
+ chg);
+ if (IS_ERR(chg->pl_enable_votable_indirect)) {
+ rc = PTR_ERR(chg->pl_enable_votable_indirect);
+ return rc;
+ }
+
return rc;
}
@@ -2345,6 +2363,10 @@ static void smblib_destroy_votables(struct smb_charger *chg)
destroy_votable(chg->awake_votable);
if (chg->pl_disable_votable)
destroy_votable(chg->pl_disable_votable);
+ if (chg->chg_disable_votable)
+ destroy_votable(chg->chg_disable_votable);
+ if (chg->pl_enable_votable_indirect)
+ destroy_votable(chg->pl_enable_votable_indirect);
}
static void smblib_iio_deinit(struct smb_charger *chg)
@@ -2381,9 +2403,6 @@ int smblib_init(struct smb_charger *chg)
return rc;
}
- chg->bms_psy = power_supply_get_by_name("bms");
- chg->pl.psy = power_supply_get_by_name("parallel");
-
rc = smblib_register_notifier(chg);
if (rc < 0) {
dev_err(chg->dev,
@@ -2391,6 +2410,12 @@ int smblib_init(struct smb_charger *chg)
return rc;
}
+ chg->bms_psy = power_supply_get_by_name("bms");
+ chg->pl.psy = power_supply_get_by_name("parallel");
+ if (chg->pl.psy)
+ vote(chg->pl_disable_votable, PARALLEL_PSY_VOTER,
+ false, 0);
+
break;
case PARALLEL_SLAVE:
break;
diff --git a/drivers/power/qcom-charger/smb-lib.h b/drivers/power/qcom-charger/smb-lib.h
index 1f2457e04ed6..c9732c25dfcd 100644
--- a/drivers/power/qcom-charger/smb-lib.h
+++ b/drivers/power/qcom-charger/smb-lib.h
@@ -24,16 +24,19 @@ enum print_reason {
PR_MISC = BIT(2),
};
-#define DEFAULT_VOTER "DEFAULT_VOTER"
-#define USER_VOTER "USER_VOTER"
-#define PD_VOTER "PD_VOTER"
-#define PL_VOTER "PL_VOTER"
-#define USBIN_ICL_VOTER "USBIN_ICL_VOTER"
-#define CHG_STATE_VOTER "CHG_STATE_VOTER"
-#define TYPEC_SRC_VOTER "TYPEC_SRC_VOTER"
-#define TAPER_END_VOTER "TAPER_END_VOTER"
-#define FCC_MAX_RESULT "FCC_MAX_RESULT"
-#define THERMAL_DAEMON "THERMAL_DAEMON"
+#define DEFAULT_VOTER "DEFAULT_VOTER"
+#define USER_VOTER "USER_VOTER"
+#define PD_VOTER "PD_VOTER"
+#define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER"
+#define PARALLEL_PSY_VOTER "PARALLEL_PSY_VOTER"
+#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
+#define USBIN_I_VOTER "USBIN_I_VOTER"
+#define USBIN_V_VOTER "USBIN_V_VOTER"
+#define CHG_STATE_VOTER "CHG_STATE_VOTER"
+#define TYPEC_SRC_VOTER "TYPEC_SRC_VOTER"
+#define TAPER_END_VOTER "TAPER_END_VOTER"
+#define FCC_MAX_RESULT_VOTER "FCC_MAX_RESULT_VOTER"
+#define THERMAL_DAEMON_VOTER "THERMAL_DAEMON_VOTER"
enum smb_mode {
PARALLEL_MASTER = 0,
@@ -41,6 +44,10 @@ enum smb_mode {
NUM_MODES,
};
+enum {
+ QC_CHARGER_DETECTION_WA_BIT = BIT(0),
+};
+
struct smb_regulator {
struct regulator_dev *rdev;
struct regulator_desc rdesc;
@@ -139,6 +146,7 @@ struct smb_charger {
struct votable *awake_votable;
struct votable *pl_disable_votable;
struct votable *chg_disable_votable;
+ struct votable *pl_enable_votable_indirect;
/* work */
struct work_struct bms_update_work;
diff --git a/drivers/power/qcom-charger/smb-reg.h b/drivers/power/qcom-charger/smb-reg.h
index 4a50d2fcbf97..c4ad72e254f9 100644
--- a/drivers/power/qcom-charger/smb-reg.h
+++ b/drivers/power/qcom-charger/smb-reg.h
@@ -427,7 +427,7 @@ enum {
#define APSD_STATUS_REG (USBIN_BASE + 0x07)
#define APSD_STATUS_7_BIT BIT(7)
-#define APSD_STATUS_6_BIT BIT(6)
+#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)