Merge "power: supply: smblite: Add support for concurrency mode"

This commit is contained in:
qctecmdr 2021-04-30 02:05:34 -07:00 committed by Gerrit - the friendly Code Review server
commit b76cd3e6db
4 changed files with 280 additions and 43 deletions

View File

@ -183,11 +183,12 @@ ATTRIBUTE_GROUPS(smblite);
static int smblite_chg_config_init(struct smblite *chip)
{
struct smb_charger *chg = &chip->chg;
int subtype = (u8)of_device_get_match_data(chg->dev);
u8 val;
int rc = 0;
switch (subtype) {
chg->subtype = (u8)of_device_get_match_data(chg->dev);
switch (chg->subtype) {
case PM2250:
chg->wa_flags |= WEAK_ADAPTER_WA;
chg->base = smb_base[PM2250];
@ -209,7 +210,7 @@ static int smblite_chg_config_init(struct smblite *chip)
chg->name = "PM5100_charger";
break;
default:
pr_err("Unsupported PMIC subtype=%d\n", subtype);
pr_err("Unsupported PMIC subtype=%d\n", chg->subtype);
return -EINVAL;
}
@ -302,6 +303,9 @@ static int smblite_parse_dt_misc(struct smblite *chip, struct device_node *node)
if (chg->chg_param.fcc_step_size_ua <= 0)
chg->chg_param.fcc_step_size_ua = DEFAULT_FCC_STEP_SIZE_UA;
chg->concurrent_mode_supported = of_property_read_bool(node,
"qcom,concurrency-mode-supported");
return 0;
}
@ -771,6 +775,41 @@ static int smblite_init_batt_psy(struct smblite *chip)
return rc;
}
/*******************
* QCOM SMB Class *
*******************/
static ssize_t boost_concurrent_mode_store(struct class *c, struct class_attribute *attr,
const char *buf, size_t count)
{
struct smb_charger *chg = container_of(c, struct smb_charger, qcom_class);
int rc;
bool val;
if (kstrtobool(buf, &val))
return -EINVAL;
rc = smblite_lib_set_concurrent_config(chg, val);
if (rc < 0)
return rc;
return count;
}
static ssize_t boost_concurrent_mode_show(struct class *c, struct class_attribute *attr,
char *buf)
{
struct smb_charger *chg = container_of(c, struct smb_charger, qcom_class);
return scnprintf(buf, PAGE_SIZE, "%d\n", chg->concurrent_mode_status);
}
static CLASS_ATTR_RW(boost_concurrent_mode);
static struct attribute *qcom_class_attrs[] = {
&class_attr_boost_concurrent_mode.attr,
NULL,
};
ATTRIBUTE_GROUPS(qcom_class);
/***************************
* HARDWARE INITIALIZATION *
***************************/
@ -1964,6 +2003,18 @@ static int smblite_probe(struct platform_device *pdev)
goto disable_irq;
}
/* Register QCOM SMB class */
if (is_concurrent_mode_supported(chg)) {
chg->qcom_class.name = "qcom-smb";
chg->qcom_class.owner = THIS_MODULE;
chg->qcom_class.class_groups = qcom_class_groups;
rc = class_register(&chg->qcom_class);
if (rc < 0) {
pr_err("Failed to create qcom_class rc=%d\n", rc);
goto disable_irq;
}
}
device_init_wakeup(chg->dev, true);
rc = smblite_lib_get_prop_usb_present(chg, &pval);
@ -1991,6 +2042,7 @@ static int smblite_remove(struct platform_device *pdev)
struct smb_charger *chg = &chip->chg;
smblite_disable_interrupts(chg);
class_destroy(&chg->qcom_class);
smblite_lib_deinit(chg);
sysfs_remove_groups(&chg->dev->kobj, smblite_groups);
platform_set_drvdata(pdev, NULL);

View File

@ -523,6 +523,40 @@ static int smblite_lib_register_notifier(struct smb_charger *chg)
return 0;
}
bool is_concurrent_mode_supported(struct smb_charger *chg)
{
return (chg->concurrent_mode_supported && chg->subtype == PM5100);
}
static int smblite_lib_concurrent_mode_config(struct smb_charger *chg, bool enable)
{
int rc;
if (!is_concurrent_mode_supported(chg))
return 0;
rc = smblite_lib_write(chg, CONCURRENT_MODE_CFG_REG(chg->base),
(enable ? CONCURRENT_MODE_EN_BIT : 0));
if (rc < 0)
smblite_lib_err(chg, "Failed to write CONCURRENT_MODE_CFG_REG rc=%d\n",
rc);
if (!enable) {
/* Remove usb_icl_vote when concurrency mode is disabled */
rc = vote(chg->usb_icl_votable, CONCURRENT_MODE_VOTER, false,
0);
if (rc < 0)
smblite_lib_err(chg, "Failed to vote on ICL rc=%d\n", rc);
/* Remove chg_disable_vote when concurrency mode is disabled */
rc = vote(chg->chg_disable_votable, CONCURRENT_MODE_VOTER, false, 0);
if (rc < 0)
smblite_lib_err(chg, "Failed to vote on ICL rc=%d\n", rc);
}
return rc;
}
static void smblite_lib_uusb_removal(struct smb_charger *chg)
{
int rc;
@ -563,6 +597,8 @@ static void smblite_lib_uusb_removal(struct smb_charger *chg)
chg->uusb_apsd_rerun_done = false;
chg->hvdcp3_detected = false;
/* Disable concurrent mode on USB removal. */
smblite_lib_concurrent_mode_config(chg, false);
}
void smblite_lib_suspend_on_debug_battery(struct smb_charger *chg)
@ -1299,7 +1335,52 @@ static int smblite_lib_dp_pulse(struct smb_charger *chg)
return rc;
}
int smblite_lib_force_vbus_voltage(struct smb_charger *chg, u8 val)
#define HVDCP3_QUALIFICATION_UV (PM5100_MAX_HVDCP3_PULSES * \
(HVDCP3_STEP_SIZE_UV / 2))
static int smblite_lib_hvdcp3_force_max_vbus(struct smb_charger *chg)
{
union power_supply_propval pval = {0, };
int cnt = 0, rc, prev_vbus;
bool qc3_detected = false;
rc = smblite_lib_get_prop_usb_voltage_now(chg, &pval);
if (rc < 0) {
smblite_lib_err(chg, "Couldn't read voltage_now rc=%d\n",
rc);
return rc;
}
prev_vbus = pval.intval;
/*
* Statically increase voltage till 6V.
* ( i.e : 1V / 200mV = 5 pulses ).
*/
while (cnt++ < PM5100_MAX_HVDCP3_PULSES) {
smblite_lib_dp_pulse(chg);
/* wait for 100ms for vbus to settle. */
msleep(100);
}
rc = smblite_lib_get_prop_usb_voltage_now(chg, &pval);
if (rc < 0) {
smblite_lib_err(chg, "Couldn't read voltage_now rc=%d\n",
rc);
return rc;
}
/* Check if voltage incremented. (i.e if QC3 ) */
if (pval.intval >= (prev_vbus + HVDCP3_QUALIFICATION_UV))
qc3_detected = true;
smblite_lib_dbg(chg, PR_MISC, "HVDCP3 : detected=%s, prev_vbus=%d, vbus_now=%d\n",
(qc3_detected ? "True" : "False"), prev_vbus,
pval.intval);
return qc3_detected;
}
static int smblite_lib_force_vbus_voltage(struct smb_charger *chg, u8 val)
{
int rc;
@ -1356,6 +1437,111 @@ int smblite_lib_run_aicl(struct smb_charger *chg, int type)
return 0;
}
#define CONCURRENCY_REDUCED_ICL_UA 300000
int smblite_lib_set_concurrent_config(struct smb_charger *chg, bool enable)
{
int rc = 0, icl_ua = 0, settled_icl_ua = 0, usb_present = 0;
union power_supply_propval pval = {0, };
if (!is_concurrent_mode_supported(chg)) {
smblite_lib_dbg(chg, PR_MISC, "Concurrent Mode supported disabled\n");
return 0;
}
/* Exit if there is no change in state */
if (chg->concurrent_mode_status == enable)
goto out;
rc = smblite_lib_get_prop_usb_present(chg, &pval);
if (rc < 0) {
smblite_lib_dbg(chg, PR_MISC,
"Couldn't get USB preset status rc=%d\n", rc);
goto failure;
}
usb_present = pval.intval;
if (enable) {
/* Check if USB is connected */
if (!usb_present) {
smblite_lib_dbg(chg, PR_MISC,
"Failed to enable concurrent mode USB disconnected\n", rc);
goto failure;
}
/* Get AICL Result */
rc = smblite_lib_get_prop_input_current_settled(chg, &settled_icl_ua);
if (rc) {
smblite_lib_err(chg, "Failed read AICL Result rc=%d\n", rc);
goto failure;
}
/* Return if AICL result is less than 300mA. */
if (settled_icl_ua <= CONCURRENCY_REDUCED_ICL_UA) {
smblite_lib_dbg(chg, PR_MISC,
"AICL Result too less to enable concurreny mode\n");
goto failure;
}
icl_ua = settled_icl_ua - CONCURRENCY_REDUCED_ICL_UA;
rc = vote(chg->usb_icl_votable, CONCURRENT_MODE_VOTER, true,
icl_ua);
if (rc < 0) {
smblite_lib_err(chg, "Failed to vote on ICL rc=%d\n", rc);
goto failure;
}
if (chg->hvdcp3_detected) {
/* Force Vbus to 5V. */
rc = smblite_lib_force_vbus_voltage(chg, FORCE_5V_BIT);
if (rc < 0)
smblite_lib_err(chg, "Failed to force vbus to 5V rc=%d\n",
rc);
}
/* Enable charger if already disabled */
rc = vote(chg->chg_disable_votable, CONCURRENT_MODE_VOTER, false, 0);
if (rc < 0) {
smblite_lib_err(chg, "Failed to Enable charger rc=%d\n",
rc);
goto failure;
}
/* Enable concurrent mode */
rc = smblite_lib_concurrent_mode_config(chg, true);
if (rc < 0)
goto failure;
chg->concurrent_mode_status = true;
smblite_lib_dbg(chg, PR_MISC, "Concurrent Mode enabled successfully: settled_icl_ua=%duA, icl_ua=%duA, is_hvdcp3=%d\n",
settled_icl_ua, icl_ua,
chg->hvdcp3_detected);
goto out;
} else {
/* Disable concurrent mode */
rc = smblite_lib_concurrent_mode_config(chg, false);
if (rc < 0)
goto failure;
/* Restore vbus to MAX(6V) if QC3P5 is connected */
if (chg->hvdcp3_detected && usb_present)
smblite_lib_hvdcp3_force_max_vbus(chg);
chg->concurrent_mode_status = false;
smblite_lib_dbg(chg, PR_MISC, "Concurrent Mode disabled successfully: is_hvdcp3=%d\n",
chg->hvdcp3_detected);
goto out;
}
failure:
rc = -EINVAL;
smblite_lib_dbg(chg, PR_MISC, "Failed to %s concurrent mode\n",
(enable ? "Enable" : "Disable"));
out:
return rc;
}
/*******************
* USB PSY GETTERS *
*******************/
@ -2397,12 +2583,30 @@ static void smblite_lib_micro_usb_plugin(struct smb_charger *chg,
bool vbus_rising)
{
int rc = 0;
u8 stat;
if (vbus_rising) {
rc = typec_partner_register(chg);
if (rc < 0)
smblite_lib_err(chg, "Couldn't register partner rc =%d\n",
rc);
/*
* For PM5100 check if concurrent mode support is enabled and
* charging is paused in hardware due to boost being enabled,
* force charging to be disabled in SW.
*/
if (is_concurrent_mode_supported(chg)) {
rc = smblite_lib_read(chg, CHGR_CHG_EN_STATUS_REG(chg->base), &stat);
if (rc < 0)
smblite_lib_err(chg, "Couldn't read CHGR_EN_STATUS_REG rc=%d\n",
rc);
vote(chg->chg_disable_votable, CONCURRENT_MODE_VOTER,
(stat & CHARGING_DISABLED_FROM_BOOST_BIT), 0);
smblite_lib_dbg(chg, PR_MISC,
"charger_en_status=%x, Charging disable by boost\n", stat);
}
} else {
smblite_lib_notify_device_mode(chg, false);
smblite_lib_uusb_removal(chg);
@ -2695,54 +2899,22 @@ static void smblite_lib_handle_apsd_done(struct smb_charger *chg, bool rising)
apsd_result->name);
}
#define HVDCP3_QUALIFICATION_UV (PM5100_MAX_HVDCP3_PULSES * \
(HVDCP3_STEP_SIZE_UV / 2))
static void smblite_lib_handle_hvdcp_check_timeout(struct smb_charger *chg,
bool rising, bool qc_charger)
{
union power_supply_propval pval = {0, };
int rc = 0, cnt = 0, prev_vbus;
int rc = 0;
if (rising) {
if (qc_charger) {
rc = smblite_lib_get_prop_usb_voltage_now(chg, &pval);
if (rc < 0) {
smblite_lib_err(chg, "Couldn't read voltage_now rc=%d\n",
rc);
goto failure;
}
prev_vbus = pval.intval;
/*
* Statically increase voltage till 6V.
* ( i.e : 1V / 200mV = 5 pulses ).
*/
while (cnt++ < PM5100_MAX_HVDCP3_PULSES) {
smblite_lib_dp_pulse(chg);
/* wait for 100ms for vbus to settle. */
msleep(100);
}
rc = smblite_lib_get_prop_usb_voltage_now(chg, &pval);
if (rc < 0) {
smblite_lib_err(chg, "Couldn't read voltage_now rc=%d\n",
rc);
goto failure;
}
/* Check if voltage incremented. (i.e if QC3 )*/
if (pval.intval >= (prev_vbus + HVDCP3_QUALIFICATION_UV))
/* Increase vbus to MAX(6V), if incremented HVDCP_3 is detected */
rc = smblite_lib_hvdcp3_force_max_vbus(chg);
if (rc < 0)
smblite_lib_err(chg, "HVDCP3 detection failure\n");
if (rc > 0)
chg->hvdcp3_detected = true;
smblite_lib_dbg(chg, PR_MISC, "HVDCP3 : detected=%s, prev_vbus=%d, vbus_now=%d\n",
(chg->hvdcp3_detected ? "True" : "False"),
prev_vbus, pval.intval);
}
}
failure:
smblite_lib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__,
rising ? "rising" : "falling");
}

View File

@ -51,6 +51,7 @@ enum print_reason {
#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER"
#define TYPEC_SWAP_VOTER "TYPEC_SWAP_VOTER"
#define FLASH_ACTIVE_VOTER "FLASH_ACTIVE_VOTER"
#define CONCURRENT_MODE_VOTER "CONCURRENT_MODE_VOTER"
#define BOOST_BACK_STORM_COUNT 3
#define WEAK_CHG_STORM_COUNT 8
@ -264,8 +265,10 @@ struct smb_charger {
struct iio_channel *iio_chans;
struct iio_channel **iio_chan_list_qg;
struct iio_channel **iio_chan_list_smb_parallel;
struct class qcom_class;
int *debug_mask;
enum smb_mode mode;
u8 subtype;
int weak_chg_icl_ua;
/* locks */
@ -359,6 +362,8 @@ struct smb_charger {
bool uusb_apsd_rerun_done;
bool dpdm_enabled;
bool hvdcp3_detected;
bool concurrent_mode_supported;
bool concurrent_mode_status;
/* workaround flag */
u32 wa_flags;
@ -503,5 +508,7 @@ int smblite_iio_get_prop(struct smb_charger *chg, int channel, int *val);
int smblite_iio_set_prop(struct smb_charger *chg, int channel, int val);
int smblite_lib_get_fcc(struct smb_chg_param *param, u8 val_raw);
int smblite_lib_set_fcc(struct smb_chg_param *param, int val_u, u8 *val_raw);
int smblite_lib_set_concurrent_config(struct smb_charger *chg, bool enable);
bool is_concurrent_mode_supported(struct smb_charger *chg);
#endif /* __SMBLITE_LIB_H */

View File

@ -30,6 +30,9 @@ enum {
DISABLE_CHARGE,
};
#define CHGR_CHG_EN_STATUS_REG(base) (base.chg_base + 0x07)
#define CHARGING_DISABLED_FROM_BOOST_BIT BIT(6)
#define CHARGER_VBAT_STATUS_REG(base) (base.chg_base + 0x08)
#define BAT_OV_BIT BIT(7)
@ -103,6 +106,9 @@ enum {
#define DCDC_LDO_CFG_REG(base) (base.dcdc_base + 0x70)
#define LDO_MODE_BIT BIT(0)
#define CONCURRENT_MODE_CFG_REG(base) (base.dcdc_base + 0x50)
#define CONCURRENT_MODE_EN_BIT BIT(0)
/********************************
* BATIF Peripheral Registers *
********************************/