Merge "power: smb-lib: start CC2 removal WA when VBUS is low"
This commit is contained in:
commit
fe484ee85a
2 changed files with 93 additions and 117 deletions
|
@ -2353,16 +2353,7 @@ int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
|
|||
int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int rc;
|
||||
u8 ctrl;
|
||||
|
||||
rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
val->intval = ctrl & EXIT_SNK_BASED_ON_CC_BIT;
|
||||
val->intval = chg->pd_hard_reset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2744,88 +2735,70 @@ static struct reg_info cc2_detach_settings[] = {
|
|||
|
||||
static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
|
||||
{
|
||||
int rc = 0;
|
||||
union power_supply_propval cc2_val = {0, };
|
||||
int rc, ccout, ufp_mode;
|
||||
u8 stat;
|
||||
|
||||
if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
|
||||
return rc;
|
||||
return 0;
|
||||
|
||||
if (chg->cc2_sink_detach_flag != CC2_SINK_NONE)
|
||||
return rc;
|
||||
if (chg->cc2_detach_wa_active)
|
||||
return 0;
|
||||
|
||||
rc = smblib_get_prop_typec_cc_orientation(chg, &cc2_val);
|
||||
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't get cc orientation rc=%d\n", rc);
|
||||
smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
if (cc2_val.intval == 1)
|
||||
return rc;
|
||||
ccout = (stat & CC_ATTACHED_BIT) ?
|
||||
(!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
|
||||
ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
|
||||
!(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
|
||||
|
||||
rc = smblib_get_prop_typec_mode(chg, &cc2_val);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
if (ccout != 2)
|
||||
return 0;
|
||||
|
||||
switch (cc2_val.intval) {
|
||||
case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
|
||||
smblib_reg_block_update(chg, cc2_detach_settings);
|
||||
chg->cc2_sink_detach_flag = CC2_SINK_STD;
|
||||
schedule_work(&chg->rdstd_cc2_detach_work);
|
||||
break;
|
||||
case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
|
||||
case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
|
||||
chg->cc2_sink_detach_flag = CC2_SINK_MEDIUM_HIGH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!ufp_mode)
|
||||
return 0;
|
||||
|
||||
chg->cc2_detach_wa_active = true;
|
||||
/* The CC2 removal WA will cause a type-c-change IRQ storm */
|
||||
smblib_reg_block_update(chg, cc2_detach_settings);
|
||||
schedule_work(&chg->rdstd_cc2_detach_work);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
|
||||
return rc;
|
||||
return 0;
|
||||
|
||||
if (chg->cc2_sink_detach_flag == CC2_SINK_STD) {
|
||||
cancel_work_sync(&chg->rdstd_cc2_detach_work);
|
||||
smblib_reg_block_restore(chg, cc2_detach_settings);
|
||||
}
|
||||
if (!chg->cc2_detach_wa_active)
|
||||
return 0;
|
||||
|
||||
chg->cc2_sink_detach_flag = CC2_SINK_NONE;
|
||||
|
||||
return rc;
|
||||
chg->cc2_detach_wa_active = false;
|
||||
cancel_work_sync(&chg->rdstd_cc2_detach_work);
|
||||
smblib_reg_block_restore(chg, cc2_detach_settings);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
if (chg->pd_hard_reset == val->intval)
|
||||
return rc;
|
||||
|
||||
chg->pd_hard_reset = val->intval;
|
||||
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
|
||||
EXIT_SNK_BASED_ON_CC_BIT,
|
||||
(val->intval) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Could not set EXIT_SNK_BASED_ON_CC rc=%d\n",
|
||||
EXIT_SNK_BASED_ON_CC_BIT,
|
||||
(chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
|
||||
if (rc < 0)
|
||||
smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
|
||||
rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, val->intval, 0);
|
||||
|
||||
if (val->intval)
|
||||
rc = smblib_cc2_sink_removal_enter(chg);
|
||||
else
|
||||
rc = smblib_cc2_sink_removal_exit(chg);
|
||||
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Could not detect cc2 removal rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
|
||||
chg->pd_hard_reset, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -3132,6 +3105,23 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
|
||||
{
|
||||
if (!vbus_rising) {
|
||||
smblib_update_usb_type(chg);
|
||||
extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
|
||||
smblib_uusb_removal(chg);
|
||||
}
|
||||
}
|
||||
|
||||
static void smblib_typec_usb_plugin(struct smb_charger *chg, bool vbus_rising)
|
||||
{
|
||||
if (vbus_rising)
|
||||
smblib_cc2_sink_removal_exit(chg);
|
||||
else
|
||||
smblib_cc2_sink_removal_enter(chg);
|
||||
}
|
||||
|
||||
#define PL_DELAY_MS 30000
|
||||
irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
|
||||
{
|
||||
|
@ -3148,9 +3138,8 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
|
|||
}
|
||||
|
||||
vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
|
||||
smblib_set_opt_freq_buck(chg,
|
||||
vbus_rising ? chg->chg_freq.freq_5V :
|
||||
chg->chg_freq.freq_removal);
|
||||
smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
|
||||
chg->chg_freq.freq_removal);
|
||||
|
||||
/* fetch the DPDM regulator */
|
||||
if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
|
||||
|
@ -3187,14 +3176,13 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
|
|||
smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
if (chg->micro_usb_mode) {
|
||||
smblib_update_usb_type(chg);
|
||||
extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
|
||||
smblib_uusb_removal(chg);
|
||||
}
|
||||
}
|
||||
|
||||
if (chg->micro_usb_mode)
|
||||
smblib_micro_usb_plugin(chg, vbus_rising);
|
||||
else
|
||||
smblib_typec_usb_plugin(chg, vbus_rising);
|
||||
|
||||
power_supply_changed(chg->usb_psy);
|
||||
smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
|
||||
irq_data->name, vbus_rising ? "attached" : "detached");
|
||||
|
@ -3615,6 +3603,8 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
|
|||
{
|
||||
int rc;
|
||||
|
||||
chg->cc2_detach_wa_active = false;
|
||||
|
||||
cancel_delayed_work_sync(&chg->pl_enable_work);
|
||||
vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
|
||||
vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
|
||||
|
@ -3699,24 +3689,6 @@ static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
|
|||
if (rc < 0)
|
||||
smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
|
||||
|
||||
/*
|
||||
* HW BUG - after cable is removed, medium or high rd reading
|
||||
* falls to std. Use it for signal of typec cc detachment in
|
||||
* software WA.
|
||||
*/
|
||||
if (chg->cc2_sink_detach_flag == CC2_SINK_MEDIUM_HIGH
|
||||
&& pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
|
||||
|
||||
chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
|
||||
|
||||
rc = smblib_masked_write(chg,
|
||||
TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
|
||||
EXIT_SNK_BASED_ON_CC_BIT, 0);
|
||||
if (rc < 0)
|
||||
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]);
|
||||
|
@ -3753,10 +3725,6 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
|
|||
if (chg->micro_usb_mode)
|
||||
return smblib_handle_usb_typec_change_for_uusb(chg);
|
||||
|
||||
/* WA - not when PD hard_reset WIP on cc2 in sink mode */
|
||||
if (chg->cc2_sink_detach_flag == CC2_SINK_STD)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
|
||||
|
@ -3773,6 +3741,13 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
|
|||
sink_attached = (bool)(stat4 & UFP_DFP_MODE_STATUS_BIT);
|
||||
legacy_cable = (bool)(stat5 & TYPEC_LEGACY_CABLE_STATUS_BIT);
|
||||
|
||||
if (chg->cc2_detach_wa_active) {
|
||||
smblib_dbg(chg, PR_INTERRUPT, "Ignoring cc2_wrkarnd=%d dd=%d\n",
|
||||
chg->cc2_detach_wa_active,
|
||||
debounce_done);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
smblib_handle_typec_debounce_done(chg,
|
||||
debounce_done, sink_attached, legacy_cable);
|
||||
|
||||
|
@ -3910,11 +3885,14 @@ static void clear_hdc_work(struct work_struct *work)
|
|||
static void rdstd_cc2_detach_work(struct work_struct *work)
|
||||
{
|
||||
int rc;
|
||||
u8 stat;
|
||||
u8 stat4, stat5;
|
||||
struct smb_irq_data irq_data = {NULL, "cc2-removal-workaround"};
|
||||
struct smb_charger *chg = container_of(work, struct smb_charger,
|
||||
rdstd_cc2_detach_work);
|
||||
|
||||
if (!chg->cc2_detach_wa_active)
|
||||
return;
|
||||
|
||||
/*
|
||||
* WA steps -
|
||||
* 1. Enable both UFP and DFP, wait for 10ms.
|
||||
|
@ -3922,7 +3900,7 @@ static void rdstd_cc2_detach_work(struct work_struct *work)
|
|||
* 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
|
||||
* and TIMER_STAGE bits are gone, otherwise repeat all by
|
||||
* work rescheduling.
|
||||
* Note, work will be cancelled when pd_hard_reset is 0.
|
||||
* Note, work will be cancelled when USB_PLUGIN rises.
|
||||
*/
|
||||
|
||||
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
|
||||
|
@ -3945,30 +3923,34 @@ static void rdstd_cc2_detach_work(struct work_struct *work)
|
|||
|
||||
usleep_range(30000, 31000);
|
||||
|
||||
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
|
||||
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
|
||||
if (rc < 0) {
|
||||
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;
|
||||
}
|
||||
if (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
|
||||
goto rerun;
|
||||
|
||||
rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
|
||||
rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg,
|
||||
"Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
|
||||
return;
|
||||
}
|
||||
if (stat & TIMER_STAGE_2_BIT)
|
||||
goto rerun;
|
||||
|
||||
/* Bingo, cc2 removal detected */
|
||||
if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
|
||||
|| (stat5 & TIMER_STAGE_2_BIT)) {
|
||||
smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
|
||||
(int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
|
||||
(int)(stat5 & TIMER_STAGE_2_BIT));
|
||||
goto rerun;
|
||||
}
|
||||
|
||||
smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
|
||||
chg->cc2_detach_wa_active = false;
|
||||
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
|
||||
EXIT_SNK_BASED_ON_CC_BIT, 0);
|
||||
smblib_reg_block_restore(chg, cc2_detach_settings);
|
||||
chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
|
||||
irq_data.parent_data = chg;
|
||||
smblib_handle_usb_typec_change(0, &irq_data);
|
||||
|
||||
return;
|
||||
|
||||
rerun:
|
||||
|
|
|
@ -71,13 +71,6 @@ enum smb_mode {
|
|||
NUM_MODES,
|
||||
};
|
||||
|
||||
enum cc2_sink_type {
|
||||
CC2_SINK_NONE = 0,
|
||||
CC2_SINK_STD,
|
||||
CC2_SINK_MEDIUM_HIGH,
|
||||
CC2_SINK_WA_DONE,
|
||||
};
|
||||
|
||||
enum {
|
||||
QC_CHARGER_DETECTION_WA_BIT = BIT(0),
|
||||
BOOST_BACK_WA = BIT(1),
|
||||
|
@ -313,10 +306,11 @@ struct smb_charger {
|
|||
int default_icl_ua;
|
||||
int otg_cl_ua;
|
||||
bool uusb_apsd_rerun_done;
|
||||
bool pd_hard_reset;
|
||||
|
||||
/* workaround flag */
|
||||
u32 wa_flags;
|
||||
enum cc2_sink_type cc2_sink_detach_flag;
|
||||
bool cc2_detach_wa_active;
|
||||
int boost_current_ua;
|
||||
int temp_speed_reading_count;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue