summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry Yang <harryy@codeaurora.org>2017-09-09 00:09:36 -0700
committerHarry Yang <harryy@codeaurora.org>2017-10-18 18:17:53 -0700
commit7e41812c03ad53256470cb60d147f753546e850b (patch)
treeab63d769977c24b66f00007fcb9fab163dbe578a
parent22b27b16d898716fb43d35bc8459408ce85e0bf7 (diff)
power: smblib: SW implementation of typeC try.SNK
Try.SNK allows a DRP that has a policy based preference to be a Sink when connecting to another DRP to effect a transition from a destined Source role to the Sink role. This is a Software implementation for PMI8998. Exiting from AttachWait.SRC State, a DRP that strongly prefers the Sink role may optionally transition to Try.SNK instead of Attached.SRC. When in the Try.SNK state, the port is querying to determine if the port partner supports the Source role. The port shall then transition to Attached.SNK when the SNK.Rp state is detected for at least tTryCCDebounce and VBUS is detected Alternatively, the port shall transition to TryWait.SRC if SNK.Rp state is not detected tTryCCDebounce. The port shall transition to Attached.SRC when SRC.Rd state is detected on exactly one of the CC pins. The port shall transition to Unattached.SNK after tDRPTry if neither of the CC1 or CC2 pins is in the SRC.Rd state. CRs-Fixed: 1114313 Change-Id: I777332e87df65082333f4e24a61c5ea834784d09 Signed-off-by: Harry Yang <harryy@codeaurora.org>
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c6
-rw-r--r--drivers/power/supply/qcom/smb-lib.c162
-rw-r--r--drivers/power/supply/qcom/smb-lib.h9
3 files changed, 175 insertions, 2 deletions
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index ea205100644d..33f59bcfb781 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -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;
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index df7aabfd7e2e..72d5c31fc216 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -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");
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 19c0d19106d6..f292ca09f532 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -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);