Merge "qcom-charger: WA for typec cc2 sink removal with rdstd"
This commit is contained in:
commit
59c99dc4e4
4 changed files with 192 additions and 2 deletions
|
@ -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",
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Reference in a new issue