OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [power/] [apm_power.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
3
 * Copyright © 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru>
4
 *
5
 * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru>
6
 *
7
 * Use consistent with the GNU GPL is permitted,
8
 * provided that this copyright notice is
9
 * preserved in its entirety in all copies and derived works.
10
 */
11
 
12
#include <linux/module.h>
13
#include <linux/power_supply.h>
14
#include <linux/apm-emulation.h>
15
 
16
#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
17
                         POWER_SUPPLY_PROP_##prop, val)
18
 
19
#define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \
20
                                                         prop, val)
21
 
22
#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
23
 
24
static struct power_supply *main_battery;
25
 
26
static void find_main_battery(void)
27
{
28
        struct device *dev;
29
        struct power_supply *bat = NULL;
30
        struct power_supply *max_charge_bat = NULL;
31
        struct power_supply *max_energy_bat = NULL;
32
        union power_supply_propval full;
33
        int max_charge = 0;
34
        int max_energy = 0;
35
 
36
        main_battery = NULL;
37
 
38
        list_for_each_entry(dev, &power_supply_class->devices, node) {
39
                bat = dev_get_drvdata(dev);
40
 
41
                if (bat->use_for_apm) {
42
                        /* nice, we explicitly asked to report this battery. */
43
                        main_battery = bat;
44
                        return;
45
                }
46
 
47
                if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) ||
48
                                !PSY_PROP(bat, CHARGE_FULL, &full)) {
49
                        if (full.intval > max_charge) {
50
                                max_charge_bat = bat;
51
                                max_charge = full.intval;
52
                        }
53
                } else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) ||
54
                                !PSY_PROP(bat, ENERGY_FULL, &full)) {
55
                        if (full.intval > max_energy) {
56
                                max_energy_bat = bat;
57
                                max_energy = full.intval;
58
                        }
59
                }
60
        }
61
 
62
        if ((max_energy_bat && max_charge_bat) &&
63
                        (max_energy_bat != max_charge_bat)) {
64
                /* try guess battery with more capacity */
65
                if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) {
66
                        if (max_energy > max_charge * full.intval)
67
                                main_battery = max_energy_bat;
68
                        else
69
                                main_battery = max_charge_bat;
70
                } else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN,
71
                                                                  &full)) {
72
                        if (max_charge > max_energy / full.intval)
73
                                main_battery = max_charge_bat;
74
                        else
75
                                main_battery = max_energy_bat;
76
                } else {
77
                        /* give up, choice any */
78
                        main_battery = max_energy_bat;
79
                }
80
        } else if (max_charge_bat) {
81
                main_battery = max_charge_bat;
82
        } else if (max_energy_bat) {
83
                main_battery = max_energy_bat;
84
        } else {
85
                /* give up, try the last if any */
86
                main_battery = bat;
87
        }
88
}
89
 
90
static int calculate_time(int status, int using_charge)
91
{
92
        union power_supply_propval full;
93
        union power_supply_propval empty;
94
        union power_supply_propval cur;
95
        union power_supply_propval I;
96
        enum power_supply_property full_prop;
97
        enum power_supply_property full_design_prop;
98
        enum power_supply_property empty_prop;
99
        enum power_supply_property empty_design_prop;
100
        enum power_supply_property cur_avg_prop;
101
        enum power_supply_property cur_now_prop;
102
 
103
        if (MPSY_PROP(CURRENT_AVG, &I)) {
104
                /* if battery can't report average value, use momentary */
105
                if (MPSY_PROP(CURRENT_NOW, &I))
106
                        return -1;
107
        }
108
 
109
        if (using_charge) {
110
                full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
111
                full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
112
                empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
113
                empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
114
                cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
115
                cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
116
        } else {
117
                full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
118
                full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
119
                empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
120
                empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
121
                cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
122
                cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
123
        }
124
 
125
        if (_MPSY_PROP(full_prop, &full)) {
126
                /* if battery can't report this property, use design value */
127
                if (_MPSY_PROP(full_design_prop, &full))
128
                        return -1;
129
        }
130
 
131
        if (_MPSY_PROP(empty_prop, &empty)) {
132
                /* if battery can't report this property, use design value */
133
                if (_MPSY_PROP(empty_design_prop, &empty))
134
                        empty.intval = 0;
135
        }
136
 
137
        if (_MPSY_PROP(cur_avg_prop, &cur)) {
138
                /* if battery can't report average value, use momentary */
139
                if (_MPSY_PROP(cur_now_prop, &cur))
140
                        return -1;
141
        }
142
 
143
        if (status == POWER_SUPPLY_STATUS_CHARGING)
144
                return ((cur.intval - full.intval) * 60L) / I.intval;
145
        else
146
                return -((cur.intval - empty.intval) * 60L) / I.intval;
147
}
148
 
149
static int calculate_capacity(int using_charge)
150
{
151
        enum power_supply_property full_prop, empty_prop;
152
        enum power_supply_property full_design_prop, empty_design_prop;
153
        enum power_supply_property now_prop, avg_prop;
154
        union power_supply_propval empty, full, cur;
155
        int ret;
156
 
157
        if (using_charge) {
158
                full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
159
                empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
160
                full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
161
                empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
162
                now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
163
                avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
164
        } else {
165
                full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
166
                empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
167
                full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
168
                empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
169
                now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
170
                avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
171
        }
172
 
173
        if (_MPSY_PROP(full_prop, &full)) {
174
                /* if battery can't report this property, use design value */
175
                if (_MPSY_PROP(full_design_prop, &full))
176
                        return -1;
177
        }
178
 
179
        if (_MPSY_PROP(avg_prop, &cur)) {
180
                /* if battery can't report average value, use momentary */
181
                if (_MPSY_PROP(now_prop, &cur))
182
                        return -1;
183
        }
184
 
185
        if (_MPSY_PROP(empty_prop, &empty)) {
186
                /* if battery can't report this property, use design value */
187
                if (_MPSY_PROP(empty_design_prop, &empty))
188
                        empty.intval = 0;
189
        }
190
 
191
        if (full.intval - empty.intval)
192
                ret =  ((cur.intval - empty.intval) * 100L) /
193
                       (full.intval - empty.intval);
194
        else
195
                return -1;
196
 
197
        if (ret > 100)
198
                return 100;
199
        else if (ret < 0)
200
                return 0;
201
 
202
        return ret;
203
}
204
 
205
static void apm_battery_apm_get_power_status(struct apm_power_info *info)
206
{
207
        union power_supply_propval status;
208
        union power_supply_propval capacity, time_to_full, time_to_empty;
209
 
210
        down(&power_supply_class->sem);
211
        find_main_battery();
212
        if (!main_battery) {
213
                up(&power_supply_class->sem);
214
                return;
215
        }
216
 
217
        /* status */
218
 
219
        if (MPSY_PROP(STATUS, &status))
220
                status.intval = POWER_SUPPLY_STATUS_UNKNOWN;
221
 
222
        /* ac line status */
223
 
224
        if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) ||
225
            (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
226
            (status.intval == POWER_SUPPLY_STATUS_FULL))
227
                info->ac_line_status = APM_AC_ONLINE;
228
        else
229
                info->ac_line_status = APM_AC_OFFLINE;
230
 
231
        /* battery life (i.e. capacity, in percents) */
232
 
233
        if (MPSY_PROP(CAPACITY, &capacity) == 0) {
234
                info->battery_life = capacity.intval;
235
        } else {
236
                /* try calculate using energy */
237
                info->battery_life = calculate_capacity(0);
238
                /* if failed try calculate using charge instead */
239
                if (info->battery_life == -1)
240
                        info->battery_life = calculate_capacity(1);
241
        }
242
 
243
        /* charging status */
244
 
245
        if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
246
                info->battery_status = APM_BATTERY_STATUS_CHARGING;
247
        } else {
248
                if (info->battery_life > 50)
249
                        info->battery_status = APM_BATTERY_STATUS_HIGH;
250
                else if (info->battery_life > 5)
251
                        info->battery_status = APM_BATTERY_STATUS_LOW;
252
                else
253
                        info->battery_status = APM_BATTERY_STATUS_CRITICAL;
254
        }
255
        info->battery_flag = info->battery_status;
256
 
257
        /* time */
258
 
259
        info->units = APM_UNITS_MINS;
260
 
261
        if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
262
                if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
263
                                !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) {
264
                        info->time = time_to_full.intval / 60;
265
                } else {
266
                        info->time = calculate_time(status.intval, 0);
267
                        if (info->time == -1)
268
                                info->time = calculate_time(status.intval, 1);
269
                }
270
        } else {
271
                if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
272
                              !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) {
273
                        info->time = time_to_empty.intval / 60;
274
                } else {
275
                        info->time = calculate_time(status.intval, 0);
276
                        if (info->time == -1)
277
                                info->time = calculate_time(status.intval, 1);
278
                }
279
        }
280
 
281
        up(&power_supply_class->sem);
282
}
283
 
284
static int __init apm_battery_init(void)
285
{
286
        printk(KERN_INFO "APM Battery Driver\n");
287
 
288
        apm_get_power_status = apm_battery_apm_get_power_status;
289
        return 0;
290
}
291
 
292
static void __exit apm_battery_exit(void)
293
{
294
        apm_get_power_status = NULL;
295
}
296
 
297
module_init(apm_battery_init);
298
module_exit(apm_battery_exit);
299
 
300
MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>");
301
MODULE_DESCRIPTION("APM emulation driver for battery monitoring class");
302
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.