Merge "qcom-charger: WA for typec cc2 sink removal with rdstd"

This commit is contained in:
Linux Build Service Account 2016-11-15 04:07:27 -08:00 committed by Gerrit - the friendly Code Review server
commit 59c99dc4e4
4 changed files with 192 additions and 2 deletions

View file

@ -1296,6 +1296,8 @@ static int smb2_setup_wa_flags(struct smb2 *chip)
chip->chg.wa_flags |= BOOST_BACK_WA; chip->chg.wa_flags |= BOOST_BACK_WA;
if (pmic_rev_id->rev4 == PMICOBALT_V1P1_REV4) /* PMI rev 1.1 */ if (pmic_rev_id->rev4 == PMICOBALT_V1P1_REV4) /* PMI rev 1.1 */
chg->wa_flags |= QC_CHARGER_DETECTION_WA_BIT; chg->wa_flags |= QC_CHARGER_DETECTION_WA_BIT;
if (pmic_rev_id->rev4 == PMICOBALT_V2P0_REV4) /* PMI rev 2.0 */
chg->wa_flags |= TYPEC_CC2_REMOVAL_WA_BIT;
break; break;
default: default:
pr_err("PMIC subtype %d not supported\n", pr_err("PMIC subtype %d not supported\n",

View file

@ -2129,6 +2129,96 @@ int smblib_reg_block_restore(struct smb_charger *chg,
return rc; return rc;
} }
static struct reg_info cc2_detach_settings[] = {
{
.reg = TYPE_C_CFG_2_REG,
.mask = TYPE_C_UFP_MODE_BIT | EN_TRY_SOURCE_MODE_BIT,
.val = TYPE_C_UFP_MODE_BIT,
.desc = "TYPE_C_CFG_2_REG",
},
{
.reg = TYPE_C_CFG_3_REG,
.mask = EN_TRYSINK_MODE_BIT,
.val = 0,
.desc = "TYPE_C_CFG_3_REG",
},
{
.reg = TAPER_TIMER_SEL_CFG_REG,
.mask = TYPEC_SPARE_CFG_BIT,
.val = TYPEC_SPARE_CFG_BIT,
.desc = "TAPER_TIMER_SEL_CFG_REG",
},
{
.reg = TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
.mask = VCONN_EN_ORIENTATION_BIT,
.val = 0,
.desc = "TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG",
},
{
.reg = MISC_CFG_REG,
.mask = TCC_DEBOUNCE_20MS_BIT,
.val = TCC_DEBOUNCE_20MS_BIT,
.desc = "Tccdebounce time"
},
{
},
};
static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
{
int rc = 0;
union power_supply_propval cc2_val = {0, };
if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
return rc;
if (chg->cc2_sink_detach_flag != CC2_SINK_NONE)
return rc;
rc = smblib_get_prop_typec_cc_orientation(chg, &cc2_val);
if (rc < 0) {
smblib_err(chg, "Couldn't get cc orientation rc=%d\n", rc);
return rc;
}
if (cc2_val.intval == 1)
return rc;
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;
}
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;
default:
break;
}
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;
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);
}
chg->cc2_sink_detach_flag = CC2_SINK_NONE;
return rc;
}
int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg, int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
const union power_supply_propval *val) const union power_supply_propval *val)
{ {
@ -2137,9 +2227,24 @@ int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
EXIT_SNK_BASED_ON_CC_BIT, EXIT_SNK_BASED_ON_CC_BIT,
(val->intval) ? EXIT_SNK_BASED_ON_CC_BIT : 0); (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",
rc);
return rc;
}
vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, val->intval, 0); 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;
}
return rc; return rc;
} }
@ -2739,6 +2844,10 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
u8 stat; u8 stat;
bool debounce_done, sink_attached, legacy_cable; bool debounce_done, sink_attached, legacy_cable;
/* 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, &stat); rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
if (rc < 0) { 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);
@ -2923,6 +3032,74 @@ static void clear_hdc_work(struct work_struct *work)
chg->is_hdc = 0; chg->is_hdc = 0;
} }
static void rdstd_cc2_detach_work(struct work_struct *work)
{
int rc;
u8 stat;
struct smb_irq_data irq_data = {NULL, "cc2-removal-workaround"};
struct smb_charger *chg = container_of(work, struct smb_charger,
rdstd_cc2_detach_work);
/*
* WA steps -
* 1. Enable both UFP and DFP, wait for 10ms.
* 2. Disable DFP, wait for 30ms.
* 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.
*/
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
UFP_EN_CMD_BIT | DFP_EN_CMD_BIT);
if (rc < 0) {
smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
return;
}
usleep_range(10000, 11000);
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
UFP_EN_CMD_BIT | DFP_EN_CMD_BIT,
UFP_EN_CMD_BIT);
if (rc < 0) {
smblib_err(chg, "Couldn't write TYPE_C_CTRL_REG rc=%d\n", rc);
return;
}
usleep_range(30000, 31000);
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);
return;
}
if (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
goto rerun;
rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
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 */
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:
schedule_work(&chg->rdstd_cc2_detach_work);
}
static int smblib_create_votables(struct smb_charger *chg) static int smblib_create_votables(struct smb_charger *chg)
{ {
int rc = 0; int rc = 0;
@ -3105,6 +3282,7 @@ int smblib_init(struct smb_charger *chg)
mutex_init(&chg->write_lock); mutex_init(&chg->write_lock);
INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->bms_update_work, bms_update_work);
INIT_WORK(&chg->pl_detect_work, smblib_pl_detect_work); INIT_WORK(&chg->pl_detect_work, smblib_pl_detect_work);
INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work); INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work); INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work);
INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work); INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);

View file

@ -54,9 +54,16 @@ enum smb_mode {
NUM_MODES, NUM_MODES,
}; };
enum cc2_sink_type {
CC2_SINK_NONE = 0,
CC2_SINK_STD,
CC2_SINK_WA_DONE,
};
enum { enum {
QC_CHARGER_DETECTION_WA_BIT = BIT(0), QC_CHARGER_DETECTION_WA_BIT = BIT(0),
BOOST_BACK_WA = BIT(1), BOOST_BACK_WA = BIT(1),
TYPEC_CC2_REMOVAL_WA_BIT = BIT(2),
}; };
struct smb_regulator { struct smb_regulator {
@ -177,6 +184,7 @@ struct smb_charger {
/* work */ /* work */
struct work_struct bms_update_work; struct work_struct bms_update_work;
struct work_struct pl_detect_work; struct work_struct pl_detect_work;
struct work_struct rdstd_cc2_detach_work;
struct delayed_work hvdcp_detect_work; struct delayed_work hvdcp_detect_work;
struct delayed_work ps_change_timeout_work; struct delayed_work ps_change_timeout_work;
struct delayed_work pl_taper_work; struct delayed_work pl_taper_work;
@ -205,6 +213,7 @@ struct smb_charger {
/* workaround flag */ /* workaround flag */
u32 wa_flags; u32 wa_flags;
enum cc2_sink_type cc2_sink_detach_flag;
}; };
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val); int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);

View file

@ -905,6 +905,7 @@ enum {
#define MISC_CFG_REG (MISC_BASE + 0x52) #define MISC_CFG_REG (MISC_BASE + 0x52)
#define GSM_PA_ON_ADJ_SEL_BIT BIT(0) #define GSM_PA_ON_ADJ_SEL_BIT BIT(0)
#define TCC_DEBOUNCE_20MS_BIT BIT(5)
#define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53) #define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53)
#define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7) #define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7)