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(
|
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;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Reference in a new issue