summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/power/power_supply_core.c96
-rw-r--r--include/linux/power_supply.h1
2 files changed, 97 insertions, 0 deletions
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 2436f1350013..f984da1066ec 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -216,6 +216,86 @@ static void psy_unregister_thermal(struct power_supply *psy)
return;
thermal_zone_device_unregister(psy->tzd);
}
+
+/* thermal cooling device callbacks */
+static int ps_get_max_charge_cntl_limit(struct thermal_cooling_device *tcd,
+ unsigned long *state)
+{
+ struct power_supply *psy;
+ union power_supply_propval val;
+ int ret;
+
+ psy = tcd->devdata;
+ ret = psy->get_property(psy,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, &val);
+ if (!ret)
+ *state = val.intval;
+
+ return ret;
+}
+
+static int ps_get_cur_chrage_cntl_limit(struct thermal_cooling_device *tcd,
+ unsigned long *state)
+{
+ struct power_supply *psy;
+ union power_supply_propval val;
+ int ret;
+
+ psy = tcd->devdata;
+ ret = psy->get_property(psy,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
+ if (!ret)
+ *state = val.intval;
+
+ return ret;
+}
+
+static int ps_set_cur_charge_cntl_limit(struct thermal_cooling_device *tcd,
+ unsigned long state)
+{
+ struct power_supply *psy;
+ union power_supply_propval val;
+ int ret;
+
+ psy = tcd->devdata;
+ val.intval = state;
+ ret = psy->set_property(psy,
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, &val);
+
+ return ret;
+}
+
+static struct thermal_cooling_device_ops psy_tcd_ops = {
+ .get_max_state = ps_get_max_charge_cntl_limit,
+ .get_cur_state = ps_get_cur_chrage_cntl_limit,
+ .set_cur_state = ps_set_cur_charge_cntl_limit,
+};
+
+static int psy_register_cooler(struct power_supply *psy)
+{
+ int i;
+
+ /* Register for cooling device if psy can control charging */
+ for (i = 0; i < psy->num_properties; i++) {
+ if (psy->properties[i] ==
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT) {
+ psy->tcd = thermal_cooling_device_register(
+ (char *)psy->name,
+ psy, &psy_tcd_ops);
+ if (IS_ERR(psy->tcd))
+ return PTR_ERR(psy->tcd);
+ break;
+ }
+ }
+ return 0;
+}
+
+static void psy_unregister_cooler(struct power_supply *psy)
+{
+ if (IS_ERR_OR_NULL(psy->tcd))
+ return;
+ thermal_cooling_device_unregister(psy->tcd);
+}
#else
static int psy_register_thermal(struct power_supply *psy)
{
@@ -225,6 +305,15 @@ static int psy_register_thermal(struct power_supply *psy)
static void psy_unregister_thermal(struct power_supply *psy)
{
}
+
+static int psy_register_cooler(struct power_supply *psy)
+{
+ return 0;
+}
+
+static void psy_unregister_cooler(struct power_supply *psy)
+{
+}
#endif
int power_supply_register(struct device *parent, struct power_supply *psy)
@@ -259,6 +348,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
if (rc)
goto register_thermal_failed;
+ rc = psy_register_cooler(psy);
+ if (rc)
+ goto register_cooler_failed;
+
rc = power_supply_create_triggers(psy);
if (rc)
goto create_triggers_failed;
@@ -268,6 +361,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
goto success;
create_triggers_failed:
+ psy_unregister_cooler(psy);
+register_cooler_failed:
psy_unregister_thermal(psy);
register_thermal_failed:
device_del(dev);
@@ -284,6 +379,7 @@ void power_supply_unregister(struct power_supply *psy)
cancel_work_sync(&psy->changed_work);
sysfs_remove_link(&psy->dev->kobj, "powers");
power_supply_remove_triggers(psy);
+ psy_unregister_cooler(psy);
psy_unregister_thermal(psy);
device_unregister(psy->dev);
}
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 445b4b249af5..1f0ab90aff00 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -188,6 +188,7 @@ struct power_supply {
struct work_struct changed_work;
#ifdef CONFIG_THERMAL
struct thermal_zone_device *tzd;
+ struct thermal_cooling_device *tcd;
#endif
#ifdef CONFIG_LEDS_TRIGGERS