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, ®, 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);