Merge "power: smb5: update USB source detection sequence" into msm-4.9
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index d3aaf26..5264254 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -177,6 +177,11 @@
debug_mask, __debug_mask, int, 0600
);
+static int __pd_disabled;
+module_param_named(
+ pd_disabled, __pd_disabled, int, 0600
+);
+
static int __weak_chg_icl_ua = 500000;
module_param_named(
weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600
@@ -434,7 +439,6 @@
POWER_SUPPLY_PROP_TYPEC_MODE,
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE,
POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION,
- POWER_SUPPLY_PROP_PD_ALLOWED,
POWER_SUPPLY_PROP_PD_ACTIVE,
POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
@@ -515,9 +519,6 @@
else
rc = smblib_get_prop_typec_cc_orientation(chg, val);
break;
- case POWER_SUPPLY_PROP_PD_ALLOWED:
- rc = smblib_get_prop_pd_allowed(chg, val);
- break;
case POWER_SUPPLY_PROP_PD_ACTIVE:
val->intval = chg->pd_active;
break;
@@ -605,12 +606,6 @@
struct smb_charger *chg = &chip->chg;
int rc = 0;
- mutex_lock(&chg->lock);
- if (!chg->typec_present) {
- rc = -EINVAL;
- goto unlock;
- }
-
switch (psp) {
case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
rc = smblib_set_prop_pd_current_max(chg, val);
@@ -652,8 +647,6 @@
break;
}
-unlock:
- mutex_unlock(&chg->lock);
return rc;
}
@@ -1425,6 +1418,15 @@
{
int rc;
+ /* disable apsd */
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+ HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT,
+ 0);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc);
+ return rc;
+ }
+
rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG,
TYPEC_CCOUT_DETACH_INT_EN_BIT |
TYPEC_CCOUT_ATTACH_INT_EN_BIT);
@@ -1459,14 +1461,6 @@
{
int rc;
- /* configure micro USB mode */
- rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
- EN_MICRO_USB_MODE_BIT, EN_MICRO_USB_MODE_BIT);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't enable micro USB mode rc=%d\n", rc);
- return rc;
- }
-
rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
MICRO_USB_STATE_CHANGE_INT_EN_BIT,
MICRO_USB_STATE_CHANGE_INT_EN_BIT);
@@ -1500,7 +1494,6 @@
&chg->default_icl_ua);
/* Use SW based VBUS control, disable HW autonomous mode */
- /* TODO: auth can be enabled through vote based on APSD flow */
rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
HVDCP_AUTH_ALG_EN_CFG_BIT);
@@ -1537,10 +1530,22 @@
type = !!(val & EN_MICRO_USB_MODE_BIT);
}
- chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB
- : POWER_SUPPLY_CONNECTOR_TYPEC;
pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
+ if (type) {
+ chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB;
+ smblib_rerun_apsd_if_required(chg);
+ rc = smb5_configure_micro_usb(chg);
+ } else {
+ chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC;
+ rc = smb5_configure_typec(chg);
+ }
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
+ return rc;
+ }
+
/*
* PMI632 based hw init:
* - Initialize flash module for PMI632
@@ -1548,8 +1553,6 @@
if (chg->smb_version == PMI632_SUBTYPE)
schgm_flash_init(chg);
- smblib_rerun_apsd_if_required(chg);
-
/* vote 0mA on usb_icl for non battery platforms */
vote(chg->usb_icl_votable,
DEFAULT_VOTER, chip->dt.no_battery, 0);
@@ -1565,12 +1568,6 @@
vote(chg->fv_votable,
BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
chg->batt_profile_fv_uv);
- vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
- true, 0);
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
- true, 0);
- vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER,
- chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0);
/* Some h/w limit maximum supported ICL */
vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
@@ -1594,16 +1591,6 @@
return rc;
}
- if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
- rc = smb5_configure_micro_usb(chg);
- else
- rc = smb5_configure_typec(chg);
- if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
- return rc;
- }
-
/* configure VBUS for software control */
rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
if (rc < 0) {
@@ -1812,11 +1799,21 @@
{
struct smb_irq_data irq_data = {chip, "determine-initial-status"};
struct smb_charger *chg = &chip->chg;
+ union power_supply_propval val;
+ int rc;
+
+ rc = smblib_get_prop_usb_present(chg, &val);
+ if (rc < 0) {
+ pr_err("Couldn't get usb present rc=%d\n", rc);
+ return rc;
+ }
+ chg->early_usb_attach = val.intval;
if (chg->bms_psy)
smblib_suspend_on_debug_battery(chg);
usb_plugin_irq_handler(0, &irq_data);
+ typec_attach_detach_irq_handler(0, &irq_data);
typec_state_change_irq_handler(0, &irq_data);
usb_source_change_irq_handler(0, &irq_data);
chg_state_change_irq_handler(0, &irq_data);
@@ -2008,6 +2005,7 @@
},
[TYPEC_ATTACH_DETACH_IRQ] = {
.name = "typec-attach-detach",
+ .handler = typec_attach_detach_irq_handler,
},
[TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
.name = "typec-legacy-cable-detect",
@@ -2303,6 +2301,7 @@
chg = &chip->chg;
chg->dev = &pdev->dev;
chg->debug_mask = &__debug_mask;
+ chg->pd_disabled = &__pd_disabled;
chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
chg->mode = PARALLEL_MASTER;
chg->irq_info = smb5_irqs;
@@ -2452,6 +2451,10 @@
struct smb5 *chip = platform_get_drvdata(pdev);
struct smb_charger *chg = &chip->chg;
+ /* force enable APSD */
+ smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+ BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
+
smb5_free_interrupts(chg);
smblib_deinit(chg);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index 5345674..1c93bf6 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -663,10 +663,6 @@
cancel_delayed_work_sync(&chg->pl_enable_work);
- rc = smblib_request_dpdm(chg, false);
- if (rc < 0)
- smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);
-
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
if (data) {
@@ -954,18 +950,6 @@
return smblib_set_dc_suspend(chg, (bool)suspend);
}
-static int smblib_pd_disallowed_votable_indirect_callback(
- struct votable *votable, void *data, int disallowed, const char *client)
-{
- struct smb_charger *chg = data;
- int rc;
-
- rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
- !disallowed, 0);
-
- return rc;
-}
-
static int smblib_awake_vote_callback(struct votable *votable, void *data,
int awake, const char *client)
{
@@ -1989,13 +1973,6 @@
return rc;
}
-int smblib_get_prop_pd_allowed(struct smb_charger *chg,
- union power_supply_propval *val)
-{
- val->intval = get_effective_result(chg->pd_allowed_votable);
- return 0;
-}
-
int smblib_get_prop_input_current_settled(struct smb_charger *chg,
union power_supply_propval *val)
{
@@ -2039,13 +2016,7 @@
int smblib_get_pe_start(struct smb_charger *chg,
union power_supply_propval *val)
{
- /*
- * hvdcp timeout voter is the last one to allow pd. Use its vote
- * to indicate start of pe engine
- */
- val->intval
- = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
- APSD_VOTER);
+ val->intval = chg->ok_to_pd;
return 0;
}
@@ -2298,14 +2269,14 @@
return rc;
}
-static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
+int smblib_set_prop_pd_active(struct smb_charger *chg,
+ const union power_supply_propval *val)
{
int rc = 0;
- chg->pd_active = pd_active;
+ chg->pd_active = val->intval;
if (chg->pd_active) {
- vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
/*
@@ -2313,24 +2284,24 @@
* It is guaranteed that pd_active is set prior to
* pd_current_max
*/
- rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
- if (rc < 0)
- smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
- rc);
-
- /* clear USB ICL vote for DCP_VOTER */
- rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
- rc);
-
- /* remove USB_PSY_VOTER */
- rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
+ vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
} else {
- vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+ vote(chg->usb_icl_votable, PD_VOTER, false, 0);
vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
+
+ /* PD hard resets failed, rerun apsd */
+ if (chg->ok_to_pd) {
+ chg->ok_to_pd = false;
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+ HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT,
+ HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't disable APSD rc=%d\n", rc);
+ return rc;
+ }
+ smblib_rerun_apsd(chg);
+ }
}
smblib_update_usb_type(chg);
@@ -2338,15 +2309,6 @@
return rc;
}
-int smblib_set_prop_pd_active(struct smb_charger *chg,
- const union power_supply_propval *val)
-{
- if (!get_effective_result(chg->pd_allowed_votable))
- return -EINVAL;
-
- return __smblib_set_prop_pd_active(chg, val->intval);
-}
-
int smblib_set_prop_ship_mode(struct smb_charger *chg,
const union power_supply_propval *val)
{
@@ -2657,11 +2619,7 @@
static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
{
- if (vbus_rising) {
- /* use the typec flag even though its not typec */
- chg->typec_present = 1;
- } else {
- chg->typec_present = 0;
+ if (!vbus_rising) {
smblib_update_usb_type(chg);
smblib_notify_device_mode(chg, false);
smblib_uusb_removal(chg);
@@ -2764,12 +2722,10 @@
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
- mutex_lock(&chg->lock);
if (chg->pd_hard_reset)
smblib_usb_plugin_hard_reset_locked(chg);
else
smblib_usb_plugin_locked(chg);
- mutex_unlock(&chg->lock);
return IRQ_HANDLED;
}
@@ -2858,8 +2814,6 @@
if (!rising)
return;
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
-
if (chg->mode == PARALLEL_MASTER)
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
@@ -2872,33 +2826,19 @@
static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
bool rising, bool qc_charger)
{
- const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
-
- /* Hold off PD only until hvdcp 2.0 detection timeout */
if (rising) {
/* enable HDC and ICL irq for QC2/3 charger */
if (qc_charger)
vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
else
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
- false, 0);
-
/*
* HVDCP detection timeout done
* If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
+ * enforce DCP ICL if specified
*/
- if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
- /* enforce DCP ICL if specified */
vote(chg->usb_icl_votable, DCP_VOTER,
chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
-
- /*
- * if pd is not allowed, then set pd_active = false right here,
- * so that it starts the hvdcp engine
- */
- if (!get_effective_result(chg->pd_allowed_votable))
- __smblib_set_prop_pd_active(chg, 0);
}
smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__,
@@ -2926,19 +2866,11 @@
case SDP_CHARGER_BIT:
case CDP_CHARGER_BIT:
case FLOAT_CHARGER_BIT:
- /* if not DCP then no hvdcp timeout happens. Enable pd here */
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
- false, 0);
if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
|| chg->use_extcon)
smblib_notify_device_mode(chg, true);
break;
case OCP_CHARGER_BIT:
- vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
- /* if not DCP then no hvdcp timeout happens, Enable pd here. */
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
- false, 0);
- break;
case DCP_CHARGER_BIT:
vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
break;
@@ -2957,6 +2889,14 @@
int rc = 0;
u8 stat;
+ /*
+ * Prepared to run PD or PD is active. At this moment, APSD is disabled,
+ * but there still can be irq on apsd_done from previously unfinished
+ * APSD run, skip it.
+ */
+ if (chg->ok_to_pd)
+ return IRQ_HANDLED;
+
rc = smblib_read(chg, APSD_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
@@ -3011,32 +2951,68 @@
static void typec_sink_insertion(struct smb_charger *chg)
{
- /* when a sink is inserted we should not wait on hvdcp timeout to
- * enable pd
- */
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
+ vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
+
if (chg->use_extcon) {
smblib_notify_usb_host(chg, true);
chg->otg_present = true;
}
+
+ if (!chg->pr_swap_in_progress)
+ chg->ok_to_pd = !(*chg->pd_disabled) || chg->early_usb_attach;
+}
+
+static void typec_src_insertion(struct smb_charger *chg)
+{
+ int rc = 0;
+ u8 stat;
+
+ if (chg->pr_swap_in_progress)
+ return;
+
+ rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n",
+ rc);
+ return;
+ }
+
+ chg->typec_legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
+ chg->ok_to_pd = !(chg->typec_legacy || *chg->pd_disabled)
+ || chg->early_usb_attach;
+ if (!chg->ok_to_pd) {
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+ HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT,
+ HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't disable APSD rc=%d\n", rc);
+ return;
+ }
+ smblib_rerun_apsd(chg);
+ }
}
static void typec_sink_removal(struct smb_charger *chg)
{
- smblib_set_charge_param(chg, &chg->param.freq_switcher,
- chg->chg_freq.freq_above_otg_threshold);
- chg->boost_current_ua = 0;
+ vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
}
-static void smblib_handle_typec_removal(struct smb_charger *chg)
+static void typec_src_removal(struct smb_charger *chg)
{
int rc;
struct smb_irq_data *data;
struct storm_watch *wdata;
- rc = smblib_request_dpdm(chg, false);
+ /* disable apsd */
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+ HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT,
+ 0);
if (rc < 0)
- smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
+ smblib_err(chg,
+ "Couldn't disable APSD rc=%d\n", rc);
+
+ smblib_update_usb_type(chg);
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
@@ -3062,11 +3038,6 @@
vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, false, 0);
- /* reset power delivery voters */
- vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
- vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0);
-
/* reset usb irq voters */
vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
@@ -3078,14 +3049,10 @@
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
- chg->vconn_attempts = 0;
- chg->otg_attempts = 0;
chg->pulse_cnt = 0;
chg->usb_icl_delta_ua = 0;
chg->voltage_min_uv = MICRO_5V;
chg->voltage_max_uv = MICRO_5V;
- chg->pd_active = 0;
- chg->pd_hard_reset = 0;
/* write back the default FLOAT charger configuration */
rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
@@ -3094,12 +3061,6 @@
smblib_err(chg, "Couldn't write float charger options rc=%d\n",
rc);
- /* reset back to 103mS tCC debounce */
- rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG,
- REDUCE_TCCDEBOUNCE_TO_2MS_BIT, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
-
/* reconfigure allowed voltage for HVDCP */
rc = smblib_set_adapter_allowance(chg,
USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
@@ -3107,58 +3068,15 @@
smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
rc);
- /* enable DRP */
- rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
- TYPEC_POWER_ROLE_CMD_MASK, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
-
- /* HW controlled CC_OUT */
- rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG,
- TYPEC_CCOUT_SRC_BIT, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
-
- /* clear exit sink based on cc */
- rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
- EXIT_SNK_BASED_ON_CC_BIT, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
- rc);
-
- typec_sink_removal(chg);
- smblib_update_usb_type(chg);
-
if (chg->use_extcon) {
if (chg->otg_present)
smblib_notify_usb_host(chg, false);
else
smblib_notify_device_mode(chg, false);
}
+
chg->otg_present = false;
-}
-
-static void smblib_handle_typec_insertion(struct smb_charger *chg)
-{
- int rc;
- u8 stat;
-
- vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
-
- rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return;
- }
-
- if (stat & SNK_SRC_MODE_BIT) {
- typec_sink_insertion(chg);
- } else {
- rc = smblib_request_dpdm(chg, true);
- if (rc < 0)
- smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
- typec_sink_removal(chg);
- }
+ chg->typec_legacy = false;
}
static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
@@ -3200,66 +3118,6 @@
vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, true, rp_ua);
}
-static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
-{
- u8 stat;
- int typec_mode, rc;
-
- if (chg->pr_swap_in_progress)
- return;
-
- typec_mode = smblib_get_prop_typec_mode(chg);
- if (chg->typec_present && (typec_mode != chg->typec_mode))
- smblib_handle_rp_change(chg, typec_mode);
-
- chg->typec_mode = typec_mode;
-
- if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
- chg->typec_present = true;
- smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
- smblib_typec_mode_name[chg->typec_mode]);
- smblib_handle_typec_insertion(chg);
- } else if (chg->typec_present &&
- chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
- chg->typec_present = false;
- smblib_dbg(chg, PR_MISC, "TypeC removal\n");
- smblib_handle_typec_removal(chg);
- }
-
- rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return;
- }
- /* suspend usb if sink */
- if ((stat & SNK_SRC_MODE_BIT) && chg->typec_present)
- vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
- else
- vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
-
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
- smblib_typec_mode_name[chg->typec_mode]);
-}
-
-static void smblib_usb_typec_change(struct smb_charger *chg)
-{
- int rc;
- u8 stat;
-
- smblib_handle_typec_cc_state_change(chg);
-
- rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return;
- }
-
- if (stat & TYPEC_VBUS_ERROR_STATUS_BIT)
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
-
- power_supply_changed(chg->usb_psy);
-}
-
irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
@@ -3281,17 +3139,81 @@
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
+ int typec_mode;
- if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
- || chg->pr_swap_in_progress) {
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
smblib_dbg(chg, PR_INTERRUPT,
- "Ignoring since pr_swap_in_progress\n");
+ "Ignoring for micro USB\n");
return IRQ_HANDLED;
}
- mutex_lock(&chg->lock);
- smblib_usb_typec_change(chg);
- mutex_unlock(&chg->lock);
+ typec_mode = smblib_get_prop_typec_mode(chg);
+ if (chg->sink_src_mode != UNATTACHED_MODE
+ && (typec_mode != chg->typec_mode))
+ smblib_handle_rp_change(chg, typec_mode);
+ chg->typec_mode = typec_mode;
+
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
+ smblib_typec_mode_name[chg->typec_mode]);
+
+ power_supply_changed(chg->usb_psy);
+
+ return IRQ_HANDLED;
+}
+
+irqreturn_t typec_attach_detach_irq_handler(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+ u8 stat;
+ int rc;
+
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+
+ rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n",
+ rc);
+ return IRQ_HANDLED;
+ }
+
+ if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) {
+ rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n",
+ rc);
+ return IRQ_HANDLED;
+ }
+
+ if (stat & SNK_SRC_MODE_BIT) {
+ chg->sink_src_mode = SRC_MODE;
+ typec_sink_insertion(chg);
+ } else {
+ chg->sink_src_mode = SINK_MODE;
+ typec_src_insertion(chg);
+ }
+
+ } else {
+ switch (chg->sink_src_mode) {
+ case SRC_MODE:
+ typec_sink_removal(chg);
+ break;
+ case SINK_MODE:
+ typec_src_removal(chg);
+ break;
+ default:
+ break;
+ }
+
+ if (!chg->pr_swap_in_progress) {
+ chg->ok_to_pd = false;
+ chg->sink_src_mode = UNATTACHED_MODE;
+ chg->early_usb_attach = false;
+ }
+ }
+
+ power_supply_changed(chg->usb_psy);
+
return IRQ_HANDLED;
}
@@ -3717,23 +3639,6 @@
return rc;
}
- chg->pd_disallowed_votable_indirect
- = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
- smblib_pd_disallowed_votable_indirect_callback, chg);
- if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
- rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
- chg->pd_disallowed_votable_indirect = NULL;
- return rc;
- }
-
- chg->pd_allowed_votable = create_votable("PD_ALLOWED",
- VOTE_SET_ANY, NULL, NULL);
- if (IS_ERR(chg->pd_allowed_votable)) {
- rc = PTR_ERR(chg->pd_allowed_votable);
- chg->pd_allowed_votable = NULL;
- return rc;
- }
-
chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
smblib_awake_vote_callback,
chg);
@@ -3771,10 +3676,6 @@
destroy_votable(chg->dc_suspend_votable);
if (chg->usb_icl_votable)
destroy_votable(chg->usb_icl_votable);
- if (chg->pd_disallowed_votable_indirect)
- destroy_votable(chg->pd_disallowed_votable_indirect);
- if (chg->pd_allowed_votable)
- destroy_votable(chg->pd_allowed_votable);
if (chg->awake_votable)
destroy_votable(chg->awake_votable);
if (chg->chg_disable_votable)
@@ -3786,7 +3687,6 @@
int rc = 0;
mutex_init(&chg->lock);
- mutex_init(&chg->otg_oc_lock);
INIT_WORK(&chg->bms_update_work, bms_update_work);
INIT_WORK(&chg->pl_update_work, pl_update_work);
INIT_WORK(&chg->jeita_update_work, jeita_update_work);
@@ -3799,6 +3699,7 @@
chg->fake_input_current_limited = -EINVAL;
chg->fake_batt_status = -EINVAL;
chg->jeita_configured = false;
+ chg->sink_src_mode = UNATTACHED_MODE;
switch (chg->mode) {
case PARALLEL_MASTER:
diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h
index 5d6d3a6..96bd550 100644
--- a/drivers/power/supply/qcom/smb5-lib.h
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -80,6 +80,12 @@
NUM_MODES,
};
+enum sink_src_mode {
+ SINK_MODE,
+ SRC_MODE,
+ UNATTACHED_MODE,
+};
+
enum {
BOOST_BACK_WA = BIT(0),
};
@@ -259,6 +265,7 @@
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 smb_version;
@@ -269,7 +276,6 @@
/* locks */
struct mutex lock;
struct mutex ps_change_lock;
- struct mutex otg_oc_lock;
/* power supplies */
struct power_supply *batt_psy;
@@ -296,8 +302,6 @@
struct votable *fcc_votable;
struct votable *fv_votable;
struct votable *usb_icl_votable;
- struct votable *pd_disallowed_votable_indirect;
- struct votable *pd_allowed_votable;
struct votable *awake_votable;
struct votable *pl_disable_votable;
struct votable *chg_disable_votable;
@@ -315,10 +319,17 @@
struct delayed_work uusb_otg_work;
struct delayed_work bb_removal_work;
- /* cached status */
+ /* pd */
int voltage_min_uv;
int voltage_max_uv;
int pd_active;
+ bool pd_hard_reset;
+ bool pr_swap_in_progress;
+ bool early_usb_attach;
+ bool ok_to_pd;
+ bool typec_legacy;
+
+ /* cached status */
bool system_suspend_supported;
int boost_threshold_ua;
int system_temp_level;
@@ -334,15 +345,10 @@
int connector_type;
bool otg_en;
bool suspend_input_on_debug_batt;
- int otg_attempts;
- int vconn_attempts;
int default_icl_ua;
int otg_cl_ua;
bool uusb_apsd_rerun_done;
- bool pd_hard_reset;
- bool typec_present;
int fake_input_current_limited;
- bool pr_swap_in_progress;
int typec_mode;
int usb_icl_change_irq_enabled;
u32 jeita_status;
@@ -352,6 +358,7 @@
int hw_max_icl_ua;
int auto_recharge_soc;
bool jeita_configured;
+ enum sink_src_mode sink_src_mode;
/* workaround flag */
u32 wa_flags;
@@ -420,6 +427,7 @@
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 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);
@@ -485,8 +493,6 @@
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_pd_allowed(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,
diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h
index 4d399aa..7a886b0 100644
--- a/drivers/power/supply/qcom/smb5-reg.h
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -215,6 +215,7 @@
#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 FLOAT_OPTIONS_MASK GENMASK(2, 0)
@@ -262,6 +263,9 @@
#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 SNK_SRC_MODE_BIT BIT(6)
#define TYPEC_VBUS_ERROR_STATUS_BIT BIT(4)
@@ -269,6 +273,7 @@
#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)