Merge branch 'acpi-battery'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 3 Jun 2014 21:11:30 +0000 (23:11 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 3 Jun 2014 21:11:30 +0000 (23:11 +0200)
* acpi-battery:
  ACPI / battery: wakeup the system only when necessary
  power_supply: allow power supply devices registered w/o wakeup source
  ACPI / battery: introduce support for POWER_SUPPLY_PROP_CAPACITY_LEVEL
  ACPI / battery: Accelerate battery resume callback

drivers/acpi/battery.c
drivers/power/power_supply_core.c
include/linux/power_supply.h

index 6e7b2a12860d31ac533c730e97d080daaa6f1385..e48fc98e71c48379694bbbd76119dd1c222660ac 100644 (file)
 /* Battery power unit: 0 means mW, 1 means mA */
 #define ACPI_BATTERY_POWER_UNIT_MA     1
 
+#define ACPI_BATTERY_STATE_DISCHARGING 0x1
+#define ACPI_BATTERY_STATE_CHARGING    0x2
+#define ACPI_BATTERY_STATE_CRITICAL    0x4
+
 #define _COMPONENT             ACPI_BATTERY_COMPONENT
 
 ACPI_MODULE_NAME("battery");
@@ -169,7 +173,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery);
 
 static int acpi_battery_is_charged(struct acpi_battery *battery)
 {
-       /* either charging or discharging */
+       /* charging, discharging or critical low */
        if (battery->state != 0)
                return 0;
 
@@ -204,9 +208,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
                return -ENODEV;
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
-               if (battery->state & 0x01)
+               if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
                        val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
-               else if (battery->state & 0x02)
+               else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
                        val->intval = POWER_SUPPLY_STATUS_CHARGING;
                else if (acpi_battery_is_charged(battery))
                        val->intval = POWER_SUPPLY_STATUS_FULL;
@@ -269,6 +273,17 @@ static int acpi_battery_get_property(struct power_supply *psy,
                else
                        val->intval = 0;
                break;
+       case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+               if (battery->state & ACPI_BATTERY_STATE_CRITICAL)
+                       val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+               else if (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
+                       (battery->capacity_now <= battery->alarm))
+                       val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+               else if (acpi_battery_is_charged(battery))
+                       val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+               else
+                       val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+               break;
        case POWER_SUPPLY_PROP_MODEL_NAME:
                val->strval = battery->model_number;
                break;
@@ -296,6 +311,7 @@ static enum power_supply_property charge_battery_props[] = {
        POWER_SUPPLY_PROP_CHARGE_FULL,
        POWER_SUPPLY_PROP_CHARGE_NOW,
        POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CAPACITY_LEVEL,
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
        POWER_SUPPLY_PROP_SERIAL_NUMBER,
@@ -313,6 +329,7 @@ static enum power_supply_property energy_battery_props[] = {
        POWER_SUPPLY_PROP_ENERGY_FULL,
        POWER_SUPPLY_PROP_ENERGY_NOW,
        POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CAPACITY_LEVEL,
        POWER_SUPPLY_PROP_MODEL_NAME,
        POWER_SUPPLY_PROP_MANUFACTURER,
        POWER_SUPPLY_PROP_SERIAL_NUMBER,
@@ -605,7 +622,8 @@ static int sysfs_add_battery(struct acpi_battery *battery)
        battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
        battery->bat.get_property = acpi_battery_get_property;
 
-       result = power_supply_register(&battery->device->dev, &battery->bat);
+       result = power_supply_register_no_ws(&battery->device->dev, &battery->bat);
+
        if (result)
                return result;
        return device_create_file(battery->bat.dev, &alarm_attr);
@@ -696,7 +714,7 @@ static void acpi_battery_quirks(struct acpi_battery *battery)
        }
 }
 
-static int acpi_battery_update(struct acpi_battery *battery)
+static int acpi_battery_update(struct acpi_battery *battery, bool resume)
 {
        int result, old_present = acpi_battery_present(battery);
        result = acpi_battery_get_status(battery);
@@ -707,6 +725,10 @@ static int acpi_battery_update(struct acpi_battery *battery)
                battery->update_time = 0;
                return 0;
        }
+
+       if (resume)
+               return 0;
+
        if (!battery->update_time ||
            old_present != acpi_battery_present(battery)) {
                result = acpi_battery_get_info(battery);
@@ -720,7 +742,19 @@ static int acpi_battery_update(struct acpi_battery *battery)
                        return result;
        }
        result = acpi_battery_get_state(battery);
+       if (result)
+               return result;
        acpi_battery_quirks(battery);
+
+       /*
+        * Wakeup the system if battery is critical low
+        * or lower than the alarm level
+        */
+       if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
+           (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
+            (battery->capacity_now <= battery->alarm)))
+               pm_wakeup_event(&battery->device->dev, 0);
+
        return result;
 }
 
@@ -915,7 +949,7 @@ static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = {
 static int acpi_battery_read(int fid, struct seq_file *seq)
 {
        struct acpi_battery *battery = seq->private;
-       int result = acpi_battery_update(battery);
+       int result = acpi_battery_update(battery, false);
        return acpi_print_funcs[fid](seq, result);
 }
 
@@ -1030,7 +1064,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
        old = battery->bat.dev;
        if (event == ACPI_BATTERY_NOTIFY_INFO)
                acpi_battery_refresh(battery);
-       acpi_battery_update(battery);
+       acpi_battery_update(battery, false);
        acpi_bus_generate_netlink_event(device->pnp.device_class,
                                        dev_name(&device->dev), event,
                                        acpi_battery_present(battery));
@@ -1045,13 +1079,27 @@ static int battery_notify(struct notifier_block *nb,
 {
        struct acpi_battery *battery = container_of(nb, struct acpi_battery,
                                                    pm_nb);
+       int result;
+
        switch (mode) {
        case PM_POST_HIBERNATION:
        case PM_POST_SUSPEND:
-               if (battery->bat.dev) {
-                       sysfs_remove_battery(battery);
-                       sysfs_add_battery(battery);
-               }
+               if (!acpi_battery_present(battery))
+                       return 0;
+
+               if (!battery->bat.dev) {
+                       result = acpi_battery_get_info(battery);
+                       if (result)
+                               return result;
+
+                       result = sysfs_add_battery(battery);
+                       if (result)
+                               return result;
+               } else
+                       acpi_battery_refresh(battery);
+
+               acpi_battery_init_alarm(battery);
+               acpi_battery_get_state(battery);
                break;
        }
 
@@ -1087,7 +1135,7 @@ static int acpi_battery_add(struct acpi_device *device)
        mutex_init(&battery->sysfs_lock);
        if (acpi_has_method(battery->device->handle, "_BIX"))
                set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
-       result = acpi_battery_update(battery);
+       result = acpi_battery_update(battery, false);
        if (result)
                goto fail;
 #ifdef CONFIG_ACPI_PROCFS_POWER
@@ -1107,6 +1155,8 @@ static int acpi_battery_add(struct acpi_device *device)
        battery->pm_nb.notifier_call = battery_notify;
        register_pm_notifier(&battery->pm_nb);
 
+       device_init_wakeup(&device->dev, 1);
+
        return result;
 
 fail:
@@ -1123,6 +1173,7 @@ static int acpi_battery_remove(struct acpi_device *device)
 
        if (!device || !acpi_driver_data(device))
                return -EINVAL;
+       device_init_wakeup(&device->dev, 0);
        battery = acpi_driver_data(device);
        unregister_pm_notifier(&battery->pm_nb);
 #ifdef CONFIG_ACPI_PROCFS_POWER
@@ -1149,7 +1200,7 @@ static int acpi_battery_resume(struct device *dev)
                return -EINVAL;
 
        battery->update_time = 0;
-       acpi_battery_update(battery);
+       acpi_battery_update(battery, true);
        return 0;
 }
 #else
index 26606641fe44d5b250caaa8eccd972701c290737..5a5a24e7d43c25f6d23bbc686cf3fb27697ad2a9 100644 (file)
@@ -537,7 +537,7 @@ static void psy_unregister_cooler(struct power_supply *psy)
 }
 #endif
 
-int power_supply_register(struct device *parent, struct power_supply *psy)
+int __power_supply_register(struct device *parent, struct power_supply *psy, bool ws)
 {
        struct device *dev;
        int rc;
@@ -568,7 +568,7 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
        }
 
        spin_lock_init(&psy->changed_lock);
-       rc = device_init_wakeup(dev, true);
+       rc = device_init_wakeup(dev, ws);
        if (rc)
                goto wakeup_init_failed;
 
@@ -606,8 +606,19 @@ dev_set_name_failed:
 success:
        return rc;
 }
+
+int power_supply_register(struct device *parent, struct power_supply *psy)
+{
+       return __power_supply_register(parent, psy, true);
+}
 EXPORT_SYMBOL_GPL(power_supply_register);
 
+int power_supply_register_no_ws(struct device *parent, struct power_supply *psy)
+{
+       return __power_supply_register(parent, psy, false);
+}
+EXPORT_SYMBOL_GPL(power_supply_register_no_ws);
+
 void power_supply_unregister(struct power_supply *psy)
 {
        cancel_work_sync(&psy->changed_work);
index c9dc4e09854cb87f728ad797d940ac4c8b1b4b14..f2b76aeaf4e45f167127876811121aecdee74300 100644 (file)
@@ -264,6 +264,8 @@ static inline int power_supply_is_system_supplied(void) { return -ENOSYS; }
 
 extern int power_supply_register(struct device *parent,
                                 struct power_supply *psy);
+extern int power_supply_register_no_ws(struct device *parent,
+                                struct power_supply *psy);
 extern void power_supply_unregister(struct power_supply *psy);
 extern int power_supply_powers(struct power_supply *psy, struct device *dev);
 
This page took 0.034131 seconds and 5 git commands to generate.