summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2017-02-01 19:23:35 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2017-02-01 19:23:35 -0800
commit5e7d38562557ebcfea71a97bcccafd87d12d364b (patch)
treee5e7a851c1b0f032d5de3db9ebe58ac8a6c60d6c
parentffaa506460d58cf093409d0cb790d2e2795114de (diff)
parentf0cf35f5921410fed20e7d2d5f89ed3326430a08 (diff)
Merge "power: qcom-charger: separate parallel code"
-rw-r--r--drivers/power/power_supply_sysfs.c5
-rw-r--r--drivers/power/supply/qcom/Makefile6
-rw-r--r--drivers/power/supply/qcom/battery.c730
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c86
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c146
-rw-r--r--drivers/power/supply/qcom/smb-lib.c315
-rw-r--r--drivers/power/supply/qcom/smb-lib.h12
-rw-r--r--drivers/power/supply/qcom/smb1351-charger.c13
-rw-r--r--drivers/power/supply/qcom/smb135x-charger.c6
-rw-r--r--drivers/power/supply/qcom/smb138x-charger.c12
-rw-r--r--include/linux/power_supply.h16
11 files changed, 987 insertions, 360 deletions
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index e99bf1ee5ad2..7e6eca7f7a7e 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -46,7 +46,7 @@ static ssize_t power_supply_show_property(struct device *dev,
static char *type_text[] = {
"Unknown", "Battery", "UPS", "Mains", "USB", "USB_DCP",
"USB_CDP", "USB_ACA", "USB_HVDCP", "USB_HVDCP_3", "USB_PD",
- "Wireless", "BMS", "USB_Parallel", "Wipower",
+ "Wireless", "BMS", "Parallel", "Main", "Wipower",
"TYPEC", "TYPEC_UFP", "TYPEC_DFP"
};
static char *status_text[] = {
@@ -280,6 +280,9 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(set_ship_mode),
POWER_SUPPLY_ATTR(soc_reporting_ready),
POWER_SUPPLY_ATTR(debug_battery),
+ POWER_SUPPLY_ATTR(fcc_delta),
+ POWER_SUPPLY_ATTR(icl_reduction),
+ POWER_SUPPLY_ATTR(parallel_mode),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile
index 0126d2d0a18e..912acb0c788a 100644
--- a/drivers/power/supply/qcom/Makefile
+++ b/drivers/power/supply/qcom/Makefile
@@ -6,6 +6,6 @@ obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o
obj-$(CONFIG_MSM_BCL_CTL) += msm_bcl.o
obj-$(CONFIG_MSM_BCL_PERIPHERAL_CTL) += bcl_peripheral.o
obj-$(CONFIG_BATTERY_BCL) += battery_current_limit.o
-obj-$(CONFIG_QPNP_SMB2) += qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o
-obj-$(CONFIG_SMB138X_CHARGER) += smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o
-obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o
+obj-$(CONFIG_QPNP_SMB2) += qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o battery.o
+obj-$(CONFIG_SMB138X_CHARGER) += smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o
+obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
new file mode 100644
index 000000000000..5f1b6b294b5f
--- /dev/null
+++ b/drivers/power/supply/qcom/battery.c
@@ -0,0 +1,730 @@
+/* Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "QCOM-BATT: %s: " fmt, __func__
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/power_supply.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/qpnp/qpnp-revid.h>
+#include <linux/printk.h>
+#include <linux/pm_wakeup.h>
+#include <linux/slab.h>
+#include "pmic-voter.h"
+
+#define DRV_MAJOR_VERSION 1
+#define DRV_MINOR_VERSION 0
+
+#define CHG_STATE_VOTER "CHG_STATE_VOTER"
+#define TAPER_END_VOTER "TAPER_END_VOTER"
+#define PL_TAPER_EARLY_BAD_VOTER "PL_TAPER_EARLY_BAD_VOTER"
+#define PARALLEL_PSY_VOTER "PARALLEL_PSY_VOTER"
+
+struct pl_data {
+ int pl_mode;
+ int slave_pct;
+ int taper_pct;
+ int slave_fcc_ua;
+ struct votable *fcc_votable;
+ struct votable *fv_votable;
+ struct votable *pl_disable_votable;
+ struct work_struct status_change_work;
+ struct delayed_work pl_taper_work;
+ struct power_supply *main_psy;
+ struct power_supply *pl_psy;
+ struct power_supply *batt_psy;
+ int settled_ua;
+ int charge_type;
+ struct class qcom_batt_class;
+ struct wakeup_source *pl_ws;
+ struct notifier_block nb;
+};
+
+struct pl_data *the_chip;
+
+enum print_reason {
+ PR_PARALLEL = BIT(0),
+};
+
+static int debug_mask;
+module_param_named(debug_mask, debug_mask, int, S_IRUSR | S_IWUSR);
+
+#define pl_dbg(chip, reason, fmt, ...) \
+ do { \
+ if (debug_mask & (reason)) \
+ pr_info(fmt, ##__VA_ARGS__); \
+ else \
+ pr_debug(fmt, ##__VA_ARGS__); \
+ } while (0)
+
+enum {
+ VER = 0,
+ SLAVE_PCT,
+};
+
+/*******
+ * ICL *
+********/
+static void split_settled(struct pl_data *chip)
+{
+ int slave_icl_pct;
+ int slave_ua;
+ union power_supply_propval pval = {0, };
+ int rc;
+
+ /* TODO some parallel chargers do not have a fine ICL resolution. For
+ * them implement a psy interface which returns the closest lower ICL
+ * for desired split
+ */
+
+ if (chip->pl_mode != POWER_SUPPLY_PARALLEL_USBIN_USBIN)
+ return;
+
+ if (chip->main_psy)
+ return;
+
+ slave_ua = 0;
+
+ if (!get_effective_result_locked(chip->pl_disable_votable)) {
+ /* read the aicl settled value */
+ rc = power_supply_get_property(chip->main_psy,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get aicl settled value rc=%d\n", rc);
+ return;
+ }
+ chip->settled_ua = pval.intval;
+ /* slave gets 10 percent points less for ICL */
+ slave_icl_pct = max(0, chip->slave_pct - 10);
+ slave_ua = (chip->settled_ua * slave_icl_pct) / 100;
+ }
+
+ /* ICL_REDUCTION on main could be 0mA when pl is disabled */
+ pval.intval = slave_ua;
+ rc = power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_ICL_REDUCTION, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't change slave suspend state rc=%d\n", rc);
+ return;
+ }
+
+ /* set parallel's ICL could be 0mA when pl is disabled */
+ pval.intval = slave_ua;
+ rc = power_supply_set_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't set parallel icl, rc=%d\n", rc);
+ return;
+ }
+}
+
+static ssize_t version_show(struct class *c, struct class_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d.%d\n",
+ DRV_MAJOR_VERSION, DRV_MINOR_VERSION);
+}
+
+/*************
+* SLAVE PCT *
+**************/
+static ssize_t slave_pct_show(struct class *c, struct class_attribute *attr,
+ char *ubuf)
+{
+ struct pl_data *chip = container_of(c, struct pl_data,
+ qcom_batt_class);
+
+ return snprintf(ubuf, PAGE_SIZE, "%d\n", chip->slave_pct);
+}
+
+static ssize_t slave_pct_store(struct class *c, struct class_attribute *attr,
+ const char *ubuf, size_t count)
+{
+ struct pl_data *chip = container_of(c, struct pl_data,
+ qcom_batt_class);
+ unsigned long val;
+
+ if (kstrtoul(ubuf, 10, &val))
+ return -EINVAL;
+
+ chip->slave_pct = val;
+ rerun_election(chip->fcc_votable);
+ rerun_election(chip->fv_votable);
+ split_settled(chip);
+
+ return count;
+}
+
+static struct class_attribute pl_attributes[] = {
+ [VER] = __ATTR_RO(version),
+ [SLAVE_PCT] = __ATTR(parallel_pct, S_IRUGO | S_IWUSR,
+ slave_pct_show, slave_pct_store),
+ __ATTR_NULL,
+};
+
+/***********
+ * TAPER *
+************/
+#define MINIMUM_PARALLEL_FCC_UA 500000
+#define PL_TAPER_WORK_DELAY_MS 100
+#define TAPER_RESIDUAL_PCT 75
+static void pl_taper_work(struct work_struct *work)
+{
+ struct pl_data *chip = container_of(work, struct pl_data,
+ pl_taper_work.work);
+ union power_supply_propval pval = {0, };
+ int rc;
+
+ /* exit immediately if parallel is disabled */
+ if (get_effective_result(chip->pl_disable_votable)) {
+ pl_dbg(chip, PR_PARALLEL, "terminating parallel not in progress\n");
+ goto done;
+ }
+
+ pl_dbg(chip, PR_PARALLEL, "entering parallel taper work slave_fcc = %d\n",
+ chip->slave_fcc_ua);
+ if (chip->slave_fcc_ua < MINIMUM_PARALLEL_FCC_UA) {
+ pl_dbg(chip, PR_PARALLEL, "terminating parallel's share lower than 500mA\n");
+ vote(chip->pl_disable_votable, TAPER_END_VOTER, true, 0);
+ goto done;
+ }
+
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get batt charge type rc=%d\n", rc);
+ goto done;
+ }
+
+ chip->charge_type = pval.intval;
+ if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
+ pl_dbg(chip, PR_PARALLEL, "master is taper charging; reducing slave FCC\n");
+
+ __pm_stay_awake(chip->pl_ws);
+ /* Reduce the taper percent by 25 percent */
+ chip->taper_pct = chip->taper_pct * TAPER_RESIDUAL_PCT / 100;
+ rerun_election(chip->fcc_votable);
+ pl_dbg(chip, PR_PARALLEL, "taper entry scheduling work after %d ms\n",
+ PL_TAPER_WORK_DELAY_MS);
+ schedule_delayed_work(&chip->pl_taper_work,
+ msecs_to_jiffies(PL_TAPER_WORK_DELAY_MS));
+ return;
+ }
+
+ /*
+ * Master back to Fast Charge, get out of this round of taper reduction
+ */
+ pl_dbg(chip, PR_PARALLEL, "master is fast charging; waiting for next taper\n");
+
+done:
+ __pm_relax(chip->pl_ws);
+}
+
+/*********
+ * FCC *
+**********/
+#define EFFICIENCY_PCT 80
+#define MICRO_5V 5000000
+static void split_fcc(struct pl_data *chip, int total_ua,
+ int *master_ua, int *slave_ua)
+{
+ int rc, effective_total_ua, slave_limited_ua, hw_cc_delta_ua = 0,
+ aicl_settled_ua, input_limited_fcc_ua;
+ union power_supply_propval pval = {0, };
+
+ rc = power_supply_get_property(chip->main_psy,
+ POWER_SUPPLY_PROP_FCC_DELTA, &pval);
+ if (rc < 0)
+ hw_cc_delta_ua = 0;
+ else
+ hw_cc_delta_ua = pval.intval;
+
+ input_limited_fcc_ua = INT_MAX;
+ if (chip->pl_mode == POWER_SUPPLY_PARALLEL_MID_MID) {
+ rc = power_supply_get_property(chip->main_psy,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
+ &pval);
+ if (rc < 0)
+ aicl_settled_ua = 0;
+ else
+ aicl_settled_ua = pval.intval;
+
+ input_limited_fcc_ua = div64_s64(
+ (s64)aicl_settled_ua * MICRO_5V * EFFICIENCY_PCT,
+ (s64)get_effective_result(chip->fv_votable)
+ * 100);
+ }
+
+ effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
+ slave_limited_ua = min(effective_total_ua, input_limited_fcc_ua);
+ *slave_ua = (slave_limited_ua * chip->slave_pct) / 100;
+ *slave_ua = (*slave_ua * chip->taper_pct) / 100;
+ *master_ua = max(0, total_ua - *slave_ua);
+}
+
+static int pl_fcc_vote_callback(struct votable *votable, void *data,
+ int total_fcc_ua, const char *client)
+{
+ struct pl_data *chip = data;
+ union power_supply_propval pval = {0, };
+ int rc, master_fcc_ua = total_fcc_ua, slave_fcc_ua = 0;
+
+ if (total_fcc_ua < 0)
+ return 0;
+
+ if (!chip->main_psy)
+ return 0;
+
+ if (chip->pl_mode == POWER_SUPPLY_PARALLEL_NONE
+ || get_effective_result_locked(chip->pl_disable_votable)) {
+ pval.intval = total_fcc_ua;
+ rc = power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ &pval);
+ if (rc < 0)
+ pr_err("Couldn't set main fcc, rc=%d\n", rc);
+ return rc;
+ }
+
+ split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
+ pval.intval = slave_fcc_ua;
+ rc = power_supply_set_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
+ return rc;
+ }
+
+ chip->slave_fcc_ua = slave_fcc_ua;
+
+ pval.intval = master_fcc_ua;
+ rc = power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
+ if (rc < 0) {
+ pr_err("Could not set main fcc, rc=%d\n", rc);
+ return rc;
+ }
+
+ pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
+ master_fcc_ua, slave_fcc_ua,
+ (master_fcc_ua * 100) / total_fcc_ua,
+ (slave_fcc_ua * 100) / total_fcc_ua);
+
+ return 0;
+}
+
+#define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000
+static int pl_fv_vote_callback(struct votable *votable, void *data,
+ int fv_uv, const char *client)
+{
+ struct pl_data *chip = data;
+ union power_supply_propval pval = {0, };
+ int rc = 0;
+
+ if (fv_uv < 0)
+ return 0;
+
+ if (!chip->main_psy)
+ return 0;
+
+ pval.intval = fv_uv;
+ rc = power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't set main fv, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (chip->pl_mode != POWER_SUPPLY_PARALLEL_NONE) {
+ pval.intval = fv_uv + PARALLEL_FLOAT_VOLTAGE_DELTA_UV;
+ rc = power_supply_set_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't set float on parallel rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static int pl_disable_vote_callback(struct votable *votable,
+ void *data, int pl_disable, const char *client)
+{
+ struct pl_data *chip = data;
+ union power_supply_propval pval = {0, };
+ int rc;
+
+ chip->settled_ua = 0;
+ chip->taper_pct = 100;
+
+ if (!pl_disable) { /* enable */
+ rerun_election(chip->fv_votable);
+ rerun_election(chip->fcc_votable);
+
+ if (chip->pl_psy) {
+ pval.intval = 0;
+ rc = power_supply_set_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
+ if (rc < 0)
+ pr_err("Couldn't change slave suspend state rc=%d\n",
+ rc);
+ }
+
+ if (chip->pl_mode == POWER_SUPPLY_PARALLEL_USBIN_USBIN)
+ split_settled(chip);
+ /*
+ * we could have been enabled while in taper mode,
+ * start the taper work if so
+ */
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get batt charge type rc=%d\n", rc);
+ } else {
+ if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
+ pl_dbg(chip, PR_PARALLEL,
+ "pl enabled in Taper scheduing work\n");
+ schedule_delayed_work(&chip->pl_taper_work, 0);
+ }
+ }
+ } else {
+ if (chip->pl_mode == POWER_SUPPLY_PARALLEL_USBIN_USBIN)
+ split_settled(chip);
+
+ if (chip->pl_psy) {
+ pval.intval = 1;
+ rc = power_supply_set_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
+ if (rc < 0)
+ pr_err("Couldn't change slave suspend state rc=%d\n",
+ rc);
+ }
+ rerun_election(chip->fcc_votable);
+ rerun_election(chip->fv_votable);
+ }
+
+ pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n",
+ pl_disable ? "disabled" : "enabled");
+
+ return 0;
+}
+
+static bool is_main_available(struct pl_data *chip)
+{
+ if (!chip->main_psy)
+ chip->main_psy = power_supply_get_by_name("main");
+
+ if (!chip->main_psy)
+ return false;
+
+ return true;
+}
+
+static bool is_batt_available(struct pl_data *chip)
+{
+ if (!chip->batt_psy)
+ chip->batt_psy = power_supply_get_by_name("battery");
+
+ if (!chip->batt_psy)
+ return false;
+
+ return true;
+}
+
+static bool is_parallel_available(struct pl_data *chip)
+{
+ union power_supply_propval pval = {0, };
+ int rc;
+
+ if (chip->pl_psy)
+ return true;
+
+ chip->pl_psy = power_supply_get_by_name("parallel");
+ if (!chip->pl_psy)
+ return false;
+
+ rc = power_supply_get_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_PARALLEL_MODE, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get parallel mode from parallel rc=%d\n",
+ rc);
+ return false;
+ }
+ /*
+ * Note that pl_mode only be udpated to anything other than a _NONE
+ * only after pl_psy is found. IOW pl_mode != _NONE implies that
+ * pl_psy is present and valid
+ */
+ chip->pl_mode = pval.intval;
+ vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);
+
+ return true;
+}
+
+static void handle_main_charge_type(struct pl_data *chip)
+{
+ union power_supply_propval pval = {0, };
+ int rc;
+
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get batt charge type rc=%d\n", rc);
+ return;
+ }
+
+ /* not fast/not taper state to disables parallel */
+ if ((pval.intval != POWER_SUPPLY_CHARGE_TYPE_FAST)
+ && (pval.intval != POWER_SUPPLY_CHARGE_TYPE_TAPER)) {
+ vote(chip->pl_disable_votable, CHG_STATE_VOTER, true, 0);
+ chip->taper_pct = 100;
+ vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0);
+ vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER,
+ false, 0);
+ chip->charge_type = pval.intval;
+ return;
+ }
+
+ /* handle fast/taper charge entry */
+ if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER
+ || pval.intval == POWER_SUPPLY_CHARGE_TYPE_FAST) {
+ pl_dbg(chip, PR_PARALLEL, "chg_state enabling parallel\n");
+ vote(chip->pl_disable_votable, CHG_STATE_VOTER, false, 0);
+ chip->charge_type = pval.intval;
+ return;
+ }
+
+ /* handle taper charge entry */
+ if (chip->charge_type == POWER_SUPPLY_CHARGE_TYPE_FAST
+ && (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER)) {
+ chip->charge_type = pval.intval;
+ pl_dbg(chip, PR_PARALLEL, "taper entry scheduling work\n");
+ schedule_delayed_work(&chip->pl_taper_work, 0);
+ return;
+ }
+
+ /* remember the new state only if it isn't any of the above */
+ chip->charge_type = pval.intval;
+}
+
+static void handle_settled_aicl_split(struct pl_data *chip)
+{
+ union power_supply_propval pval = {0, };
+ int rc;
+
+ if (!get_effective_result(chip->pl_disable_votable)
+ && chip->pl_mode == POWER_SUPPLY_PARALLEL_USBIN_USBIN) {
+ /*
+ * call aicl split only when USBIN_USBIN and enabled
+ * and if aicl changed
+ */
+ rc = power_supply_get_property(chip->main_psy,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get aicl settled value rc=%d\n", rc);
+ return;
+ }
+ if (chip->settled_ua != pval.intval) {
+ chip->settled_ua = pval.intval;
+ split_settled(chip);
+ }
+ }
+}
+
+static void handle_parallel_in_taper(struct pl_data *chip)
+{
+ union power_supply_propval pval = {0, };
+ int rc;
+
+ if (get_effective_result_locked(chip->pl_disable_votable))
+ return;
+
+ if (!chip->pl_psy)
+ return;
+
+ rc = power_supply_get_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_CHARGE_TYPE, &pval);
+ if (rc < 0) {
+ pr_err("Couldn't get pl charge type rc=%d\n", rc);
+ return;
+ }
+
+ /*
+ * if parallel is seen in taper mode ever, that is an anomaly and
+ * we disable parallel charger
+ */
+ if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
+ vote(chip->pl_disable_votable, PL_TAPER_EARLY_BAD_VOTER,
+ true, 0);
+ return;
+ }
+}
+
+static void status_change_work(struct work_struct *work)
+{
+ struct pl_data *chip = container_of(work,
+ struct pl_data, status_change_work);
+
+ if (!is_main_available(chip))
+ return;
+
+ if (!is_batt_available(chip))
+ return;
+
+ is_parallel_available(chip);
+
+ handle_main_charge_type(chip);
+ handle_settled_aicl_split(chip);
+ handle_parallel_in_taper(chip);
+}
+
+static int pl_notifier_call(struct notifier_block *nb,
+ unsigned long ev, void *v)
+{
+ struct power_supply *psy = v;
+ struct pl_data *chip = container_of(nb, struct pl_data, nb);
+
+ if (ev != PSY_EVENT_PROP_CHANGED)
+ return NOTIFY_OK;
+
+ if ((strcmp(psy->desc->name, "parallel") == 0)
+ || (strcmp(psy->desc->name, "battery") == 0))
+ schedule_work(&chip->status_change_work);
+
+ return NOTIFY_OK;
+}
+
+static int pl_register_notifier(struct pl_data *chip)
+{
+ int rc;
+
+ chip->nb.notifier_call = pl_notifier_call;
+ rc = power_supply_reg_notifier(&chip->nb);
+ if (rc < 0) {
+ pr_err("Couldn't register psy notifier rc = %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int pl_determine_initial_status(struct pl_data *chip)
+{
+ status_change_work(&chip->status_change_work);
+ return 0;
+}
+
+static int pl_init(void)
+{
+ struct pl_data *chip;
+ int rc = 0;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+ chip->slave_pct = 50;
+
+ chip->pl_ws = wakeup_source_register("qcom-battery");
+ if (!chip->pl_ws)
+ goto cleanup;
+
+ chip->fcc_votable = create_votable("FCC", VOTE_MIN,
+ pl_fcc_vote_callback,
+ chip);
+ if (IS_ERR(chip->fcc_votable)) {
+ rc = PTR_ERR(chip->fcc_votable);
+ goto release_wakeup_source;
+ }
+
+ chip->fv_votable = create_votable("FV", VOTE_MAX,
+ pl_fv_vote_callback,
+ chip);
+ if (IS_ERR(chip->fv_votable)) {
+ rc = PTR_ERR(chip->fv_votable);
+ goto destroy_votable;
+ }
+
+ chip->pl_disable_votable = create_votable("PL_DISABLE", VOTE_SET_ANY,
+ pl_disable_vote_callback,
+ chip);
+ if (IS_ERR(chip->pl_disable_votable)) {
+ rc = PTR_ERR(chip->pl_disable_votable);
+ goto destroy_votable;
+ }
+ vote(chip->pl_disable_votable, CHG_STATE_VOTER, true, 0);
+ vote(chip->pl_disable_votable, TAPER_END_VOTER, false, 0);
+ vote(chip->pl_disable_votable, PARALLEL_PSY_VOTER, true, 0);
+
+ INIT_WORK(&chip->status_change_work, status_change_work);
+ INIT_DELAYED_WORK(&chip->pl_taper_work, pl_taper_work);
+
+ rc = pl_register_notifier(chip);
+ if (rc < 0) {
+ pr_err("Couldn't register psy notifier rc = %d\n", rc);
+ goto unreg_notifier;
+ }
+
+ rc = pl_determine_initial_status(chip);
+ if (rc < 0) {
+ pr_err("Couldn't determine initial status rc=%d\n", rc);
+ goto unreg_notifier;
+ }
+
+ chip->qcom_batt_class.name = "qcom-battery",
+ chip->qcom_batt_class.owner = THIS_MODULE,
+ chip->qcom_batt_class.class_attrs = pl_attributes;
+
+ rc = class_register(&chip->qcom_batt_class);
+ if (rc < 0) {
+ pr_err("couldn't register pl_data sysfs class rc = %d\n", rc);
+ goto unreg_notifier;
+ }
+
+ return rc;
+
+unreg_notifier:
+ power_supply_unreg_notifier(&chip->nb);
+destroy_votable:
+ destroy_votable(chip->pl_disable_votable);
+ destroy_votable(chip->fv_votable);
+ destroy_votable(chip->fcc_votable);
+release_wakeup_source:
+ wakeup_source_unregister(chip->pl_ws);
+cleanup:
+ kfree(chip);
+ return rc;
+}
+
+static void pl_deinit(void)
+{
+ struct pl_data *chip = the_chip;
+
+ power_supply_unreg_notifier(&chip->nb);
+ destroy_votable(chip->pl_disable_votable);
+ destroy_votable(chip->fv_votable);
+ destroy_votable(chip->fcc_votable);
+ wakeup_source_unregister(chip->pl_ws);
+ kfree(chip);
+}
+
+module_init(pl_init);
+module_exit(pl_deinit)
+
+MODULE_DESCRIPTION("");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index a441ff310e9f..7ffa583ca01d 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -981,6 +981,38 @@ static int fg_set_esr_timer(struct fg_chip *chip, int cycles, bool charging,
/* Other functions HERE */
+static void fg_notify_charger(struct fg_chip *chip)
+{
+ union power_supply_propval prop = {0, };
+ int rc;
+
+ if (!chip->batt_psy)
+ return;
+
+ if (!chip->profile_available)
+ return;
+
+ prop.intval = chip->bp.float_volt_uv;
+ rc = power_supply_set_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
+ if (rc < 0) {
+ pr_err("Error in setting voltage_max property on batt_psy, rc=%d\n",
+ rc);
+ return;
+ }
+
+ prop.intval = chip->bp.fastchg_curr_ma * 1000;
+ rc = power_supply_set_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
+ if (rc < 0) {
+ pr_err("Error in setting constant_charge_current_max property on batt_psy, rc=%d\n",
+ rc);
+ return;
+ }
+
+ fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n");
+}
+
static int fg_awake_cb(struct votable *votable, void *data, int awake,
const char *client)
{
@@ -995,14 +1027,18 @@ static int fg_awake_cb(struct votable *votable, void *data, int awake,
return 0;
}
-static bool is_charger_available(struct fg_chip *chip)
+static bool batt_psy_initialized(struct fg_chip *chip)
{
- if (!chip->batt_psy)
- chip->batt_psy = power_supply_get_by_name("battery");
+ if (chip->batt_psy)
+ return true;
+ chip->batt_psy = power_supply_get_by_name("battery");
if (!chip->batt_psy)
return false;
+ /* batt_psy is initialized, set the fcc and fv */
+ fg_notify_charger(chip);
+
return true;
}
@@ -1359,7 +1395,7 @@ static int fg_charge_full_update(struct fg_chip *chip)
if (!chip->dt.hold_soc_while_full)
return 0;
- if (!is_charger_available(chip))
+ if (!batt_psy_initialized(chip))
return 0;
rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH,
@@ -1723,7 +1759,7 @@ static void status_change_work(struct work_struct *work)
union power_supply_propval prop = {0, };
int rc;
- if (!is_charger_available(chip)) {
+ if (!batt_psy_initialized(chip)) {
fg_dbg(chip, FG_STATUS, "Charger not available?!\n");
goto out;
}
@@ -2040,37 +2076,6 @@ out:
return rc;
}
-static void fg_notify_charger(struct fg_chip *chip)
-{
- union power_supply_propval prop = {0, };
- int rc;
-
- if (!is_charger_available(chip)) {
- pr_warn("Charger not available yet?\n");
- return;
- }
-
- prop.intval = chip->bp.float_volt_uv;
- rc = power_supply_set_property(chip->batt_psy,
- POWER_SUPPLY_PROP_VOLTAGE_MAX, &prop);
- if (rc < 0) {
- pr_err("Error in setting voltage_max property on batt_psy, rc=%d\n",
- rc);
- return;
- }
-
- prop.intval = chip->bp.fastchg_curr_ma * 1000;
- rc = power_supply_set_property(chip->batt_psy,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop);
- if (rc < 0) {
- pr_err("Error in setting constant_charge_current_max property on batt_psy, rc=%d\n",
- rc);
- return;
- }
-
- fg_dbg(chip, FG_STATUS, "Notified charger on float voltage and FCC\n");
-}
-
static void profile_load_work(struct work_struct *work)
{
struct fg_chip *chip = container_of(work,
@@ -2136,6 +2141,7 @@ done:
rc);
}
+ batt_psy_initialized(chip);
fg_notify_charger(chip);
chip->profile_loaded = true;
chip->soc_reporting_ready = true;
@@ -2296,7 +2302,7 @@ static int fg_get_time_to_full(struct fg_chip *chip, int *val)
return -ENODATA;
}
- if (!is_charger_available(chip)) {
+ if (!batt_psy_initialized(chip)) {
fg_dbg(chip, FG_TTF, "charger is not available\n");
return -ENODATA;
}
@@ -3004,7 +3010,7 @@ static irqreturn_t fg_delta_batt_temp_irq_handler(int irq, void *data)
if (rc < 0)
pr_err("Error in configuring ESR filter rc:%d\n", rc);
- if (!is_charger_available(chip)) {
+ if (!batt_psy_initialized(chip)) {
chip->last_batt_temp = batt_temp;
return IRQ_HANDLED;
}
@@ -3062,7 +3068,7 @@ static irqreturn_t fg_delta_soc_irq_handler(int irq, void *data)
if (rc < 0)
pr_err("Error in adjusting ki_coeff_dischg, rc=%d\n", rc);
- if (is_charger_available(chip))
+ if (batt_psy_initialized(chip))
power_supply_changed(chip->batt_psy);
return IRQ_HANDLED;
@@ -3073,7 +3079,7 @@ static irqreturn_t fg_empty_soc_irq_handler(int irq, void *data)
struct fg_chip *chip = data;
fg_dbg(chip, FG_IRQ, "irq %d triggered\n", irq);
- if (is_charger_available(chip))
+ if (batt_psy_initialized(chip))
power_supply_changed(chip->batt_psy);
return IRQ_HANDLED;
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 8dc93f42b059..dea932ae37ad 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -479,7 +479,7 @@ static int smb2_usb_get_prop(struct power_supply *psy,
rc = smblib_get_pe_start(chg, val);
break;
default:
- pr_err("get prop %d is not supported\n", psp);
+ pr_err("get prop %d is not supported in usb\n", psp);
rc = -EINVAL;
break;
}
@@ -574,6 +574,118 @@ static int smb2_init_usb_psy(struct smb2 *chip)
return 0;
}
+/*****************************
+ * USB MAIN PSY REGISTRATION *
+ *****************************/
+
+static enum power_supply_property smb2_usb_main_props[] = {
+ POWER_SUPPLY_PROP_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_ICL_REDUCTION,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_TYPE,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
+ POWER_SUPPLY_PROP_FCC_DELTA,
+ /*
+ * TODO move the TEMP and TEMP_MAX properties here,
+ * and update the thermal balancer to look here
+ */
+};
+
+static int smb2_usb_main_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct smb2 *chip = power_supply_get_drvdata(psy);
+ struct smb_charger *chg = &chip->chg;
+ int rc = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_ICL_REDUCTION:
+ val->intval = chg->icl_reduction_ua;
+ break;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+ rc = smblib_get_charge_param(chg, &chg->param.fcc,
+ &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_TYPE:
+ val->intval = POWER_SUPPLY_TYPE_MAIN;
+ break;
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED:
+ rc = smblib_get_prop_input_current_settled(chg, val);
+ break;
+ case POWER_SUPPLY_PROP_FCC_DELTA:
+ rc = smblib_get_prop_fcc_delta(chg, val);
+ break;
+ default:
+ pr_err("get prop %d is not supported in usb-main\n", psp);
+ rc = -EINVAL;
+ break;
+ }
+ if (rc < 0) {
+ pr_debug("Couldn't get prop %d rc = %d\n", psp, rc);
+ return -ENODATA;
+ }
+ return 0;
+}
+
+static int smb2_usb_main_set_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct smb2 *chip = power_supply_get_drvdata(psy);
+ struct smb_charger *chg = &chip->chg;
+ int rc = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+ rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval);
+ break;
+ case POWER_SUPPLY_PROP_ICL_REDUCTION:
+ chg->icl_reduction_ua = val->intval;
+ rc = rerun_election(chg->usb_icl_votable);
+ break;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+ rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
+ break;
+ default:
+ pr_err("set prop %d is not supported\n", psp);
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+static const struct power_supply_desc usb_main_psy_desc = {
+ .name = "main",
+ .type = POWER_SUPPLY_TYPE_MAIN,
+ .properties = smb2_usb_main_props,
+ .num_properties = ARRAY_SIZE(smb2_usb_main_props),
+ .get_property = smb2_usb_main_get_prop,
+ .set_property = smb2_usb_main_set_prop,
+};
+
+static int smb2_init_usb_main_psy(struct smb2 *chip)
+{
+ struct power_supply_config usb_main_cfg = {};
+ struct smb_charger *chg = &chip->chg;
+
+ usb_main_cfg.drv_data = chip;
+ usb_main_cfg.of_node = chg->dev->of_node;
+ chg->usb_main_psy = devm_power_supply_register(chg->dev,
+ &usb_main_psy_desc,
+ &usb_main_cfg);
+ if (IS_ERR(chg->usb_main_psy)) {
+ pr_err("Couldn't register USB main power supply\n");
+ return PTR_ERR(chg->usb_main_psy);
+ }
+
+ return 0;
+}
+
/*************************
* DC PSY REGISTRATION *
*************************/
@@ -701,7 +813,6 @@ static enum power_supply_property smb2_batt_props[] = {
POWER_SUPPLY_PROP_STEP_CHARGING_STEP,
POWER_SUPPLY_PROP_CHARGE_DONE,
POWER_SUPPLY_PROP_PARALLEL_DISABLE,
- POWER_SUPPLY_PROP_PARALLEL_PERCENT,
POWER_SUPPLY_PROP_SET_SHIP_MODE,
};
@@ -775,9 +886,6 @@ static int smb2_batt_get_prop(struct power_supply *psy,
val->intval = get_client_vote(chg->pl_disable_votable,
USER_VOTER);
break;
- case POWER_SUPPLY_PROP_PARALLEL_PERCENT:
- val->intval = chg->pl.slave_pct;
- break;
case POWER_SUPPLY_PROP_SET_SHIP_MODE:
/* Not in ship mode as long as device is active */
val->intval = 0;
@@ -815,12 +923,6 @@ static int smb2_batt_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
vote(chg->pl_disable_votable, USER_VOTER, (bool)val->intval, 0);
break;
- case POWER_SUPPLY_PROP_PARALLEL_PERCENT:
- if (val->intval < 0 || val->intval > 100)
- return -EINVAL;
- chg->pl.slave_pct = val->intval;
- rerun_election(chg->fcc_votable);
- break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
vote(chg->fv_votable, DEFAULT_VOTER, true, val->intval);
break;
@@ -848,7 +950,6 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy,
case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
case POWER_SUPPLY_PROP_CAPACITY:
case POWER_SUPPLY_PROP_PARALLEL_DISABLE:
- case POWER_SUPPLY_PROP_PARALLEL_PERCENT:
return 1;
default:
break;
@@ -1226,12 +1327,6 @@ static int smb2_init_hw(struct smb2 *chip)
}
/* votes must be cast before configuring software control */
- vote(chg->pl_disable_votable,
- PL_INDIRECT_VOTER, true, 0);
- vote(chg->pl_disable_votable,
- CHG_STATE_VOTER, true, 0);
- vote(chg->pl_disable_votable,
- PARALLEL_PSY_VOTER, true, 0);
vote(chg->usb_suspend_votable,
DEFAULT_VOTER, chip->dt.no_battery, 0);
vote(chg->dc_suspend_votable,
@@ -1821,7 +1916,6 @@ static int smb2_probe(struct platform_device *pdev)
struct smb2 *chip;
struct smb_charger *chg;
int rc = 0;
- u8 stat;
union power_supply_propval val;
int usb_present, batt_present, batt_health, batt_charge_type;
@@ -1912,20 +2006,12 @@ static int smb2_probe(struct platform_device *pdev)
goto cleanup;
}
- rc = smblib_read(chg, SHDN_CMD_REG, &stat);
+ rc = smb2_init_usb_main_psy(chip);
if (rc < 0) {
- pr_err("Couldn't read MISC_SHDN_CMD_REG rc=%d\n", rc);
- return rc;
- }
-
- if (stat) {
- pr_err("bad charger part; faking USB insertion\n");
- chip->bad_part = true;
- power_supply_changed(chg->usb_psy);
- return 0;
+ pr_err("Couldn't initialize usb psy rc=%d\n", rc);
+ goto cleanup;
}
- chg->pl.slave_pct = 50;
rc = smb2_init_batt_psy(chip);
if (rc < 0) {
pr_err("Couldn't initialize batt psy rc=%d\n", rc);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 2f612884fe0e..022ed49ce6eb 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -39,7 +39,6 @@
static bool is_secure(struct smb_charger *chg, int addr)
{
-
if (addr == SHIP_MODE_REG)
return true;
/* assume everything above 0xA0 is secure */
@@ -152,36 +151,6 @@ static int smblib_get_jeita_cc_delta(struct smb_charger *chg, int *cc_delta_ua)
return 0;
}
-static void smblib_split_fcc(struct smb_charger *chg, int total_ua,
- int *master_ua, int *slave_ua)
-{
- int rc, jeita_cc_delta_ua, step_cc_delta_ua, effective_total_ua,
- slave_limited_ua, hw_cc_delta_ua = 0;
-
- rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
- step_cc_delta_ua = 0;
- } else {
- hw_cc_delta_ua = step_cc_delta_ua;
- }
-
- rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
- jeita_cc_delta_ua = 0;
- } else if (jeita_cc_delta_ua < 0) {
- /* HW will take the min between JEITA and step charge */
- hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
- }
-
- effective_total_ua = max(0, total_ua + hw_cc_delta_ua);
- slave_limited_ua = min(effective_total_ua, chg->input_limited_fcc_ua);
- *slave_ua = (slave_limited_ua * chg->pl.slave_pct) / 100;
- *slave_ua = (*slave_ua * chg->pl.taper_pct) / 100;
- *master_ua = max(0, total_ua - *slave_ua);
-}
-
/********************
* REGISTER GETTERS *
********************/
@@ -536,10 +505,8 @@ static int smblib_notifier_call(struct notifier_block *nb,
schedule_work(&chg->bms_update_work);
}
- if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) {
+ if (!chg->pl.psy && !strcmp(psy->desc->name, "usb-parallel"))
chg->pl.psy = psy;
- schedule_work(&chg->pl_detect_work);
- }
return NOTIFY_OK;
}
@@ -600,8 +567,6 @@ static void smblib_uusb_removal(struct smb_charger *chg)
/* reset both usbin current and voltage votes */
vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
- /* reset taper_end voter here */
- vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
@@ -729,84 +694,6 @@ static int smblib_fcc_max_vote_callback(struct votable *votable, void *data,
return vote(chg->fcc_votable, FCC_MAX_RESULT_VOTER, true, fcc_ua);
}
-static int smblib_fcc_vote_callback(struct votable *votable, void *data,
- int total_fcc_ua, const char *client)
-{
- struct smb_charger *chg = data;
- union power_supply_propval pval = {0, };
- int rc, master_fcc_ua = total_fcc_ua, slave_fcc_ua = 0;
-
- if (total_fcc_ua < 0)
- return 0;
-
- if (chg->mode == PARALLEL_MASTER
- && !get_effective_result_locked(chg->pl_disable_votable)) {
- smblib_split_fcc(chg, total_fcc_ua, &master_fcc_ua,
- &slave_fcc_ua);
-
- /*
- * parallel charger is not disabled, implying that
- * chg->pl.psy exists
- */
- pval.intval = slave_fcc_ua;
- rc = power_supply_set_property(chg->pl.psy,
- POWER_SUPPLY_PROP_CURRENT_MAX, &pval);
- if (rc < 0) {
- smblib_err(chg, "Could not set parallel fcc, rc=%d\n",
- rc);
- return rc;
- }
-
- chg->pl.slave_fcc_ua = slave_fcc_ua;
- }
-
- rc = smblib_set_charge_param(chg, &chg->param.fcc, master_fcc_ua);
- if (rc < 0) {
- smblib_err(chg, "Couldn't set master fcc rc=%d\n", rc);
- return rc;
- }
-
- smblib_dbg(chg, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
- master_fcc_ua, slave_fcc_ua,
- (master_fcc_ua * 100) / total_fcc_ua,
- (slave_fcc_ua * 100) / total_fcc_ua);
-
- return 0;
-}
-
-#define PARALLEL_FLOAT_VOLTAGE_DELTA_UV 50000
-static int smblib_fv_vote_callback(struct votable *votable, void *data,
- int fv_uv, const char *client)
-{
- struct smb_charger *chg = data;
- union power_supply_propval pval = {0, };
- int rc = 0;
-
- if (fv_uv < 0) {
- smblib_dbg(chg, PR_MISC, "No Voter\n");
- return 0;
- }
-
- rc = smblib_set_charge_param(chg, &chg->param.fv, fv_uv);
- if (rc < 0) {
- smblib_err(chg, "Couldn't set floating voltage rc=%d\n", rc);
- return rc;
- }
-
- if (chg->mode == PARALLEL_MASTER && chg->pl.psy) {
- pval.intval = fv_uv + PARALLEL_FLOAT_VOLTAGE_DELTA_UV;
- rc = power_supply_set_property(chg->pl.psy,
- POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval);
- if (rc < 0) {
- smblib_err(chg,
- "Couldn't set float on parallel rc=%d\n", rc);
- return rc;
- }
- }
-
- return 0;
-}
-
#define USBIN_25MA 25000
#define USBIN_100MA 100000
#define USBIN_150MA 150000
@@ -947,35 +834,6 @@ static int smblib_awake_vote_callback(struct votable *votable, void *data,
return 0;
}
-static int smblib_pl_disable_vote_callback(struct votable *votable, void *data,
- int pl_disable, const char *client)
-{
- struct smb_charger *chg = data;
- union power_supply_propval pval = {0, };
- int rc;
-
- if (chg->mode != PARALLEL_MASTER || !chg->pl.psy)
- return 0;
-
- chg->pl.taper_pct = 100;
- rerun_election(chg->fv_votable);
- rerun_election(chg->fcc_votable);
-
- pval.intval = pl_disable;
- rc = power_supply_set_property(chg->pl.psy,
- POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
- if (rc < 0) {
- smblib_err(chg,
- "Couldn't change slave suspend state rc=%d\n", rc);
- return rc;
- }
-
- smblib_dbg(chg, PR_PARALLEL, "parallel charging %s\n",
- pl_disable ? "disabled" : "enabled");
-
- return 0;
-}
-
static int smblib_chg_disable_vote_callback(struct votable *votable, void *data,
int chg_disable, const char *client)
{
@@ -2359,6 +2217,39 @@ int smblib_set_prop_ship_mode(struct smb_charger *chg,
return rc;
}
+/***********************
+* USB MAIN PSY GETTERS *
+*************************/
+int smblib_get_prop_fcc_delta(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ int rc, jeita_cc_delta_ua, step_cc_delta_ua, hw_cc_delta_ua = 0;
+
+ rc = smblib_get_step_cc_delta(chg, &step_cc_delta_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get step cc delta rc=%d\n", rc);
+ step_cc_delta_ua = 0;
+ } else {
+ hw_cc_delta_ua = step_cc_delta_ua;
+ }
+
+ rc = smblib_get_jeita_cc_delta(chg, &jeita_cc_delta_ua);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't get jeita cc delta rc=%d\n", rc);
+ jeita_cc_delta_ua = 0;
+ } else if (jeita_cc_delta_ua < 0) {
+ /* HW will take the min between JEITA and step charge */
+ hw_cc_delta_ua = min(hw_cc_delta_ua, jeita_cc_delta_ua);
+ }
+
+ val->intval = hw_cc_delta_ua;
+ return 0;
+}
+
+/***********************
+* USB MAIN PSY SETTERS *
+*************************/
+
int smblib_reg_block_update(struct smb_charger *chg,
struct reg_info *entry)
{
@@ -2623,35 +2514,6 @@ unlock:
return IRQ_HANDLED;
}
-static void smblib_pl_handle_chg_state_change(struct smb_charger *chg, u8 stat)
-{
- bool pl_enabled;
-
- if (chg->mode != PARALLEL_MASTER)
- return;
-
- pl_enabled = !get_effective_result_locked(chg->pl_disable_votable);
- switch (stat) {
- case FAST_CHARGE:
- case FULLON_CHARGE:
- vote(chg->pl_disable_votable, CHG_STATE_VOTER, false, 0);
- break;
- case TAPER_CHARGE:
- if (pl_enabled) {
- cancel_delayed_work_sync(&chg->pl_taper_work);
- schedule_delayed_work(&chg->pl_taper_work, 0);
- }
- break;
- case TERMINATE_CHARGE:
- case INHIBIT_CHARGE:
- case DISABLE_CHARGE:
- vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
- break;
- default:
- break;
- }
-}
-
irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
@@ -2669,7 +2531,6 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data)
}
stat = stat & BATTERY_CHARGER_STATUS_MASK;
- smblib_pl_handle_chg_state_change(chg, stat);
power_supply_changed(chg->batt_psy);
return IRQ_HANDLED;
}
@@ -2819,16 +2680,15 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
}
#define USB_WEAK_INPUT_UA 1400000
-#define EFFICIENCY_PCT 80
irqreturn_t smblib_handle_icl_change(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
- int rc, icl_ua;
+ int rc, settled_ua;
smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
- rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &icl_ua);
+ rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't get ICL status rc=%d\n", rc);
return IRQ_HANDLED;
@@ -2837,15 +2697,10 @@ irqreturn_t smblib_handle_icl_change(int irq, void *data)
if (chg->mode != PARALLEL_MASTER)
return IRQ_HANDLED;
- chg->input_limited_fcc_ua = div64_s64(
- (s64)icl_ua * MICRO_5V * EFFICIENCY_PCT,
- (s64)get_effective_result(chg->fv_votable) * 100);
-
- if (!get_effective_result(chg->pl_disable_votable))
- rerun_election(chg->fcc_votable);
+ power_supply_changed(chg->usb_main_psy);
vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER,
- icl_ua >= USB_WEAK_INPUT_UA, 0);
+ settled_ua >= USB_WEAK_INPUT_UA, 0);
return IRQ_HANDLED;
}
@@ -3063,12 +2918,9 @@ static void typec_source_removal(struct smb_charger *chg)
{
int rc;
- vote(chg->pl_disable_votable, TYPEC_SRC_VOTER, true, 0);
/* reset both usbin current and voltage votes */
vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
- /* reset taper_end voter here */
- vote(chg->pl_disable_votable, TAPER_END_VOTER, false, 0);
cancel_delayed_work_sync(&chg->hvdcp_detect_work);
@@ -3101,7 +2953,6 @@ static void typec_source_removal(struct smb_charger *chg)
static void typec_source_insertion(struct smb_charger *chg)
{
- vote(chg->pl_disable_votable, TYPEC_SRC_VOTER, false, 0);
}
static void typec_sink_insertion(struct smb_charger *chg)
@@ -3435,58 +3286,6 @@ static void step_soc_req_work(struct work_struct *work)
step_charge_soc_update(chg, pval.intval);
}
-static void smblib_pl_detect_work(struct work_struct *work)
-{
- struct smb_charger *chg = container_of(work, struct smb_charger,
- pl_detect_work);
-
- vote(chg->pl_disable_votable, PARALLEL_PSY_VOTER, false, 0);
-}
-
-#define MINIMUM_PARALLEL_FCC_UA 500000
-#define PL_TAPER_WORK_DELAY_MS 100
-#define TAPER_RESIDUAL_PCT 75
-static void smblib_pl_taper_work(struct work_struct *work)
-{
- struct smb_charger *chg = container_of(work, struct smb_charger,
- pl_taper_work.work);
- union power_supply_propval pval = {0, };
- int rc;
-
- smblib_dbg(chg, PR_PARALLEL, "starting parallel taper work\n");
- if (chg->pl.slave_fcc_ua < MINIMUM_PARALLEL_FCC_UA) {
- smblib_dbg(chg, PR_PARALLEL, "parallel taper is done\n");
- vote(chg->pl_disable_votable, TAPER_END_VOTER, true, 0);
- goto done;
- }
-
- rc = smblib_get_prop_batt_charge_type(chg, &pval);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get batt charge type rc=%d\n", rc);
- goto done;
- }
-
- if (pval.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER) {
- smblib_dbg(chg, PR_PARALLEL, "master is taper charging; reducing slave FCC\n");
- vote(chg->awake_votable, PL_TAPER_WORK_RUNNING_VOTER, true, 0);
- /* Reduce the taper percent by 25 percent */
- chg->pl.taper_pct = chg->pl.taper_pct
- * TAPER_RESIDUAL_PCT / 100;
- rerun_election(chg->fcc_votable);
- schedule_delayed_work(&chg->pl_taper_work,
- msecs_to_jiffies(PL_TAPER_WORK_DELAY_MS));
- return;
- }
-
- /*
- * Master back to Fast Charge, get out of this round of taper reduction
- */
- smblib_dbg(chg, PR_PARALLEL, "master is fast charging; waiting for next taper\n");
-
-done:
- vote(chg->awake_votable, PL_TAPER_WORK_RUNNING_VOTER, false, 0);
-}
-
static void clear_hdc_work(struct work_struct *work)
{
struct smb_charger *chg = container_of(work, struct smb_charger,
@@ -3591,19 +3390,15 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
- chg->fcc_votable = create_votable("FCC", VOTE_MIN,
- smblib_fcc_vote_callback,
- chg);
- if (IS_ERR(chg->fcc_votable)) {
- rc = PTR_ERR(chg->fcc_votable);
+ chg->fcc_votable = find_votable("FCC");
+ if (!chg->fcc_votable) {
+ rc = -EPROBE_DEFER;
return rc;
}
- chg->fv_votable = create_votable("FV", VOTE_MAX,
- smblib_fv_vote_callback,
- chg);
- if (IS_ERR(chg->fv_votable)) {
- rc = PTR_ERR(chg->fv_votable);
+ chg->fv_votable = find_votable("FV");
+ if (!chg->fv_votable) {
+ rc = -EPROBE_DEFER;
return rc;
}
@@ -3646,13 +3441,12 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
- chg->pl_disable_votable = create_votable("PL_DISABLE", VOTE_SET_ANY,
- smblib_pl_disable_vote_callback,
- chg);
- if (IS_ERR(chg->pl_disable_votable)) {
- rc = PTR_ERR(chg->pl_disable_votable);
+ chg->pl_disable_votable = find_votable("PL_DISABLE");
+ if (!chg->pl_disable_votable) {
+ rc = -EPROBE_DEFER;
return rc;
}
+ vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0);
chg->chg_disable_votable = create_votable("CHG_DISABLE", VOTE_SET_ANY,
smblib_chg_disable_vote_callback,
@@ -3710,10 +3504,6 @@ static void smblib_destroy_votables(struct smb_charger *chg)
destroy_votable(chg->dc_suspend_votable);
if (chg->fcc_max_votable)
destroy_votable(chg->fcc_max_votable);
- if (chg->fcc_votable)
- destroy_votable(chg->fcc_votable);
- if (chg->fv_votable)
- destroy_votable(chg->fv_votable);
if (chg->usb_icl_votable)
destroy_votable(chg->usb_icl_votable);
if (chg->dc_icl_votable)
@@ -3724,8 +3514,6 @@ static void smblib_destroy_votables(struct smb_charger *chg)
destroy_votable(chg->pd_allowed_votable);
if (chg->awake_votable)
destroy_votable(chg->awake_votable);
- if (chg->pl_disable_votable)
- destroy_votable(chg->pl_disable_votable);
if (chg->chg_disable_votable)
destroy_votable(chg->chg_disable_votable);
if (chg->pl_enable_votable_indirect)
@@ -3755,10 +3543,8 @@ int smblib_init(struct smb_charger *chg)
mutex_init(&chg->write_lock);
mutex_init(&chg->otg_overcurrent_lock);
INIT_WORK(&chg->bms_update_work, bms_update_work);
- INIT_WORK(&chg->pl_detect_work, smblib_pl_detect_work);
INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
- INIT_DELAYED_WORK(&chg->pl_taper_work, smblib_pl_taper_work);
INIT_DELAYED_WORK(&chg->step_soc_req_work, step_soc_req_work);
INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
chg->fake_capacity = -EINVAL;
@@ -3780,10 +3566,7 @@ int smblib_init(struct smb_charger *chg)
}
chg->bms_psy = power_supply_get_by_name("bms");
- chg->pl.psy = power_supply_get_by_name("parallel");
- if (chg->pl.psy)
- vote(chg->pl_disable_votable, PARALLEL_PSY_VOTER,
- false, 0);
+ chg->pl.psy = power_supply_get_by_name("usb-parallel");
break;
case PARALLEL_SLAVE:
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index a4121224b121..b3fce23c6508 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -32,7 +32,6 @@ enum print_reason {
#define DCP_VOTER "DCP_VOTER"
#define USB_PSY_VOTER "USB_PSY_VOTER"
#define PL_TAPER_WORK_RUNNING_VOTER "PL_TAPER_WORK_RUNNING_VOTER"
-#define PARALLEL_PSY_VOTER "PARALLEL_PSY_VOTER"
#define PL_INDIRECT_VOTER "PL_INDIRECT_VOTER"
#define USBIN_I_VOTER "USBIN_I_VOTER"
#define USBIN_V_VOTER "USBIN_V_VOTER"
@@ -128,9 +127,6 @@ struct smb_params {
struct parallel_params {
struct power_supply *psy;
- int slave_pct;
- int taper_pct;
- int slave_fcc_ua;
};
struct smb_iio {
@@ -170,6 +166,7 @@ struct smb_charger {
struct power_supply *dc_psy;
struct power_supply *bms_psy;
struct power_supply_desc usb_psy_desc;
+ struct power_supply *usb_main_psy;
/* notifiers */
struct notifier_block nb;
@@ -202,11 +199,9 @@ struct smb_charger {
/* work */
struct work_struct bms_update_work;
- struct work_struct pl_detect_work;
struct work_struct rdstd_cc2_detach_work;
struct delayed_work hvdcp_detect_work;
struct delayed_work ps_change_timeout_work;
- struct delayed_work pl_taper_work;
struct delayed_work step_soc_req_work;
struct delayed_work clear_hdc_work;
@@ -226,7 +221,6 @@ struct smb_charger {
bool is_hdc;
bool chg_done;
bool micro_usb_mode;
- int input_limited_fcc_ua;
bool otg_en;
bool vconn_en;
int otg_attempts;
@@ -240,6 +234,8 @@ struct smb_charger {
/* extcon for VBUS / ID notification to USB for uUSB */
struct extcon_dev *extcon;
bool usb_ever_removed;
+
+ int icl_reduction_ua;
};
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
@@ -386,6 +382,8 @@ int smblib_set_prop_ship_mode(struct smb_charger *chg,
const union power_supply_propval *val);
void smblib_suspend_on_debug_battery(struct smb_charger *chg);
int smblib_rerun_apsd_if_required(struct smb_charger *chg);
+int smblib_get_prop_fcc_delta(struct smb_charger *chg,
+ union power_supply_propval *val);
int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb1351-charger.c b/drivers/power/supply/qcom/smb1351-charger.c
index e9d8c0e08447..0c2943c7f2df 100644
--- a/drivers/power/supply/qcom/smb1351-charger.c
+++ b/drivers/power/supply/qcom/smb1351-charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1414,6 +1414,7 @@ static enum power_supply_property smb1351_parallel_properties[] = {
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_PARALLEL_MODE,
};
static int smb1351_parallel_set_chg_present(struct smb1351_charger *chip,
@@ -1667,6 +1668,12 @@ static int smb1351_parallel_get_property(struct power_supply *psy,
else
val->intval = 0;
break;
+ case POWER_SUPPLY_PROP_PARALLEL_MODE:
+ if (chip->parallel_charger_present)
+ val->intval = POWER_SUPPLY_PARALLEL_USBIN_USBIN;
+ else
+ val->intval = POWER_SUPPLY_PARALLEL_NONE;
+ break;
default:
return -EINVAL;
}
@@ -3158,8 +3165,8 @@ static int smb1351_parallel_charger_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip);
- chip->parallel_psy_d.name = "usb-parallel";
- chip->parallel_psy_d.type = POWER_SUPPLY_TYPE_USB_PARALLEL;
+ chip->parallel_psy_d.name = "parallel";
+ chip->parallel_psy_d.type = POWER_SUPPLY_TYPE_PARALLEL;
chip->parallel_psy_d.get_property = smb1351_parallel_get_property;
chip->parallel_psy_d.set_property = smb1351_parallel_set_property;
chip->parallel_psy_d.properties = smb1351_parallel_properties;
diff --git a/drivers/power/supply/qcom/smb135x-charger.c b/drivers/power/supply/qcom/smb135x-charger.c
index 65d4ae56ff83..08af01544590 100644
--- a/drivers/power/supply/qcom/smb135x-charger.c
+++ b/drivers/power/supply/qcom/smb135x-charger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -4378,8 +4378,8 @@ static int smb135x_parallel_charger_probe(struct i2c_client *client,
i2c_set_clientdata(client, chip);
- chip->parallel_psy_d.name = "usb-parallel";
- chip->parallel_psy_d.type = POWER_SUPPLY_TYPE_USB_PARALLEL;
+ chip->parallel_psy_d.name = "parallel";
+ chip->parallel_psy_d.type = POWER_SUPPLY_TYPE_PARALLEL;
chip->parallel_psy_d.get_property = smb135x_parallel_get_property;
chip->parallel_psy_d.set_property = smb135x_parallel_set_property;
chip->parallel_psy_d.properties = smb135x_parallel_properties;
diff --git a/drivers/power/supply/qcom/smb138x-charger.c b/drivers/power/supply/qcom/smb138x-charger.c
index c836e780fc86..ae15fef6c3a6 100644
--- a/drivers/power/supply/qcom/smb138x-charger.c
+++ b/drivers/power/supply/qcom/smb138x-charger.c
@@ -409,11 +409,12 @@ static enum power_supply_property smb138x_parallel_props[] = {
POWER_SUPPLY_PROP_PIN_ENABLED,
POWER_SUPPLY_PROP_INPUT_SUSPEND,
POWER_SUPPLY_PROP_VOLTAGE_MAX,
- POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CHARGER_TEMP,
POWER_SUPPLY_PROP_CHARGER_TEMP_MAX,
POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_PARALLEL_MODE,
};
static int smb138x_parallel_get_prop(struct power_supply *psy,
@@ -447,7 +448,7 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_get_charge_param(chg, &chg->param.fv, &val->intval);
break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
rc = smblib_get_charge_param(chg, &chg->param.fcc,
&val->intval);
break;
@@ -463,6 +464,9 @@ static int smb138x_parallel_get_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = "smb138x";
break;
+ case POWER_SUPPLY_PROP_PARALLEL_MODE:
+ val->intval = POWER_SUPPLY_PARALLEL_MID_MID;
+ break;
default:
pr_err("parallel power supply get prop %d not supported\n",
prop);
@@ -516,7 +520,7 @@ static int smb138x_parallel_set_prop(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_MAX:
rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval);
break;
- case POWER_SUPPLY_PROP_CURRENT_MAX:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval);
break;
case POWER_SUPPLY_PROP_BUCK_FREQ:
@@ -540,7 +544,7 @@ static int smb138x_parallel_prop_is_writeable(struct power_supply *psy,
static const struct power_supply_desc parallel_psy_desc = {
.name = "parallel",
- .type = POWER_SUPPLY_TYPE_USB_PARALLEL,
+ .type = POWER_SUPPLY_TYPE_PARALLEL,
.properties = smb138x_parallel_props,
.num_properties = ARRAY_SIZE(smb138x_parallel_props),
.get_property = smb138x_parallel_get_prop,
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index de35fe9441fe..6a495ea6c523 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -104,6 +104,12 @@ enum {
POWER_SUPPLY_DP_DM_ICL_UP = 12,
};
+enum {
+ POWER_SUPPLY_PARALLEL_NONE,
+ POWER_SUPPLY_PARALLEL_USBIN_USBIN,
+ POWER_SUPPLY_PARALLEL_MID_MID,
+};
+
enum power_supply_property {
/* Properties of type `int' */
POWER_SUPPLY_PROP_STATUS = 0,
@@ -229,6 +235,9 @@ enum power_supply_property {
POWER_SUPPLY_PROP_SET_SHIP_MODE,
POWER_SUPPLY_PROP_SOC_REPORTING_READY,
POWER_SUPPLY_PROP_DEBUG_BATTERY,
+ POWER_SUPPLY_PROP_FCC_DELTA,
+ POWER_SUPPLY_PROP_ICL_REDUCTION,
+ POWER_SUPPLY_PROP_PARALLEL_MODE,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
@@ -252,9 +261,10 @@ enum power_supply_type {
POWER_SUPPLY_TYPE_USB_PD, /* Power Delivery */
POWER_SUPPLY_TYPE_WIRELESS, /* Accessory Charger Adapters */
POWER_SUPPLY_TYPE_BMS, /* Battery Monitor System */
- POWER_SUPPLY_TYPE_USB_PARALLEL, /* USB Parallel Path */
- POWER_SUPPLY_TYPE_WIPOWER, /* Wipower */
- POWER_SUPPLY_TYPE_TYPEC, /*Type-C */
+ POWER_SUPPLY_TYPE_PARALLEL, /* Parallel Path */
+ POWER_SUPPLY_TYPE_MAIN, /* Main Path */
+ POWER_SUPPLY_TYPE_WIPOWER, /* Wipower */
+ POWER_SUPPLY_TYPE_TYPEC, /* Type-C */
POWER_SUPPLY_TYPE_UFP, /* Type-C UFP */
POWER_SUPPLY_TYPE_DFP, /* TYpe-C DFP */
};