Merge "power: smblib: SW implementation of typeC try.SNK"
This commit is contained in:
commit
15bfd17433
3 changed files with 175 additions and 2 deletions
|
@ -188,6 +188,11 @@ static int __weak_chg_icl_ua = 500000;
|
|||
module_param_named(
|
||||
weak_chg_icl_ua, __weak_chg_icl_ua, int, S_IRUSR | S_IWUSR);
|
||||
|
||||
static int __try_sink_enabled = 1;
|
||||
module_param_named(
|
||||
try_sink_enabled, __try_sink_enabled, int, 0600
|
||||
);
|
||||
|
||||
#define MICRO_1P5A 1500000
|
||||
#define MICRO_P1A 100000
|
||||
#define OTG_DEFAULT_DEGLITCH_TIME_MS 50
|
||||
|
@ -2236,6 +2241,7 @@ static int smb2_probe(struct platform_device *pdev)
|
|||
chg->dev = &pdev->dev;
|
||||
chg->param = v1_params;
|
||||
chg->debug_mask = &__debug_mask;
|
||||
chg->try_sink_enabled = &__try_sink_enabled;
|
||||
chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
|
||||
chg->mode = PARALLEL_MASTER;
|
||||
chg->irq_info = smb2_irqs;
|
||||
|
|
|
@ -3734,8 +3734,165 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int typec_try_sink(struct smb_charger *chg)
|
||||
{
|
||||
union power_supply_propval val;
|
||||
bool debounce_done, vbus_detected, sink;
|
||||
u8 stat;
|
||||
int exit_mode = ATTACHED_SRC, rc;
|
||||
|
||||
/* ignore typec interrupt while try.snk WIP */
|
||||
chg->try_sink_active = true;
|
||||
|
||||
/* force SNK mode */
|
||||
val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
|
||||
rc = smblib_set_prop_typec_power_role(chg, &val);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
|
||||
goto try_sink_exit;
|
||||
}
|
||||
|
||||
/* reduce Tccdebounce time to ~20ms */
|
||||
rc = smblib_masked_write(chg, MISC_CFG_REG,
|
||||
TCC_DEBOUNCE_20MS_BIT, TCC_DEBOUNCE_20MS_BIT);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
|
||||
goto try_sink_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* give opportunity to the other side to be a SRC,
|
||||
* for tDRPTRY + Tccdebounce time
|
||||
*/
|
||||
msleep(100);
|
||||
|
||||
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
|
||||
rc);
|
||||
goto try_sink_exit;
|
||||
}
|
||||
|
||||
debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
|
||||
|
||||
if (!debounce_done)
|
||||
/*
|
||||
* The other side didn't switch to source, either it
|
||||
* is an adamant sink or is removed go back to showing Rp
|
||||
*/
|
||||
goto try_wait_src;
|
||||
|
||||
/*
|
||||
* We are in force sink mode and the other side has switched to
|
||||
* showing Rp. Config DRP in case the other side removes Rp so we
|
||||
* can quickly (20ms) switch to showing our Rp. Note that the spec
|
||||
* needs us to show Rp for 80mS while the drp DFP residency is just
|
||||
* 54mS. But 54mS is plenty time for us to react and force Rp for
|
||||
* the remaining 26mS.
|
||||
*/
|
||||
val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
|
||||
rc = smblib_set_prop_typec_power_role(chg, &val);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't set DFP mode rc=%d\n",
|
||||
rc);
|
||||
goto try_sink_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* while other side is Rp, wait for VBUS from it; exit if other side
|
||||
* removes Rp
|
||||
*/
|
||||
do {
|
||||
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
|
||||
rc);
|
||||
goto try_sink_exit;
|
||||
}
|
||||
|
||||
debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
|
||||
vbus_detected = stat & TYPEC_VBUS_STATUS_BIT;
|
||||
|
||||
/* Successfully transitioned to ATTACHED.SNK */
|
||||
if (vbus_detected && debounce_done) {
|
||||
exit_mode = ATTACHED_SINK;
|
||||
goto try_sink_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure sink since drp may put us in source if other
|
||||
* side switches back to Rd
|
||||
*/
|
||||
sink = !(stat & UFP_DFP_MODE_STATUS_BIT);
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
} while (debounce_done && sink);
|
||||
|
||||
try_wait_src:
|
||||
/*
|
||||
* Transition to trywait.SRC state. check if other side still wants
|
||||
* to be SNK or has been removed.
|
||||
*/
|
||||
val.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
|
||||
rc = smblib_set_prop_typec_power_role(chg, &val);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
|
||||
goto try_sink_exit;
|
||||
}
|
||||
|
||||
/* Need to be in this state for tDRPTRY time, 75ms~150ms */
|
||||
msleep(80);
|
||||
|
||||
rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
|
||||
if (rc < 0) {
|
||||
smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
|
||||
goto try_sink_exit;
|
||||
}
|
||||
|
||||
debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
|
||||
|
||||
if (debounce_done)
|
||||
/* the other side wants to be a sink */
|
||||
exit_mode = ATTACHED_SRC;
|
||||
else
|
||||
/* the other side is detached */
|
||||
exit_mode = UNATTACHED_SINK;
|
||||
|
||||
try_sink_exit:
|
||||
/* release forcing of SRC/SNK mode */
|
||||
val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
|
||||
rc = smblib_set_prop_typec_power_role(chg, &val);
|
||||
if (rc < 0)
|
||||
smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc);
|
||||
|
||||
/* revert Tccdebounce time back to ~120ms */
|
||||
rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
|
||||
if (rc < 0)
|
||||
smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
|
||||
|
||||
chg->try_sink_active = false;
|
||||
|
||||
return exit_mode;
|
||||
}
|
||||
|
||||
static void typec_sink_insertion(struct smb_charger *chg)
|
||||
{
|
||||
int exit_mode;
|
||||
|
||||
/*
|
||||
* Try.SNK entry status - ATTACHWAIT.SRC state and detected Rd-open
|
||||
* or RD-Ra for TccDebounce time.
|
||||
*/
|
||||
|
||||
if (*chg->try_sink_enabled) {
|
||||
exit_mode = typec_try_sink(chg);
|
||||
|
||||
if (exit_mode != ATTACHED_SRC) {
|
||||
smblib_usb_typec_change(chg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* when a sink is inserted we should not wait on hvdcp timeout to
|
||||
* enable pd
|
||||
*/
|
||||
|
@ -3993,7 +4150,7 @@ static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
|
|||
smblib_typec_mode_name[chg->typec_mode]);
|
||||
}
|
||||
|
||||
static void smblib_usb_typec_change(struct smb_charger *chg)
|
||||
void smblib_usb_typec_change(struct smb_charger *chg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -4029,7 +4186,8 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
|
||||
if (chg->cc2_detach_wa_active || chg->typec_en_dis_active ||
|
||||
chg->try_sink_active) {
|
||||
smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
|
||||
chg->cc2_detach_wa_active ?
|
||||
"cc2_detach_wa" : "typec_en_dis");
|
||||
|
|
|
@ -128,6 +128,12 @@ enum smb_irq_index {
|
|||
SMB_IRQ_MAX,
|
||||
};
|
||||
|
||||
enum try_sink_exit_mode {
|
||||
ATTACHED_SRC = 0,
|
||||
ATTACHED_SINK,
|
||||
UNATTACHED_SINK,
|
||||
};
|
||||
|
||||
struct smb_irq_info {
|
||||
const char *name;
|
||||
const irq_handler_t handler;
|
||||
|
@ -232,6 +238,7 @@ struct smb_charger {
|
|||
struct smb_params param;
|
||||
struct smb_iio iio;
|
||||
int *debug_mask;
|
||||
int *try_sink_enabled;
|
||||
enum smb_mode mode;
|
||||
struct smb_chg_freq chg_freq;
|
||||
int smb_version;
|
||||
|
@ -341,6 +348,7 @@ struct smb_charger {
|
|||
u32 wa_flags;
|
||||
bool cc2_detach_wa_active;
|
||||
bool typec_en_dis_active;
|
||||
bool try_sink_active;
|
||||
int boost_current_ua;
|
||||
int temp_speed_reading_count;
|
||||
|
||||
|
@ -518,6 +526,7 @@ 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);
|
||||
void smblib_usb_typec_change(struct smb_charger *chg);
|
||||
|
||||
int smblib_init(struct smb_charger *chg);
|
||||
int smblib_deinit(struct smb_charger *chg);
|
||||
|
|
Loading…
Add table
Reference in a new issue