diff options
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/apm_power.c | 116 | ||||
-rw-r--r-- | drivers/power/power_supply_core.c | 74 |
2 files changed, 107 insertions, 83 deletions
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c index bbf3ee10da04..7e29b90a4f63 100644 --- a/drivers/power/apm_power.c +++ b/drivers/power/apm_power.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/power_supply.h> | 13 | #include <linux/power_supply.h> |
14 | #include <linux/apm-emulation.h> | 14 | #include <linux/apm-emulation.h> |
15 | 15 | ||
16 | static DEFINE_MUTEX(apm_mutex); | ||
16 | #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ | 17 | #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ |
17 | POWER_SUPPLY_PROP_##prop, val) | 18 | POWER_SUPPLY_PROP_##prop, val) |
18 | 19 | ||
@@ -23,67 +24,86 @@ | |||
23 | 24 | ||
24 | static struct power_supply *main_battery; | 25 | static struct power_supply *main_battery; |
25 | 26 | ||
26 | static void find_main_battery(void) | 27 | struct find_bat_param { |
27 | { | 28 | struct power_supply *main; |
28 | struct device *dev; | 29 | struct power_supply *bat; |
29 | struct power_supply *bat = NULL; | 30 | struct power_supply *max_charge_bat; |
30 | struct power_supply *max_charge_bat = NULL; | 31 | struct power_supply *max_energy_bat; |
31 | struct power_supply *max_energy_bat = NULL; | ||
32 | union power_supply_propval full; | 32 | union power_supply_propval full; |
33 | int max_charge = 0; | 33 | int max_charge; |
34 | int max_energy = 0; | 34 | int max_energy; |
35 | }; | ||
35 | 36 | ||
36 | main_battery = NULL; | 37 | static int __find_main_battery(struct device *dev, void *data) |
38 | { | ||
39 | struct find_bat_param *bp = (struct find_bat_param *)data; | ||
37 | 40 | ||
38 | list_for_each_entry(dev, &power_supply_class->devices, node) { | 41 | bp->bat = dev_get_drvdata(dev); |
39 | bat = dev_get_drvdata(dev); | ||
40 | 42 | ||
41 | if (bat->use_for_apm) { | 43 | if (bp->bat->use_for_apm) { |
42 | /* nice, we explicitly asked to report this battery. */ | 44 | /* nice, we explicitly asked to report this battery. */ |
43 | main_battery = bat; | 45 | bp->main = bp->bat; |
44 | return; | 46 | return 1; |
45 | } | 47 | } |
46 | 48 | ||
47 | if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) || | 49 | if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) || |
48 | !PSY_PROP(bat, CHARGE_FULL, &full)) { | 50 | !PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) { |
49 | if (full.intval > max_charge) { | 51 | if (bp->full.intval > bp->max_charge) { |
50 | max_charge_bat = bat; | 52 | bp->max_charge_bat = bp->bat; |
51 | max_charge = full.intval; | 53 | bp->max_charge = bp->full.intval; |
52 | } | 54 | } |
53 | } else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) || | 55 | } else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) || |
54 | !PSY_PROP(bat, ENERGY_FULL, &full)) { | 56 | !PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) { |
55 | if (full.intval > max_energy) { | 57 | if (bp->full.intval > bp->max_energy) { |
56 | max_energy_bat = bat; | 58 | bp->max_energy_bat = bp->bat; |
57 | max_energy = full.intval; | 59 | bp->max_energy = bp->full.intval; |
58 | } | ||
59 | } | 60 | } |
60 | } | 61 | } |
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static void find_main_battery(void) | ||
66 | { | ||
67 | struct find_bat_param bp; | ||
68 | int error; | ||
69 | |||
70 | memset(&bp, 0, sizeof(struct find_bat_param)); | ||
71 | main_battery = NULL; | ||
72 | bp.main = main_battery; | ||
73 | |||
74 | error = class_for_each_device(power_supply_class, &bp, | ||
75 | __find_main_battery); | ||
76 | if (error) { | ||
77 | main_battery = bp.main; | ||
78 | return; | ||
79 | } | ||
61 | 80 | ||
62 | if ((max_energy_bat && max_charge_bat) && | 81 | if ((bp.max_energy_bat && bp.max_charge_bat) && |
63 | (max_energy_bat != max_charge_bat)) { | 82 | (bp.max_energy_bat != bp.max_charge_bat)) { |
64 | /* try guess battery with more capacity */ | 83 | /* try guess battery with more capacity */ |
65 | if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) { | 84 | if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN, |
66 | if (max_energy > max_charge * full.intval) | 85 | &bp.full)) { |
67 | main_battery = max_energy_bat; | 86 | if (bp.max_energy > bp.max_charge * bp.full.intval) |
87 | main_battery = bp.max_energy_bat; | ||
68 | else | 88 | else |
69 | main_battery = max_charge_bat; | 89 | main_battery = bp.max_charge_bat; |
70 | } else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN, | 90 | } else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN, |
71 | &full)) { | 91 | &bp.full)) { |
72 | if (max_charge > max_energy / full.intval) | 92 | if (bp.max_charge > bp.max_energy / bp.full.intval) |
73 | main_battery = max_charge_bat; | 93 | main_battery = bp.max_charge_bat; |
74 | else | 94 | else |
75 | main_battery = max_energy_bat; | 95 | main_battery = bp.max_energy_bat; |
76 | } else { | 96 | } else { |
77 | /* give up, choice any */ | 97 | /* give up, choice any */ |
78 | main_battery = max_energy_bat; | 98 | main_battery = bp.max_energy_bat; |
79 | } | 99 | } |
80 | } else if (max_charge_bat) { | 100 | } else if (bp.max_charge_bat) { |
81 | main_battery = max_charge_bat; | 101 | main_battery = bp.max_charge_bat; |
82 | } else if (max_energy_bat) { | 102 | } else if (bp.max_energy_bat) { |
83 | main_battery = max_energy_bat; | 103 | main_battery = bp.max_energy_bat; |
84 | } else { | 104 | } else { |
85 | /* give up, try the last if any */ | 105 | /* give up, try the last if any */ |
86 | main_battery = bat; | 106 | main_battery = bp.bat; |
87 | } | 107 | } |
88 | } | 108 | } |
89 | 109 | ||
@@ -207,10 +227,10 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) | |||
207 | union power_supply_propval status; | 227 | union power_supply_propval status; |
208 | union power_supply_propval capacity, time_to_full, time_to_empty; | 228 | union power_supply_propval capacity, time_to_full, time_to_empty; |
209 | 229 | ||
210 | down(&power_supply_class->sem); | 230 | mutex_lock(&apm_mutex); |
211 | find_main_battery(); | 231 | find_main_battery(); |
212 | if (!main_battery) { | 232 | if (!main_battery) { |
213 | up(&power_supply_class->sem); | 233 | mutex_unlock(&apm_mutex); |
214 | return; | 234 | return; |
215 | } | 235 | } |
216 | 236 | ||
@@ -278,7 +298,7 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) | |||
278 | } | 298 | } |
279 | } | 299 | } |
280 | 300 | ||
281 | up(&power_supply_class->sem); | 301 | mutex_unlock(&apm_mutex); |
282 | } | 302 | } |
283 | 303 | ||
284 | static int __init apm_battery_init(void) | 304 | static int __init apm_battery_init(void) |
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index a63b75cf75e2..03d6a38464ef 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c | |||
@@ -20,28 +20,29 @@ | |||
20 | 20 | ||
21 | struct class *power_supply_class; | 21 | struct class *power_supply_class; |
22 | 22 | ||
23 | static int __power_supply_changed_work(struct device *dev, void *data) | ||
24 | { | ||
25 | struct power_supply *psy = (struct power_supply *)data; | ||
26 | struct power_supply *pst = dev_get_drvdata(dev); | ||
27 | int i; | ||
28 | |||
29 | for (i = 0; i < psy->num_supplicants; i++) | ||
30 | if (!strcmp(psy->supplied_to[i], pst->name)) { | ||
31 | if (pst->external_power_changed) | ||
32 | pst->external_power_changed(pst); | ||
33 | } | ||
34 | return 0; | ||
35 | } | ||
36 | |||
23 | static void power_supply_changed_work(struct work_struct *work) | 37 | static void power_supply_changed_work(struct work_struct *work) |
24 | { | 38 | { |
25 | struct power_supply *psy = container_of(work, struct power_supply, | 39 | struct power_supply *psy = container_of(work, struct power_supply, |
26 | changed_work); | 40 | changed_work); |
27 | int i; | ||
28 | 41 | ||
29 | dev_dbg(psy->dev, "%s\n", __FUNCTION__); | 42 | dev_dbg(psy->dev, "%s\n", __FUNCTION__); |
30 | 43 | ||
31 | for (i = 0; i < psy->num_supplicants; i++) { | 44 | class_for_each_device(power_supply_class, psy, |
32 | struct device *dev; | 45 | __power_supply_changed_work); |
33 | |||
34 | down(&power_supply_class->sem); | ||
35 | list_for_each_entry(dev, &power_supply_class->devices, node) { | ||
36 | struct power_supply *pst = dev_get_drvdata(dev); | ||
37 | |||
38 | if (!strcmp(psy->supplied_to[i], pst->name)) { | ||
39 | if (pst->external_power_changed) | ||
40 | pst->external_power_changed(pst); | ||
41 | } | ||
42 | } | ||
43 | up(&power_supply_class->sem); | ||
44 | } | ||
45 | 46 | ||
46 | power_supply_update_leds(psy); | 47 | power_supply_update_leds(psy); |
47 | 48 | ||
@@ -55,32 +56,35 @@ void power_supply_changed(struct power_supply *psy) | |||
55 | schedule_work(&psy->changed_work); | 56 | schedule_work(&psy->changed_work); |
56 | } | 57 | } |
57 | 58 | ||
58 | int power_supply_am_i_supplied(struct power_supply *psy) | 59 | static int __power_supply_am_i_supplied(struct device *dev, void *data) |
59 | { | 60 | { |
60 | union power_supply_propval ret = {0,}; | 61 | union power_supply_propval ret = {0,}; |
61 | struct device *dev; | 62 | struct power_supply *psy = (struct power_supply *)data; |
62 | 63 | struct power_supply *epsy = dev_get_drvdata(dev); | |
63 | down(&power_supply_class->sem); | 64 | int i; |
64 | list_for_each_entry(dev, &power_supply_class->devices, node) { | 65 | |
65 | struct power_supply *epsy = dev_get_drvdata(dev); | 66 | for (i = 0; i < epsy->num_supplicants; i++) { |
66 | int i; | 67 | if (!strcmp(epsy->supplied_to[i], psy->name)) { |
67 | 68 | if (epsy->get_property(epsy, | |
68 | for (i = 0; i < epsy->num_supplicants; i++) { | 69 | POWER_SUPPLY_PROP_ONLINE, &ret)) |
69 | if (!strcmp(epsy->supplied_to[i], psy->name)) { | 70 | continue; |
70 | if (epsy->get_property(epsy, | 71 | if (ret.intval) |
71 | POWER_SUPPLY_PROP_ONLINE, &ret)) | 72 | return ret.intval; |
72 | continue; | ||
73 | if (ret.intval) | ||
74 | goto out; | ||
75 | } | ||
76 | } | 73 | } |
77 | } | 74 | } |
78 | out: | 75 | return 0; |
79 | up(&power_supply_class->sem); | 76 | } |
77 | |||
78 | int power_supply_am_i_supplied(struct power_supply *psy) | ||
79 | { | ||
80 | int error; | ||
81 | |||
82 | error = class_for_each_device(power_supply_class, psy, | ||
83 | __power_supply_am_i_supplied); | ||
80 | 84 | ||
81 | dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval); | 85 | dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error); |
82 | 86 | ||
83 | return ret.intval; | 87 | return error; |
84 | } | 88 | } |
85 | 89 | ||
86 | int power_supply_register(struct device *parent, struct power_supply *psy) | 90 | int power_supply_register(struct device *parent, struct power_supply *psy) |