At present charger manager support only regulator based charging
control. But most of the charger drivers are registered with power
supply subsystem. This patch adds support for power supply based
charging control along with the regulator based control. With the
patch, charging control can be done either using power supply
interface or with regulator interface. The charging is setup
based on battery parameters received through the battery info
handlers.
Signed-off-by: Jenny TC
---
drivers/power/charger-manager.c | 486 +
include/linux/power/charger-manager.h | 30 +-
2 files changed, 399 insertions(+), 117 deletions(-)
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 14b0d85..b455ac2 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -42,6 +42,7 @@ static const char * const default_event_names[] = {
[CM_EVENT_BATT_OUT] = "Battery Pulled Out",
[CM_EVENT_BATT_OVERHEAT] = "Battery Overheat",
[CM_EVENT_BATT_COLD] = "Battery Cold",
+ [CM_EVENT_BATT_TZONE_CHANGE] = "Battery Temp Zone Change",
[CM_EVENT_EXT_PWR_IN_OUT] = "External Power Attach/Detach",
[CM_EVENT_CHG_START_STOP] = "Charging Start/Stop",
[CM_EVENT_OTHERS] = "Other battery events"
@@ -81,6 +82,97 @@ static unsigned long next_polling; /* Next appointed polling
time */
static struct workqueue_struct *cm_wq; /* init at driver add */
static struct delayed_work cm_monitor_work; /* init at driver add */
+static inline int psy_set_charger_contol_prop(struct power_supply *psy,
+ enum psy_charger_control_property pscp,
+ const union power_supply_propval *val)
+{
+ struct power_supply_charger *psyc;
+
+ psyc = psy->psy_charger;
+
+ if (psyc && psyc->set_property)
+ return psyc->set_property(psyc, pscp, val);
+
+ return -EINVAL;
+}
+
+static inline int psy_get_charger_contol_prop(struct power_supply *psy,
+ enum psy_charger_control_property pscp,
+ union power_supply_propval *val)
+{
+ struct power_supply_charger *psyc;
+
+ psyc = psy->psy_charger;
+
+ if (psyc && psyc->get_property)
+ return psyc->get_property(psyc, pscp, val);
+
+ return -EINVAL;
+}
+
+static inline int psy_enable_charger(struct power_supply *psy, bool enable)
+{
+ union power_supply_propval prop_val;
+
+ prop_val.intval = enable;
+ return psy_set_charger_contol_prop(psy,
+ PSY_CHARGER_PROP_ENABLE_CHARGER, &prop_val);
+}
+
+static inline int psy_is_charger_enabled(struct power_supply *psy)
+{
+ union power_supply_propval prop_val;
+ int ret;
+
+ ret = psy_get_charger_contol_prop(psy,
+ PSY_CHARGER_PROP_ENABLE_CHARGER, &prop_val);
+ if (ret)
+ return ret;
+
+ return prop_val.intval;
+}
+
+static inline int psy_set_inlimit(struct power_supply *psy, int inlimit)
+{
+ union power_supply_propval prop_val;
+
+ prop_val.intval = inlimit;
+ return power_supply_set_property(psy,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+ &prop_val);
+}
+
+static int enable_charger(struct charger_controller *charger, bool enable)
+{
+ if (charger->regulator_control) {
+ if (enable)
+ return regulator_enable(charger->regulator_control);
+ else
+ return regulator_disable(charger->regulator_control);
+ }
+
+ return psy_enable_charger(charger->psy_control, enable);
+}
+
+static int is_charger_enabled(struct charger_controller *charger)
+{
+ if (charger->regulator_control)
+ return regulator_is_enabled(charger->regulator_control);
+
+ return psy_is_charger_enabled(charger->psy_control);
+}
+
+static int set_input_current(struct charger_cable *cable)
+{
+ if (cable->charger->regulator_control)
+ return regulator_set_current_limit(
+ cable->charger->regulator_control,
+ cable->min_uA, cable->max_uA);
+
+ return psy_set_inlimit(cable->charger->psy_control,
+ cable->max_uA / 1000);
+}
+
/**
* is_batt_present - See if the battery presents in place.
* @cm: the Charger Manager representing the battery.
@@ -328,6 +420,140 @@ static bool is_polling_required(struct charger_manager
*cm)
return false;
}
+static int get_temp_zone_index(struct psy_charging_obj *cobj, int temp)
+{
+ int i, tzone_count;
+
+ tzone_count = cobj->temp_mon_count > PSY_MAX_TEMP_ZONE ?
+ PSY_MAX_TEMP_ZONE : cobj->temp_mon_count;
+
+ for (i = 0; i < tzone_count; i++) {
+ if (temp <= cobj-