power: supply: qcom: use typec mode instead of debounce done

When the CC state change IRQ fires on USB removal the debounce done
status may still be high, and the removal cleanup will not be called.
Use the UFP/DFP status bits to determine whether the CC lines are
present or not instead.

While at it cache the CC state so it doesn't have to be derived
everywhere it is needed. The status bits are already cached, so there
should be no functional difference.

Change-Id: Ifb89c78a032ae9d38fbc8c281518698941e131c2
Signed-off-by: Nicholas Troast <ntroast@codeaurora.org>
This commit is contained in:
Nicholas Troast 2017-04-12 12:38:18 -07:00
parent a5706c4fda
commit 841a455179
5 changed files with 45 additions and 92 deletions

View file

@ -455,8 +455,7 @@ static int smb2_usb_get_prop(struct power_supply *psy,
if (!val->intval) if (!val->intval)
break; break;
rc = smblib_get_prop_typec_mode(chg, val); if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
chg->micro_usb_mode) && chg->micro_usb_mode) &&
chg->real_charger_type == POWER_SUPPLY_TYPE_USB) chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
val->intval = 0; val->intval = 0;
@ -493,7 +492,7 @@ static int smb2_usb_get_prop(struct power_supply *psy,
else if (chip->bad_part) else if (chip->bad_part)
val->intval = POWER_SUPPLY_TYPEC_SOURCE_DEFAULT; val->intval = POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
else else
rc = smblib_get_prop_typec_mode(chg, val); val->intval = chg->typec_mode;
break; break;
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE: case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
if (chg->micro_usb_mode) if (chg->micro_usb_mode)
@ -678,8 +677,7 @@ static int smb2_usb_port_get_prop(struct power_supply *psy,
if (!val->intval) if (!val->intval)
break; break;
rc = smblib_get_prop_typec_mode(chg, val); if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
if ((val->intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT ||
chg->micro_usb_mode) && chg->micro_usb_mode) &&
chg->real_charger_type == POWER_SUPPLY_TYPE_USB) chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
val->intval = 1; val->intval = 1;

View file

@ -841,7 +841,6 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
{ {
int rc = 0; int rc = 0;
bool override; bool override;
union power_supply_propval pval;
/* suspend and return if 25mA or less is requested */ /* suspend and return if 25mA or less is requested */
if (icl_ua < USBIN_25MA) if (icl_ua < USBIN_25MA)
@ -851,14 +850,8 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua)
if (icl_ua == INT_MAX) if (icl_ua == INT_MAX)
goto override_suspend_config; goto override_suspend_config;
rc = smblib_get_prop_typec_mode(chg, &pval);
if (rc < 0) {
smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
goto enable_icl_changed_interrupt;
}
/* configure current */ /* configure current */
if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
&& (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) { && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) {
rc = set_sdp_current(chg, icl_ua); rc = set_sdp_current(chg, icl_ua);
if (rc < 0) { if (rc < 0) {
@ -880,7 +873,7 @@ override_suspend_config:
if (icl_ua == INT_MAX) { if (icl_ua == INT_MAX) {
/* remove override if no voters - hw defaults is desired */ /* remove override if no voters - hw defaults is desired */
override = false; override = false;
} else if (pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) { } else if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
/* For std cable with type = SDP never override */ /* For std cable with type = SDP never override */
override = false; override = false;
@ -920,15 +913,8 @@ int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua)
int rc = 0; int rc = 0;
u8 load_cfg; u8 load_cfg;
bool override; bool override;
union power_supply_propval pval;
rc = smblib_get_prop_typec_mode(chg, &pval); if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
if (rc < 0) {
smblib_err(chg, "Couldn't get typeC mode rc = %d\n", rc);
return rc;
}
if ((pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT
|| chg->micro_usb_mode) || chg->micro_usb_mode)
&& (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) { && (chg->usb_psy_desc.type == POWER_SUPPLY_TYPE_USB)) {
rc = get_sdp_current(chg, icl_ua); rc = get_sdp_current(chg, icl_ua);
@ -2219,8 +2205,6 @@ static const char * const smblib_typec_mode_name[] = {
static int smblib_get_prop_ufp_mode(struct smb_charger *chg) static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
{ {
switch (chg->typec_status[0]) { switch (chg->typec_status[0]) {
case 0:
return POWER_SUPPLY_TYPEC_NONE;
case UFP_TYPEC_RDSTD_BIT: case UFP_TYPEC_RDSTD_BIT:
return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT; return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT;
case UFP_TYPEC_RD1P5_BIT: case UFP_TYPEC_RD1P5_BIT:
@ -2231,7 +2215,7 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
break; break;
} }
return POWER_SUPPLY_TYPEC_NON_COMPLIANT; return POWER_SUPPLY_TYPEC_NONE;
} }
static int smblib_get_prop_dfp_mode(struct smb_charger *chg) static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
@ -2245,8 +2229,6 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE; return POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE;
case DFP_RD_OPEN_BIT: case DFP_RD_OPEN_BIT:
return POWER_SUPPLY_TYPEC_SINK; return POWER_SUPPLY_TYPEC_SINK;
case DFP_RA_OPEN_BIT:
return POWER_SUPPLY_TYPEC_POWERED_CABLE_ONLY;
default: default:
break; break;
} }
@ -2254,20 +2236,12 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
return POWER_SUPPLY_TYPEC_NONE; return POWER_SUPPLY_TYPEC_NONE;
} }
int smblib_get_prop_typec_mode(struct smb_charger *chg, static int smblib_get_prop_typec_mode(struct smb_charger *chg)
union power_supply_propval *val)
{ {
if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
val->intval = POWER_SUPPLY_TYPEC_NONE;
return 0;
}
if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
val->intval = smblib_get_prop_dfp_mode(chg); return smblib_get_prop_dfp_mode(chg);
else else
val->intval = smblib_get_prop_ufp_mode(chg); return smblib_get_prop_ufp_mode(chg);
return 0;
} }
int smblib_get_prop_typec_power_role(struct smb_charger *chg, int smblib_get_prop_typec_power_role(struct smb_charger *chg,
@ -2555,24 +2529,12 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
const union power_supply_propval *val) const union power_supply_propval *val)
{ {
int rc; int rc;
bool orientation, cc_debounced, sink_attached, hvdcp; bool orientation, sink_attached, hvdcp;
u8 stat; u8 stat;
if (!get_effective_result(chg->pd_allowed_votable)) if (!get_effective_result(chg->pd_allowed_votable))
return -EINVAL; return -EINVAL;
rc = smblib_read(chg, APSD_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
return rc;
}
cc_debounced = (bool)
(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
sink_attached = (bool)
(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
hvdcp = stat & QC_CHARGER_BIT;
chg->pd_active = val->intval; chg->pd_active = val->intval;
if (chg->pd_active) { if (chg->pd_active) {
vote(chg->apsd_disable_votable, PD_VOTER, true, 0); vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
@ -2624,6 +2586,14 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
if (rc < 0) if (rc < 0)
smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc); smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
} else { } else {
rc = smblib_read(chg, APSD_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg, "Couldn't read APSD status rc=%d\n",
rc);
return rc;
}
hvdcp = stat & QC_CHARGER_BIT;
vote(chg->apsd_disable_votable, PD_VOTER, false, 0); vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
vote(chg->pd_allowed_votable, PD_VOTER, true, 0); vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
@ -2643,8 +2613,8 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
* and data could be interrupted. Non-legacy DCP could also draw * and data could be interrupted. Non-legacy DCP could also draw
* more, but it may impact compliance. * more, but it may impact compliance.
*/ */
if (!chg->typec_legacy_valid && cc_debounced && sink_attached = chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT;
!sink_attached && hvdcp) if (!chg->typec_legacy_valid && !sink_attached && hvdcp)
schedule_work(&chg->legacy_detection_work); schedule_work(&chg->legacy_detection_work);
} }
@ -2766,6 +2736,7 @@ static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return rc; return rc;
} }
ccout = (stat & CC_ATTACHED_BIT) ? ccout = (stat & CC_ATTACHED_BIT) ?
(!!(stat & CC_ORIENTATION_BIT) + 1) : 0; (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ? ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
@ -3684,8 +3655,7 @@ unlock:
smblib_update_usb_type(chg); smblib_update_usb_type(chg);
} }
static void smblib_handle_typec_insertion(struct smb_charger *chg, static void smblib_handle_typec_insertion(struct smb_charger *chg)
bool sink_attached)
{ {
int rc; int rc;
@ -3697,45 +3667,37 @@ static void smblib_handle_typec_insertion(struct smb_charger *chg,
smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n", smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
rc); rc);
if (sink_attached) if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
typec_sink_insertion(chg); typec_sink_insertion(chg);
else else
typec_sink_removal(chg); typec_sink_removal(chg);
} }
static void smblib_handle_typec_debounce_done(struct smb_charger *chg, static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
bool rising, bool sink_attached)
{ {
int rc; if (chg->pr_swap_in_progress)
union power_supply_propval pval = {0, }; return;
if (rising) { chg->typec_mode = smblib_get_prop_typec_mode(chg);
if (!chg->typec_present && !chg->pr_swap_in_progress) { if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
chg->typec_present = true; chg->typec_present = true;
smblib_dbg(chg, PR_MISC, "TypeC insertion\n"); smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
smblib_handle_typec_insertion(chg, sink_attached); smblib_typec_mode_name[chg->typec_mode]);
} smblib_handle_typec_insertion(chg);
} else { } else if (chg->typec_present &&
if (chg->typec_present && !chg->pr_swap_in_progress) { chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
chg->typec_present = false; chg->typec_present = false;
smblib_dbg(chg, PR_MISC, "TypeC removal\n"); smblib_dbg(chg, PR_MISC, "TypeC removal\n");
smblib_handle_typec_removal(chg); smblib_handle_typec_removal(chg);
}
} }
rc = smblib_get_prop_typec_mode(chg, &pval); smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
if (rc < 0) smblib_typec_mode_name[chg->typec_mode]);
smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
rising ? "rising" : "falling",
smblib_typec_mode_name[pval.intval]);
} }
static void smblib_usb_typec_change(struct smb_charger *chg) static void smblib_usb_typec_change(struct smb_charger *chg)
{ {
int rc; int rc;
bool debounce_done, sink_attached;
rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG, rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
chg->typec_status, 5); chg->typec_status, 5);
@ -3744,12 +3706,7 @@ static void smblib_usb_typec_change(struct smb_charger *chg)
return; return;
} }
debounce_done = smblib_handle_typec_cc_state_change(chg);
(bool)(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
sink_attached =
(bool)(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached);
if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT) if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n"); smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
@ -4264,8 +4221,7 @@ static void smblib_legacy_detection_work(struct work_struct *work)
chg->typec_legacy_valid = true; chg->typec_legacy_valid = true;
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT; legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
rp_high = smblib_get_prop_ufp_mode(chg) == rp_high = chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH;
POWER_SUPPLY_TYPEC_SOURCE_HIGH;
if (!legacy || !rp_high) if (!legacy || !rp_high)
vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
false, 0); false, 0);

View file

@ -322,6 +322,7 @@ struct smb_charger {
bool typec_legacy_valid; bool typec_legacy_valid;
int fake_input_current_limited; int fake_input_current_limited;
bool pr_swap_in_progress; bool pr_swap_in_progress;
int typec_mode;
/* workaround flag */ /* workaround flag */
u32 wa_flags; u32 wa_flags;
@ -453,8 +454,6 @@ int smblib_get_prop_usb_current_now(struct smb_charger *chg,
union power_supply_propval *val); union power_supply_propval *val);
int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg, int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
union power_supply_propval *val); union power_supply_propval *val);
int smblib_get_prop_typec_mode(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_typec_power_role(struct smb_charger *chg, int smblib_get_prop_typec_power_role(struct smb_charger *chg,
union power_supply_propval *val); union power_supply_propval *val);
int smblib_get_prop_pd_allowed(struct smb_charger *chg, int smblib_get_prop_pd_allowed(struct smb_charger *chg,

View file

@ -486,11 +486,11 @@ enum {
#define UFP_TYPEC_OPEN_OPEN_BIT BIT(0) #define UFP_TYPEC_OPEN_OPEN_BIT BIT(0)
#define TYPE_C_STATUS_2_REG (USBIN_BASE + 0x0C) #define TYPE_C_STATUS_2_REG (USBIN_BASE + 0x0C)
#define DFP_TYPEC_MASK 0x8F
#define DFP_RA_OPEN_BIT BIT(7) #define DFP_RA_OPEN_BIT BIT(7)
#define TIMER_STAGE_BIT BIT(6) #define TIMER_STAGE_BIT BIT(6)
#define EXIT_UFP_MODE_BIT BIT(5) #define EXIT_UFP_MODE_BIT BIT(5)
#define EXIT_DFP_MODE_BIT BIT(4) #define EXIT_DFP_MODE_BIT BIT(4)
#define DFP_TYPEC_MASK GENMASK(3, 0)
#define DFP_RD_OPEN_BIT BIT(3) #define DFP_RD_OPEN_BIT BIT(3)
#define DFP_RD_RA_VCONN_BIT BIT(2) #define DFP_RD_RA_VCONN_BIT BIT(2)
#define DFP_RD_RD_BIT BIT(1) #define DFP_RD_RD_BIT BIT(1)

View file

@ -248,7 +248,7 @@ static int smb138x_usb_get_prop(struct power_supply *psy,
val->intval = chg->usb_psy_desc.type; val->intval = chg->usb_psy_desc.type;
break; break;
case POWER_SUPPLY_PROP_TYPEC_MODE: case POWER_SUPPLY_PROP_TYPEC_MODE:
rc = smblib_get_prop_typec_mode(chg, val); val->intval = chg->typec_mode;
break; break;
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE: case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
rc = smblib_get_prop_typec_power_role(chg, val); rc = smblib_get_prop_typec_power_role(chg, val);