From 9c3f7e472cb687cef9bf828f023b30a71c957b81 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 13 Jul 2020 12:43:13 -0700 Subject: [PATCH 1/2] power: supply: qti_battery_charger: add some more properties To support userspace application and testing, add some more properties under USB power supply and qcom-battery class. To show USB connector temperature, following property is added. - /sys/class/power_supply/usb/temp To support restricted charging similar to legacy targets, following parameters are added. - /sys/class/qcom-battery/restrict_cur - /sys/class/qcom-battery/restrict_chg To show whether the Type-C sink/source connected is compliant, following parameter is added. - /sys/class/qcom-battery/usb_typec_compliant To show the custom USB_TYPE for Quick charge adapters like HVDCP, HVDCP3 etc., following parameter is added. - /sys/class/qcom-battery/usb_real_type. Change-Id: Ia8dfba41c6ed3056dda588a1955a60ef19568112 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qti_battery_charger.c | 177 ++++++++++++++++++++- 1 file changed, 174 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index 08a7c5c27532..6917808719ca 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -47,6 +47,7 @@ #define WLS_FW_PREPARE_TIME_MS 300 #define WLS_FW_WAIT_TIME_MS 500 #define WLS_FW_BUF_SIZE 128 +#define DEFAULT_RESTRICT_FCC_UA 1000000 enum psy_type { PSY_TYPE_BATTERY, @@ -100,6 +101,9 @@ enum usb_property_id { USB_ADAP_TYPE, USB_MOISTURE_DET_EN, USB_MOISTURE_DET_STS, + USB_TEMP, + USB_REAL_TYPE, + USB_TYPEC_COMPLIANT, USB_PROP_MAX, }; @@ -114,6 +118,12 @@ enum wireless_property_id { WLS_PROP_MAX, }; +enum { + QTI_POWER_SUPPLY_USB_TYPE_HVDCP = 0x80, + QTI_POWER_SUPPLY_USB_TYPE_HVDCP_3, + QTI_POWER_SUPPLY_USB_TYPE_HVDCP_3P5, +}; + struct battery_charger_set_notify_msg { struct pmic_glink_hdr hdr; u32 battery_id; @@ -221,6 +231,9 @@ struct battery_chg_dev { bool wls_fw_update_reqd; u32 wls_fw_version; struct notifier_block reboot_notifier; + u32 thermal_fcc_ua; + u32 restrict_fcc_ua; + bool restrict_chg_en; }; static const int battery_prop_map[BATT_PROP_MAX] = { @@ -256,6 +269,7 @@ static const int usb_prop_map[USB_PROP_MAX] = { [USB_CURR_MAX] = POWER_SUPPLY_PROP_CURRENT_MAX, [USB_INPUT_CURR_LIMIT] = POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, [USB_ADAP_TYPE] = POWER_SUPPLY_PROP_USB_TYPE, + [USB_TEMP] = POWER_SUPPLY_PROP_TEMP, }; static const int wls_prop_map[WLS_PROP_MAX] = { @@ -266,6 +280,17 @@ static const int wls_prop_map[WLS_PROP_MAX] = { [WLS_CURR_MAX] = POWER_SUPPLY_PROP_CURRENT_MAX, }; +/* Standard usb_type definitions similar to power_supply_sysfs.c */ +static const char * const power_supply_usb_type_text[] = { + "Unknown", "SDP", "DCP", "CDP", "ACA", "C", + "PD", "PD_DRP", "PD_PPS", "BrickID" +}; + +/* Custom usb_type definitions */ +static const char * const qc_power_supply_usb_type_text[] = { + "HVDCP", "HVDCP_3", "HVDCP_3P5" +}; + static int battery_chg_fw_write(struct battery_chg_dev *bcdev, void *data, int len) { @@ -707,6 +732,28 @@ static const struct power_supply_desc wls_psy_desc = { .property_is_writeable = wls_psy_prop_is_writeable, }; +static const char *get_usb_type_name(u32 usb_type) +{ + u32 i; + + if (usb_type >= QTI_POWER_SUPPLY_USB_TYPE_HVDCP && + usb_type <= QTI_POWER_SUPPLY_USB_TYPE_HVDCP_3P5) { + for (i = 0; i < ARRAY_SIZE(qc_power_supply_usb_type_text); + i++) { + if (i == (usb_type - QTI_POWER_SUPPLY_USB_TYPE_HVDCP)) + return qc_power_supply_usb_type_text[i]; + } + return "Unknown"; + } + + for (i = 0; i < ARRAY_SIZE(power_supply_usb_type_text); i++) { + if (i == usb_type) + return power_supply_usb_type_text[i]; + } + + return "Unknown"; +} + static int usb_psy_set_icl(struct battery_chg_dev *bcdev, u32 prop_id, int val) { struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_USB]; @@ -758,6 +805,8 @@ static int usb_psy_get_prop(struct power_supply *psy, return rc; pval->intval = pst->prop[prop_id]; + if (prop == POWER_SUPPLY_PROP_TEMP) + pval->intval = DIV_ROUND_CLOSEST((int)pval->intval, 10); return 0; } @@ -806,6 +855,7 @@ static enum power_supply_property usb_props[] = { POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, POWER_SUPPLY_PROP_USB_TYPE, + POWER_SUPPLY_PROP_TEMP, }; static enum power_supply_usb_type usb_psy_supported_types[] = { @@ -833,6 +883,26 @@ static const struct power_supply_desc usb_psy_desc = { .property_is_writeable = usb_psy_prop_is_writeable, }; +static int __battery_psy_set_charge_current(struct battery_chg_dev *bcdev, + u32 fcc_ua) +{ + int rc; + + if (bcdev->restrict_chg_en) + fcc_ua = min_t(u32, fcc_ua, bcdev->thermal_fcc_ua); + else + fcc_ua = bcdev->thermal_fcc_ua; + + rc = write_property_id(bcdev, &bcdev->psy_list[PSY_TYPE_BATTERY], + BATT_CHG_CTRL_LIM, fcc_ua); + if (rc < 0) + pr_err("Failed to set FCC %u, rc=%d\n", fcc_ua, rc); + else + pr_debug("Set FCC to %u uA\n", fcc_ua); + + return rc; +} + static int battery_psy_set_charge_current(struct battery_chg_dev *bcdev, int val) { @@ -852,11 +922,10 @@ static int battery_psy_set_charge_current(struct battery_chg_dev *bcdev, fcc_ua = bcdev->thermal_levels[val]; - rc = write_property_id(bcdev, &bcdev->psy_list[PSY_TYPE_BATTERY], - BATT_CHG_CTRL_LIM, fcc_ua); + rc = __battery_psy_set_charge_current(bcdev, fcc_ua); if (!rc) { bcdev->curr_thermal_level = val; - pr_debug("Set FCC to %u uA\n", fcc_ua); + bcdev->thermal_fcc_ua = fcc_ua; } return rc; @@ -1232,6 +1301,102 @@ static ssize_t wireless_fw_update_store(struct class *c, } static CLASS_ATTR_WO(wireless_fw_update); +static ssize_t usb_typec_compliant_show(struct class *c, + struct class_attribute *attr, char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_USB]; + int rc; + + rc = read_property_id(bcdev, pst, USB_TYPEC_COMPLIANT); + if (rc < 0) + return rc; + + return scnprintf(buf, PAGE_SIZE, "%d\n", + (int)pst->prop[USB_TYPEC_COMPLIANT]); +} +static CLASS_ATTR_RO(usb_typec_compliant); + +static ssize_t usb_real_type_show(struct class *c, + struct class_attribute *attr, char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_USB]; + int rc; + + rc = read_property_id(bcdev, pst, USB_REAL_TYPE); + if (rc < 0) + return rc; + + return scnprintf(buf, PAGE_SIZE, "%s\n", + get_usb_type_name(pst->prop[USB_REAL_TYPE])); +} +static CLASS_ATTR_RO(usb_real_type); + +static ssize_t restrict_cur_store(struct class *c, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + int rc; + u32 val; + + if (kstrtou32(buf, 0, &val) || val > bcdev->thermal_fcc_ua) + return -EINVAL; + + if (bcdev->restrict_chg_en) { + rc = __battery_psy_set_charge_current(bcdev, val); + if (rc < 0) + return rc; + } + + bcdev->restrict_fcc_ua = val; + + return count; +} + +static ssize_t restrict_cur_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + + return scnprintf(buf, PAGE_SIZE, "%u\n", bcdev->restrict_fcc_ua); +} +static CLASS_ATTR_RW(restrict_cur); + +static ssize_t restrict_chg_store(struct class *c, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + int rc; + bool val; + + if (kstrtobool(buf, &val)) + return -EINVAL; + + bcdev->restrict_chg_en = val; + + rc = __battery_psy_set_charge_current(bcdev, bcdev->restrict_fcc_ua); + if (rc < 0) + return rc; + + return count; +} + +static ssize_t restrict_chg_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + + return scnprintf(buf, PAGE_SIZE, "%d\n", bcdev->restrict_chg_en); +} +static CLASS_ATTR_RW(restrict_chg); + static ssize_t fake_soc_store(struct class *c, struct class_attribute *attr, const char *buf, size_t count) { @@ -1417,6 +1582,10 @@ static struct attribute *battery_class_attrs[] = { &class_attr_wireless_fw_force_update.attr, &class_attr_wireless_fw_version.attr, &class_attr_ship_mode_en.attr, + &class_attr_restrict_chg.attr, + &class_attr_restrict_cur.attr, + &class_attr_usb_real_type.attr, + &class_attr_usb_typec_compliant.attr, NULL, }; ATTRIBUTE_GROUPS(battery_class); @@ -1512,6 +1681,7 @@ static int battery_chg_parse_dt(struct battery_chg_dev *bcdev) } bcdev->num_thermal_levels = len; + bcdev->thermal_fcc_ua = pst->prop[BATT_CHG_CTRL_LIM_MAX]; return 0; } @@ -1609,6 +1779,7 @@ static int battery_chg_probe(struct platform_device *pdev) if (rc < 0) goto error; + bcdev->restrict_fcc_ua = DEFAULT_RESTRICT_FCC_UA; platform_set_drvdata(pdev, bcdev); bcdev->fake_soc = -EINVAL; rc = battery_chg_init_psy(bcdev); From 466c5d5e26294600d14b4064724944e2d7305ba9 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Thu, 23 Jul 2020 20:02:45 -0700 Subject: [PATCH 2/2] power: supply: qti_battery_charger: update USB power supply type runtime Currently, USB power supply type is set to POWER_SUPPLY_TYPE_USB in power supply descriptor. power_supply_show_property() would show POWER_SUPPLY_PROP_TYPE based on psy->desc->type. Userspace process like healthd would read POWER_SUPPLY_PROP_TYPE to print the adapter type in logs (e.g. "chg=u" for SDP, "chg=a" for DCP). Hence update usb_psy_desc type runtime to show the USB power supply type accordingly. This is useful for testing. Change-Id: Icd88098f97beba053105d826614b4182f3716144 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qti_battery_charger.c | 53 +++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index 6917808719ca..e32940879993 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -224,6 +224,7 @@ struct battery_chg_dev { int num_thermal_levels; atomic_t state; struct work_struct subsys_up_work; + struct work_struct usb_type_work; int fake_soc; bool block_tx; bool ship_mode_en; @@ -620,6 +621,54 @@ static void handle_message(struct battery_chg_dev *bcdev, void *data, complete(&bcdev->ack); } +static struct power_supply_desc usb_psy_desc; + +static void battery_chg_update_usb_type_work(struct work_struct *work) +{ + struct battery_chg_dev *bcdev = container_of(work, + struct battery_chg_dev, usb_type_work); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_USB]; + int rc; + + rc = read_property_id(bcdev, pst, USB_ADAP_TYPE); + if (rc < 0) { + pr_err("Failed to read USB_ADAP_TYPE rc=%d\n", rc); + return; + } + + pr_debug("usb_adap_type: %u\n", pst->prop[USB_ADAP_TYPE]); + + switch (pst->prop[USB_ADAP_TYPE]) { + case POWER_SUPPLY_USB_TYPE_SDP: + usb_psy_desc.type = POWER_SUPPLY_TYPE_USB; + break; + case POWER_SUPPLY_USB_TYPE_DCP: + case POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID: + case QTI_POWER_SUPPLY_USB_TYPE_HVDCP: + case QTI_POWER_SUPPLY_USB_TYPE_HVDCP_3: + case QTI_POWER_SUPPLY_USB_TYPE_HVDCP_3P5: + usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_DCP; + break; + case POWER_SUPPLY_USB_TYPE_CDP: + usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_CDP; + break; + case POWER_SUPPLY_USB_TYPE_ACA: + usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_ACA; + break; + case POWER_SUPPLY_USB_TYPE_C: + usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_TYPE_C; + break; + case POWER_SUPPLY_USB_TYPE_PD: + case POWER_SUPPLY_USB_TYPE_PD_DRP: + case POWER_SUPPLY_USB_TYPE_PD_PPS: + usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD; + break; + default: + usb_psy_desc.type = POWER_SUPPLY_TYPE_USB; + break; + } +} + static void handle_notification(struct battery_chg_dev *bcdev, void *data, size_t len) { @@ -640,6 +689,7 @@ static void handle_notification(struct battery_chg_dev *bcdev, void *data, break; case BC_USB_STATUS_GET: pst = &bcdev->psy_list[PSY_TYPE_USB]; + schedule_work(&bcdev->usb_type_work); break; case BC_WLS_STATUS_GET: pst = &bcdev->psy_list[PSY_TYPE_WLS]; @@ -871,7 +921,7 @@ static enum power_supply_usb_type usb_psy_supported_types[] = { POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID, }; -static const struct power_supply_desc usb_psy_desc = { +static struct power_supply_desc usb_psy_desc = { .name = "usb", .type = POWER_SUPPLY_TYPE_USB, .properties = usb_props, @@ -1753,6 +1803,7 @@ static int battery_chg_probe(struct platform_device *pdev) init_completion(&bcdev->fw_buf_ack); init_completion(&bcdev->fw_update_ack); INIT_WORK(&bcdev->subsys_up_work, battery_chg_subsys_up_work); + INIT_WORK(&bcdev->usb_type_work, battery_chg_update_usb_type_work); atomic_set(&bcdev->state, PMIC_GLINK_STATE_UP); bcdev->dev = dev;