Merge "power: supply: smblite: Add support for concurrency mode"
This commit is contained in:
commit
b76cd3e6db
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 *
|
||||
********************************/
|
||||
|
Loading…
Reference in New Issue
Block a user