Merge "power: smblib: SW implementation of typeC try.SNK"

This commit is contained in:
Linux Build Service Account 2017-10-20 16:49:17 -07:00 committed by Gerrit - the friendly Code Review server
commit 15bfd17433
3 changed files with 175 additions and 2 deletions

View file

@ -188,6 +188,11 @@ static int __weak_chg_icl_ua = 500000;
module_param_named( module_param_named(
weak_chg_icl_ua, __weak_chg_icl_ua, int, S_IRUSR | S_IWUSR); 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_1P5A 1500000
#define MICRO_P1A 100000 #define MICRO_P1A 100000
#define OTG_DEFAULT_DEGLITCH_TIME_MS 50 #define OTG_DEFAULT_DEGLITCH_TIME_MS 50
@ -2236,6 +2241,7 @@ static int smb2_probe(struct platform_device *pdev)
chg->dev = &pdev->dev; chg->dev = &pdev->dev;
chg->param = v1_params; chg->param = v1_params;
chg->debug_mask = &__debug_mask; chg->debug_mask = &__debug_mask;
chg->try_sink_enabled = &__try_sink_enabled;
chg->weak_chg_icl_ua = &__weak_chg_icl_ua; chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
chg->mode = PARALLEL_MASTER; chg->mode = PARALLEL_MASTER;
chg->irq_info = smb2_irqs; chg->irq_info = smb2_irqs;

View file

@ -3734,8 +3734,165 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
return IRQ_HANDLED; 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) 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 /* when a sink is inserted we should not wait on hvdcp timeout to
* enable pd * 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]); 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; int rc;
@ -4029,7 +4186,8 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
return IRQ_HANDLED; 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", smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
chg->cc2_detach_wa_active ? chg->cc2_detach_wa_active ?
"cc2_detach_wa" : "typec_en_dis"); "cc2_detach_wa" : "typec_en_dis");

View file

@ -128,6 +128,12 @@ enum smb_irq_index {
SMB_IRQ_MAX, SMB_IRQ_MAX,
}; };
enum try_sink_exit_mode {
ATTACHED_SRC = 0,
ATTACHED_SINK,
UNATTACHED_SINK,
};
struct smb_irq_info { struct smb_irq_info {
const char *name; const char *name;
const irq_handler_t handler; const irq_handler_t handler;
@ -232,6 +238,7 @@ struct smb_charger {
struct smb_params param; struct smb_params param;
struct smb_iio iio; struct smb_iio iio;
int *debug_mask; int *debug_mask;
int *try_sink_enabled;
enum smb_mode mode; enum smb_mode mode;
struct smb_chg_freq chg_freq; struct smb_chg_freq chg_freq;
int smb_version; int smb_version;
@ -341,6 +348,7 @@ struct smb_charger {
u32 wa_flags; u32 wa_flags;
bool cc2_detach_wa_active; bool cc2_detach_wa_active;
bool typec_en_dis_active; bool typec_en_dis_active;
bool try_sink_active;
int boost_current_ua; int boost_current_ua;
int temp_speed_reading_count; 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); union power_supply_propval *val);
int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
const union power_supply_propval *val); const union power_supply_propval *val);
void smblib_usb_typec_change(struct smb_charger *chg);
int smblib_init(struct smb_charger *chg); int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg);