summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/power/qpnp-smbcharger.c247
1 files changed, 126 insertions, 121 deletions
diff --git a/drivers/power/qpnp-smbcharger.c b/drivers/power/qpnp-smbcharger.c
index ca6bba0582e5..731e908ce485 100644
--- a/drivers/power/qpnp-smbcharger.c
+++ b/drivers/power/qpnp-smbcharger.c
@@ -198,6 +198,8 @@ struct smbchg_chip {
u32 wa_flags;
int usb_icl_delta;
bool typec_dfp;
+ unsigned int usb_current_max;
+ unsigned int usb_health;
/* jeita and temperature */
bool batt_hot;
@@ -236,6 +238,7 @@ struct smbchg_chip {
bool enable_aicl_wake;
/* psy */
+ struct power_supply_desc usb_psy_d;
struct power_supply *usb_psy;
struct power_supply_desc batt_psy_d;
struct power_supply *batt_psy;
@@ -1109,7 +1112,6 @@ static void update_typec_status(struct smbchg_chip *chip)
{
union power_supply_propval type = {0, };
union power_supply_propval capability = {0, };
- int rc;
get_property_from_typec(chip, POWER_SUPPLY_PROP_TYPE, &type);
if (type.intval != POWER_SUPPLY_TYPE_UNKNOWN) {
@@ -1117,17 +1119,8 @@ static void update_typec_status(struct smbchg_chip *chip)
POWER_SUPPLY_PROP_CURRENT_CAPABILITY,
&capability);
chip->typec_current_ma = capability.intval;
-
- if (!chip->skip_usb_notification) {
- rc = power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_INPUT_CURRENT_MAX,
- &capability);
- if (rc)
- pr_err("typec failed to set current max rc=%d\n",
- rc);
- pr_smb(PR_TYPEC, "SMB Type-C mode = %d, current=%d\n",
- type.intval, capability.intval);
- }
+ pr_smb(PR_TYPEC, "SMB Type-C mode = %d, current=%d\n",
+ type.intval, capability.intval);
} else {
pr_smb(PR_TYPEC,
"typec detection not completed continuing with USB update\n");
@@ -1493,7 +1486,6 @@ static void smbchg_usb_update_online_work(struct work_struct *work)
usb_set_online_work);
bool user_enabled = !get_client_vote(chip->usb_suspend_votable,
USER_EN_VOTER);
- union power_supply_propval ret;
int online;
online = user_enabled && chip->usb_present && !chip->very_weak_charger;
@@ -1501,10 +1493,8 @@ static void smbchg_usb_update_online_work(struct work_struct *work)
mutex_lock(&chip->usb_set_online_lock);
if (chip->usb_online != online) {
pr_smb(PR_MISC, "setting usb psy online = %d\n", online);
- ret.intval = online;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_ONLINE, &ret);
chip->usb_online = online;
+ power_supply_changed(chip->usb_psy);
}
mutex_unlock(&chip->usb_set_online_lock);
}
@@ -3587,10 +3577,12 @@ static void smbchg_external_power_changed(struct power_supply *psy)
vote(chip->usb_suspend_votable, POWER_SUPPLY_EN_VOTER,
!prop.intval, 0);
- rc = power_supply_get_property(chip->usb_psy,
- POWER_SUPPLY_PROP_CURRENT_MAX, &prop);
- if (rc == 0)
- current_limit = prop.intval / 1000;
+ current_limit = chip->usb_current_max / 1000;
+
+ /* Override if type-c charger used */
+ if (chip->typec_current_ma > 500 &&
+ current_limit < chip->typec_current_ma)
+ current_limit = chip->typec_current_ma;
read_usb_type(chip, &usb_type_name, &usb_supply_type);
@@ -4290,7 +4282,6 @@ static int smbchg_change_usb_supply_type(struct smbchg_chip *chip,
enum power_supply_type type)
{
int rc, current_limit_ma;
- union power_supply_propval pval = {0, };
/*
* if the type is not unknown, set the type before changing ICL vote
@@ -4309,8 +4300,6 @@ static int smbchg_change_usb_supply_type(struct smbchg_chip *chip,
current_limit_ma = chip->typec_current_ma;
else if (type == POWER_SUPPLY_TYPE_USB)
current_limit_ma = DEFAULT_SDP_MA;
- else if (type == POWER_SUPPLY_TYPE_USB)
- current_limit_ma = DEFAULT_SDP_MA;
else if (type == POWER_SUPPLY_TYPE_USB_CDP)
current_limit_ma = DEFAULT_CDP_MA;
else if (type == POWER_SUPPLY_TYPE_USB_HVDCP)
@@ -4329,16 +4318,13 @@ static int smbchg_change_usb_supply_type(struct smbchg_chip *chip,
goto out;
}
- if (!chip->skip_usb_notification) {
- pval.intval = type;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_TYPE, &pval);
- }
-
/* otherwise if it is unknown, set type after the vote */
if (type == POWER_SUPPLY_TYPE_UNKNOWN)
chip->usb_supply_type = type;
+ if (!chip->skip_usb_notification)
+ power_supply_changed(chip->usb_psy);
+
/* set the correct buck switching frequency */
rc = smbchg_set_optimal_charging_mode(chip, type);
if (rc < 0)
@@ -4528,25 +4514,13 @@ static void handle_usb_removal(struct smbchg_chip *chip)
if (chip->typec_psy)
chip->typec_current_ma = 0;
smbchg_change_usb_supply_type(chip, POWER_SUPPLY_TYPE_UNKNOWN);
- if (!chip->skip_usb_notification) {
- pr_smb(PR_MISC, "setting usb psy present = %d\n",
- chip->usb_present);
- pval.intval = chip->usb_present;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT, &pval);
- }
extcon_set_cable_state_(chip->extcon, EXTCON_USB, chip->usb_present);
set_usb_psy_dp_dm(chip, POWER_SUPPLY_DP_DM_DPR_DMR);
schedule_work(&chip->usb_set_online_work);
pr_smb(PR_MISC, "setting usb psy health UNKNOWN\n");
- pval.intval = POWER_SUPPLY_HEALTH_UNKNOWN;
- rc = power_supply_set_property(chip->usb_psy, POWER_SUPPLY_PROP_HEALTH,
- &pval);
- if (rc < 0)
- pr_smb(PR_STATUS,
- "usb psy does not allow updating prop %d rc = %d\n",
- POWER_SUPPLY_HEALTH_UNKNOWN, rc);
+ chip->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN;
+ power_supply_changed(chip->usb_psy);
if (parallel_psy && chip->parallel_charger_detected) {
pval.intval = false;
@@ -4619,13 +4593,6 @@ static void handle_usb_insertion(struct smbchg_chip *chip)
if (chip->typec_psy)
update_typec_status(chip);
smbchg_change_usb_supply_type(chip, usb_supply_type);
- if (!chip->skip_usb_notification) {
- pr_smb(PR_MISC, "setting usb psy present = %d\n",
- chip->usb_present);
- pval.intval = chip->usb_present;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT, &pval);
- }
/* Only notify USB if it's not a charger */
if (usb_supply_type == POWER_SUPPLY_TYPE_USB ||
@@ -4643,16 +4610,10 @@ static void handle_usb_insertion(struct smbchg_chip *chip)
pr_smb(PR_MISC, "setting usb psy health %s\n",
chip->very_weak_charger
? "UNSPEC_FAILURE" : "GOOD");
- pval.intval = chip->very_weak_charger
+ chip->usb_health = chip->very_weak_charger
? POWER_SUPPLY_HEALTH_UNSPEC_FAILURE
: POWER_SUPPLY_HEALTH_GOOD;
- rc = power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_HEALTH,
- &pval);
- if (rc < 0)
- pr_smb(PR_STATUS,
- "usb psy does not allow updating prop %d rc = %d\n",
- POWER_SUPPLY_HEALTH_GOOD, rc);
+ power_supply_changed(chip->usb_psy);
}
schedule_work(&chip->usb_set_online_work);
@@ -4777,7 +4738,6 @@ static void increment_aicl_count(struct smbchg_chip *chip)
u8 reg;
long elapsed_seconds;
unsigned long now_seconds;
- union power_supply_propval pval = {0, };
pr_smb(PR_INTERRUPT, "aicl count c:%d dgltch:%d first:%ld\n",
chip->aicl_irq_count, chip->aicl_deglitch_short,
@@ -4859,13 +4819,8 @@ static void increment_aicl_count(struct smbchg_chip *chip)
if (bad_charger) {
pr_smb(PR_MISC,
"setting usb psy health UNSPEC_FAILURE\n");
- pval.intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
- rc = power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_HEALTH,
- &pval);
- if (rc)
- pr_err("Couldn't set health on usb psy rc:%d\n",
- rc);
+ chip->usb_health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ power_supply_changed(chip->usb_psy);
schedule_work(&chip->usb_set_online_work);
}
}
@@ -5514,17 +5469,8 @@ static int smbchg_dp_dm(struct smbchg_chip *chip, int val)
static void update_typec_capability_status(struct smbchg_chip *chip,
const union power_supply_propval *val)
{
- int rc;
-
pr_smb(PR_TYPEC, "typec capability = %dma\n", val->intval);
- if (!chip->skip_usb_notification) {
- rc = power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_INPUT_CURRENT_MAX, val);
- if (rc)
- pr_err("typec failed to set current max rc=%d\n", rc);
- }
-
pr_debug("changing ICL from %dma to %dma\n", chip->typec_current_ma,
val->intval);
chip->typec_current_ma = val->intval;
@@ -5540,8 +5486,6 @@ static void update_typec_otg_status(struct smbchg_chip *chip, int mode,
if (mode == POWER_SUPPLY_TYPE_DFP) {
chip->typec_dfp = true;
pval.intval = 1;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_USB_OTG, &pval);
extcon_set_cable_state_(chip->extcon, EXTCON_USB_HOST,
chip->typec_dfp);
/* update FG */
@@ -5550,8 +5494,6 @@ static void update_typec_otg_status(struct smbchg_chip *chip, int mode,
} else if (force || chip->typec_dfp) {
chip->typec_dfp = false;
pval.intval = 0;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_USB_OTG, &pval);
extcon_set_cable_state_(chip->extcon, EXTCON_USB_HOST,
chip->typec_dfp);
/* update FG */
@@ -5560,6 +5502,82 @@ static void update_typec_otg_status(struct smbchg_chip *chip, int mode,
}
}
+static int smbchg_usb_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct smbchg_chip *chip = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = chip->usb_current_max;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = chip->usb_present;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = chip->usb_online;
+ break;
+ case POWER_SUPPLY_PROP_TYPE:
+ val->intval = chip->usb_supply_type;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = chip->usb_health;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int smbchg_usb_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct smbchg_chip *chip = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ chip->usb_current_max = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ chip->usb_online = val->intval;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ power_supply_changed(psy);
+ return 0;
+}
+
+static int
+smbchg_usb_is_writeable(struct power_supply *psy, enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+static char *smbchg_usb_supplicants[] = {
+ "battery",
+ "bms",
+};
+
+static enum power_supply_property smbchg_usb_properties[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_TYPE,
+ POWER_SUPPLY_PROP_HEALTH,
+};
+
#define CHARGE_OUTPUT_VTG_RATIO 840
static int smbchg_get_iusb(struct smbchg_chip *chip)
{
@@ -6158,7 +6176,6 @@ static irqreturn_t usbin_ov_handler(int irq, void *_chip)
int rc;
u8 reg;
bool usb_present;
- union power_supply_propval pval = {0, };
rc = smbchg_read(chip, &reg, chip->usb_chgpth_base + RT_STS, 1);
if (rc < 0) {
@@ -6169,17 +6186,9 @@ static irqreturn_t usbin_ov_handler(int irq, void *_chip)
/* OV condition is detected. Notify it to USB psy */
if (reg & USBIN_OV_BIT) {
chip->usb_ov_det = true;
- if (chip->usb_psy) {
- pr_smb(PR_MISC, "setting usb psy health OV\n");
- pval.intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
- rc = power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_HEALTH,
- &pval);
- if (rc)
- pr_smb(PR_STATUS,
- "usb psy does not allow updating prop %d rc = %d\n",
- POWER_SUPPLY_HEALTH_OVERVOLTAGE, rc);
- }
+ pr_smb(PR_MISC, "setting usb psy health OV\n");
+ chip->usb_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ power_supply_changed(chip->usb_psy);
} else {
chip->usb_ov_det = false;
/* If USB is present, then handle the USB insertion */
@@ -6270,11 +6279,8 @@ static irqreturn_t usbin_uv_handler(int irq, void *_chip)
rc);
}
pr_smb(PR_MISC, "setting usb psy health UNSPEC_FAILURE\n");
- pval.intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
- rc = power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_HEALTH, &pval);
- if (rc)
- pr_err("Couldn't set health on usb psy rc:%d\n", rc);
+ chip->usb_health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ power_supply_changed(chip->usb_psy);
schedule_work(&chip->usb_set_online_work);
}
@@ -6428,18 +6434,12 @@ static irqreturn_t usbid_change_handler(int irq, void *_chip)
{
struct smbchg_chip *chip = _chip;
bool otg_present;
- union power_supply_propval pval = {0, };
pr_smb(PR_INTERRUPT, "triggered\n");
otg_present = is_otg_present(chip);
- if (chip->usb_psy) {
- pr_smb(PR_MISC, "setting usb psy OTG = %d\n",
- otg_present ? 1 : 0);
- pval.intval = otg_present ? 1 : 0;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_USB_OTG, &pval);
- }
+ pr_smb(PR_MISC, "setting usb psy OTG = %d\n",
+ otg_present ? 1 : 0);
extcon_set_cable_state_(chip->extcon, EXTCON_USB_HOST, otg_present);
@@ -7858,19 +7858,13 @@ static int smbchg_probe(struct platform_device *pdev)
{
int rc;
struct smbchg_chip *chip;
- struct power_supply *usb_psy, *typec_psy = NULL;
+ struct power_supply *typec_psy = NULL;
struct qpnp_vadc_chip *vadc_dev, *vchg_vadc_dev;
const char *typec_psy_name;
- union power_supply_propval pval = {0, };
+ struct power_supply_config usb_psy_cfg = {};
struct power_supply_config batt_psy_cfg = {};
struct power_supply_config dc_psy_cfg = {};
- usb_psy = power_supply_get_by_name("usb");
- if (!usb_psy) {
- pr_smb(PR_STATUS, "USB supply not found, deferring probe\n");
- return -EPROBE_DEFER;
- }
-
if (of_property_read_bool(pdev->dev.of_node, "qcom,external-typec")) {
/* read the type power supply name */
rc = of_property_read_string(pdev->dev.of_node,
@@ -8002,7 +7996,6 @@ static int smbchg_probe(struct platform_device *pdev)
chip->pdev = pdev;
chip->dev = &pdev->dev;
- chip->usb_psy = usb_psy;
chip->typec_psy = typec_psy;
chip->fake_battery_soc = -EINVAL;
chip->usb_online = -EINVAL;
@@ -8055,6 +8048,26 @@ static int smbchg_probe(struct platform_device *pdev)
return rc;
}
+ chip->usb_psy_d.name = "usb";
+ chip->usb_psy_d.type = POWER_SUPPLY_TYPE_USB;
+ chip->usb_psy_d.get_property = smbchg_usb_get_property;
+ chip->usb_psy_d.set_property = smbchg_usb_set_property;
+ chip->usb_psy_d.properties = smbchg_usb_properties;
+ chip->usb_psy_d.num_properties = ARRAY_SIZE(smbchg_usb_properties);
+ chip->usb_psy_d.property_is_writeable = smbchg_usb_is_writeable;
+
+ usb_psy_cfg.drv_data = chip;
+ usb_psy_cfg.supplied_to = smbchg_usb_supplicants;
+ usb_psy_cfg.num_supplicants = ARRAY_SIZE(smbchg_usb_supplicants);
+
+ chip->usb_psy = devm_power_supply_register(chip->dev,
+ &chip->usb_psy_d, &usb_psy_cfg);
+ if (IS_ERR(chip->usb_psy)) {
+ dev_err(&pdev->dev, "Unable to register usb_psy rc = %ld\n",
+ PTR_ERR(chip->usb_psy));
+ return PTR_ERR(chip->usb_psy);
+ }
+
rc = smbchg_hw_init(chip);
if (rc < 0) {
dev_err(&pdev->dev,
@@ -8142,14 +8155,6 @@ static int smbchg_probe(struct platform_device *pdev)
goto unregister_led_class;
}
- if (!chip->skip_usb_notification) {
- pr_smb(PR_MISC, "setting usb psy present = %d\n",
- chip->usb_present);
- pval.intval = chip->usb_present;
- power_supply_set_property(chip->usb_psy,
- POWER_SUPPLY_PROP_PRESENT, &pval);
- }
-
rerun_hvdcp_det_if_necessary(chip);
dump_regs(chip);