Commit 7b3d54a8c30d2c524889a05d0c1334813d516b93

Authored by Anton Vorontsov
1 parent 5ebf6e6a96

Power supply class and drivers: remove non obligatory return statements

Per Jeff Garzik request.

Signed-off-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Anton Vorontsov <cbou@mail.ru>

Showing 9 changed files with 0 additions and 39 deletions Inline Diff

drivers/power/apm_power.c
1 /* 1 /*
2 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> 2 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
3 * Copyright © 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru> 3 * Copyright © 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru>
4 * 4 *
5 * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru> 5 * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru>
6 * 6 *
7 * Use consistent with the GNU GPL is permitted, 7 * Use consistent with the GNU GPL is permitted,
8 * provided that this copyright notice is 8 * provided that this copyright notice is
9 * preserved in its entirety in all copies and derived works. 9 * preserved in its entirety in all copies and derived works.
10 */ 10 */
11 11
12 #include <linux/module.h> 12 #include <linux/module.h>
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 #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ 16 #define PSY_PROP(psy, prop, val) psy->get_property(psy, \
17 POWER_SUPPLY_PROP_##prop, val) 17 POWER_SUPPLY_PROP_##prop, val)
18 18
19 #define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \ 19 #define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \
20 prop, val) 20 prop, val)
21 21
22 #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val) 22 #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
23 23
24 static struct power_supply *main_battery; 24 static struct power_supply *main_battery;
25 25
26 static void find_main_battery(void) 26 static void find_main_battery(void)
27 { 27 {
28 struct device *dev; 28 struct device *dev;
29 struct power_supply *bat, *batm; 29 struct power_supply *bat, *batm;
30 union power_supply_propval full; 30 union power_supply_propval full;
31 int max_charge = 0; 31 int max_charge = 0;
32 32
33 main_battery = NULL; 33 main_battery = NULL;
34 batm = NULL; 34 batm = NULL;
35 list_for_each_entry(dev, &power_supply_class->devices, node) { 35 list_for_each_entry(dev, &power_supply_class->devices, node) {
36 bat = dev_get_drvdata(dev); 36 bat = dev_get_drvdata(dev);
37 /* If none of battery devices cantains 'use_for_apm' flag, 37 /* If none of battery devices cantains 'use_for_apm' flag,
38 choice one with maximum design charge */ 38 choice one with maximum design charge */
39 if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) { 39 if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) {
40 if (full.intval > max_charge) { 40 if (full.intval > max_charge) {
41 batm = bat; 41 batm = bat;
42 max_charge = full.intval; 42 max_charge = full.intval;
43 } 43 }
44 } 44 }
45 45
46 if (bat->use_for_apm) 46 if (bat->use_for_apm)
47 main_battery = bat; 47 main_battery = bat;
48 } 48 }
49 if (!main_battery) 49 if (!main_battery)
50 main_battery = batm; 50 main_battery = batm;
51
52 return;
53 } 51 }
54 52
55 static int calculate_time(int status) 53 static int calculate_time(int status)
56 { 54 {
57 union power_supply_propval charge_full, charge_empty; 55 union power_supply_propval charge_full, charge_empty;
58 union power_supply_propval charge, I; 56 union power_supply_propval charge, I;
59 57
60 if (MPSY_PROP(CHARGE_FULL, &charge_full)) { 58 if (MPSY_PROP(CHARGE_FULL, &charge_full)) {
61 /* if battery can't report this property, use design value */ 59 /* if battery can't report this property, use design value */
62 if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full)) 60 if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full))
63 return -1; 61 return -1;
64 } 62 }
65 63
66 if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) { 64 if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) {
67 /* if battery can't report this property, use design value */ 65 /* if battery can't report this property, use design value */
68 if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty)) 66 if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty))
69 charge_empty.intval = 0; 67 charge_empty.intval = 0;
70 } 68 }
71 69
72 if (MPSY_PROP(CHARGE_AVG, &charge)) { 70 if (MPSY_PROP(CHARGE_AVG, &charge)) {
73 /* if battery can't report average value, use momentary */ 71 /* if battery can't report average value, use momentary */
74 if (MPSY_PROP(CHARGE_NOW, &charge)) 72 if (MPSY_PROP(CHARGE_NOW, &charge))
75 return -1; 73 return -1;
76 } 74 }
77 75
78 if (MPSY_PROP(CURRENT_AVG, &I)) { 76 if (MPSY_PROP(CURRENT_AVG, &I)) {
79 /* if battery can't report average value, use momentary */ 77 /* if battery can't report average value, use momentary */
80 if (MPSY_PROP(CURRENT_NOW, &I)) 78 if (MPSY_PROP(CURRENT_NOW, &I))
81 return -1; 79 return -1;
82 } 80 }
83 81
84 if (status == POWER_SUPPLY_STATUS_CHARGING) 82 if (status == POWER_SUPPLY_STATUS_CHARGING)
85 return ((charge.intval - charge_full.intval) * 60L) / 83 return ((charge.intval - charge_full.intval) * 60L) /
86 I.intval; 84 I.intval;
87 else 85 else
88 return -((charge.intval - charge_empty.intval) * 60L) / 86 return -((charge.intval - charge_empty.intval) * 60L) /
89 I.intval; 87 I.intval;
90 } 88 }
91 89
92 static int calculate_capacity(int using_charge) 90 static int calculate_capacity(int using_charge)
93 { 91 {
94 enum power_supply_property full_prop, empty_prop; 92 enum power_supply_property full_prop, empty_prop;
95 enum power_supply_property full_design_prop, empty_design_prop; 93 enum power_supply_property full_design_prop, empty_design_prop;
96 enum power_supply_property now_prop, avg_prop; 94 enum power_supply_property now_prop, avg_prop;
97 union power_supply_propval empty, full, cur; 95 union power_supply_propval empty, full, cur;
98 int ret; 96 int ret;
99 97
100 if (using_charge) { 98 if (using_charge) {
101 full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; 99 full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
102 empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; 100 empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
103 full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; 101 full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
104 empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN; 102 empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
105 now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; 103 now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
106 avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; 104 avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
107 } else { 105 } else {
108 full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; 106 full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
109 empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; 107 empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
110 full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; 108 full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
111 empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN; 109 empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
112 now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; 110 now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
113 avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; 111 avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
114 } 112 }
115 113
116 if (_MPSY_PROP(full_prop, &full)) { 114 if (_MPSY_PROP(full_prop, &full)) {
117 /* if battery can't report this property, use design value */ 115 /* if battery can't report this property, use design value */
118 if (_MPSY_PROP(full_design_prop, &full)) 116 if (_MPSY_PROP(full_design_prop, &full))
119 return -1; 117 return -1;
120 } 118 }
121 119
122 if (_MPSY_PROP(avg_prop, &cur)) { 120 if (_MPSY_PROP(avg_prop, &cur)) {
123 /* if battery can't report average value, use momentary */ 121 /* if battery can't report average value, use momentary */
124 if (_MPSY_PROP(now_prop, &cur)) 122 if (_MPSY_PROP(now_prop, &cur))
125 return -1; 123 return -1;
126 } 124 }
127 125
128 if (_MPSY_PROP(empty_prop, &empty)) { 126 if (_MPSY_PROP(empty_prop, &empty)) {
129 /* if battery can't report this property, use design value */ 127 /* if battery can't report this property, use design value */
130 if (_MPSY_PROP(empty_design_prop, &empty)) 128 if (_MPSY_PROP(empty_design_prop, &empty))
131 empty.intval = 0; 129 empty.intval = 0;
132 } 130 }
133 131
134 if (full.intval - empty.intval) 132 if (full.intval - empty.intval)
135 ret = ((cur.intval - empty.intval) * 100L) / 133 ret = ((cur.intval - empty.intval) * 100L) /
136 (full.intval - empty.intval); 134 (full.intval - empty.intval);
137 else 135 else
138 return -1; 136 return -1;
139 137
140 if (ret > 100) 138 if (ret > 100)
141 return 100; 139 return 100;
142 else if (ret < 0) 140 else if (ret < 0)
143 return 0; 141 return 0;
144 142
145 return ret; 143 return ret;
146 } 144 }
147 145
148 static void apm_battery_apm_get_power_status(struct apm_power_info *info) 146 static void apm_battery_apm_get_power_status(struct apm_power_info *info)
149 { 147 {
150 union power_supply_propval status; 148 union power_supply_propval status;
151 union power_supply_propval capacity, time_to_full, time_to_empty; 149 union power_supply_propval capacity, time_to_full, time_to_empty;
152 150
153 down(&power_supply_class->sem); 151 down(&power_supply_class->sem);
154 find_main_battery(); 152 find_main_battery();
155 if (!main_battery) { 153 if (!main_battery) {
156 up(&power_supply_class->sem); 154 up(&power_supply_class->sem);
157 return; 155 return;
158 } 156 }
159 157
160 /* status */ 158 /* status */
161 159
162 if (MPSY_PROP(STATUS, &status)) 160 if (MPSY_PROP(STATUS, &status))
163 status.intval = POWER_SUPPLY_STATUS_UNKNOWN; 161 status.intval = POWER_SUPPLY_STATUS_UNKNOWN;
164 162
165 /* ac line status */ 163 /* ac line status */
166 164
167 if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) || 165 if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) ||
168 (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) || 166 (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) ||
169 (status.intval == POWER_SUPPLY_STATUS_FULL)) 167 (status.intval == POWER_SUPPLY_STATUS_FULL))
170 info->ac_line_status = APM_AC_ONLINE; 168 info->ac_line_status = APM_AC_ONLINE;
171 else 169 else
172 info->ac_line_status = APM_AC_OFFLINE; 170 info->ac_line_status = APM_AC_OFFLINE;
173 171
174 /* battery life (i.e. capacity, in percents) */ 172 /* battery life (i.e. capacity, in percents) */
175 173
176 if (MPSY_PROP(CAPACITY, &capacity) == 0) { 174 if (MPSY_PROP(CAPACITY, &capacity) == 0) {
177 info->battery_life = capacity.intval; 175 info->battery_life = capacity.intval;
178 } else { 176 } else {
179 /* try calculate using energy */ 177 /* try calculate using energy */
180 info->battery_life = calculate_capacity(0); 178 info->battery_life = calculate_capacity(0);
181 /* if failed try calculate using charge instead */ 179 /* if failed try calculate using charge instead */
182 if (info->battery_life == -1) 180 if (info->battery_life == -1)
183 info->battery_life = calculate_capacity(1); 181 info->battery_life = calculate_capacity(1);
184 } 182 }
185 183
186 /* charging status */ 184 /* charging status */
187 185
188 if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { 186 if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
189 info->battery_status = APM_BATTERY_STATUS_CHARGING; 187 info->battery_status = APM_BATTERY_STATUS_CHARGING;
190 } else { 188 } else {
191 if (info->battery_life > 50) 189 if (info->battery_life > 50)
192 info->battery_status = APM_BATTERY_STATUS_HIGH; 190 info->battery_status = APM_BATTERY_STATUS_HIGH;
193 else if (info->battery_life > 5) 191 else if (info->battery_life > 5)
194 info->battery_status = APM_BATTERY_STATUS_LOW; 192 info->battery_status = APM_BATTERY_STATUS_LOW;
195 else 193 else
196 info->battery_status = APM_BATTERY_STATUS_CRITICAL; 194 info->battery_status = APM_BATTERY_STATUS_CRITICAL;
197 } 195 }
198 info->battery_flag = info->battery_status; 196 info->battery_flag = info->battery_status;
199 197
200 /* time */ 198 /* time */
201 199
202 info->units = APM_UNITS_MINS; 200 info->units = APM_UNITS_MINS;
203 201
204 if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { 202 if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
205 if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) { 203 if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) {
206 if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) 204 if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
207 info->time = calculate_time(status.intval); 205 info->time = calculate_time(status.intval);
208 else 206 else
209 info->time = time_to_full.intval / 60; 207 info->time = time_to_full.intval / 60;
210 } 208 }
211 } else { 209 } else {
212 if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) { 210 if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) {
213 if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) 211 if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
214 info->time = calculate_time(status.intval); 212 info->time = calculate_time(status.intval);
215 else 213 else
216 info->time = time_to_empty.intval / 60; 214 info->time = time_to_empty.intval / 60;
217 } 215 }
218 } 216 }
219 217
220 up(&power_supply_class->sem); 218 up(&power_supply_class->sem);
221 return;
222 } 219 }
223 220
224 static int __init apm_battery_init(void) 221 static int __init apm_battery_init(void)
225 { 222 {
226 printk(KERN_INFO "APM Battery Driver\n"); 223 printk(KERN_INFO "APM Battery Driver\n");
227 224
228 apm_get_power_status = apm_battery_apm_get_power_status; 225 apm_get_power_status = apm_battery_apm_get_power_status;
229 return 0; 226 return 0;
230 } 227 }
231 228
232 static void __exit apm_battery_exit(void) 229 static void __exit apm_battery_exit(void)
233 { 230 {
234 apm_get_power_status = NULL; 231 apm_get_power_status = NULL;
235 return;
236 } 232 }
237 233
238 module_init(apm_battery_init); 234 module_init(apm_battery_init);
239 module_exit(apm_battery_exit); 235 module_exit(apm_battery_exit);
240 236
241 MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>"); 237 MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>");
242 MODULE_DESCRIPTION("APM emulation driver for battery monitoring class"); 238 MODULE_DESCRIPTION("APM emulation driver for battery monitoring class");
243 MODULE_LICENSE("GPL"); 239 MODULE_LICENSE("GPL");
244 240
drivers/power/ds2760_battery.c
1 /* 1 /*
2 * Driver for batteries with DS2760 chips inside. 2 * Driver for batteries with DS2760 chips inside.
3 * 3 *
4 * Copyright © 2007 Anton Vorontsov 4 * Copyright © 2007 Anton Vorontsov
5 * 2004-2007 Matt Reimer 5 * 2004-2007 Matt Reimer
6 * 2004 Szabolcs Gyurko 6 * 2004 Szabolcs Gyurko
7 * 7 *
8 * Use consistent with the GNU GPL is permitted, 8 * Use consistent with the GNU GPL is permitted,
9 * provided that this copyright notice is 9 * provided that this copyright notice is
10 * preserved in its entirety in all copies and derived works. 10 * preserved in its entirety in all copies and derived works.
11 * 11 *
12 * Author: Anton Vorontsov <cbou@mail.ru> 12 * Author: Anton Vorontsov <cbou@mail.ru>
13 * February 2007 13 * February 2007
14 * 14 *
15 * Matt Reimer <mreimer@vpop.net> 15 * Matt Reimer <mreimer@vpop.net>
16 * April 2004, 2005, 2007 16 * April 2004, 2005, 2007
17 * 17 *
18 * Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> 18 * Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
19 * September 2004 19 * September 2004
20 */ 20 */
21 21
22 #include <linux/module.h> 22 #include <linux/module.h>
23 #include <linux/param.h> 23 #include <linux/param.h>
24 #include <linux/jiffies.h> 24 #include <linux/jiffies.h>
25 #include <linux/workqueue.h> 25 #include <linux/workqueue.h>
26 #include <linux/pm.h> 26 #include <linux/pm.h>
27 #include <linux/platform_device.h> 27 #include <linux/platform_device.h>
28 #include <linux/power_supply.h> 28 #include <linux/power_supply.h>
29 29
30 #include "../w1/w1.h" 30 #include "../w1/w1.h"
31 #include "../w1/slaves/w1_ds2760.h" 31 #include "../w1/slaves/w1_ds2760.h"
32 32
33 struct ds2760_device_info { 33 struct ds2760_device_info {
34 struct device *dev; 34 struct device *dev;
35 35
36 /* DS2760 data, valid after calling ds2760_battery_read_status() */ 36 /* DS2760 data, valid after calling ds2760_battery_read_status() */
37 unsigned long update_time; /* jiffies when data read */ 37 unsigned long update_time; /* jiffies when data read */
38 char raw[DS2760_DATA_SIZE]; /* raw DS2760 data */ 38 char raw[DS2760_DATA_SIZE]; /* raw DS2760 data */
39 int voltage_raw; /* units of 4.88 mV */ 39 int voltage_raw; /* units of 4.88 mV */
40 int voltage_uV; /* units of µV */ 40 int voltage_uV; /* units of µV */
41 int current_raw; /* units of 0.625 mA */ 41 int current_raw; /* units of 0.625 mA */
42 int current_uA; /* units of µA */ 42 int current_uA; /* units of µA */
43 int accum_current_raw; /* units of 0.25 mAh */ 43 int accum_current_raw; /* units of 0.25 mAh */
44 int accum_current_uAh; /* units of µAh */ 44 int accum_current_uAh; /* units of µAh */
45 int temp_raw; /* units of 0.125 °C */ 45 int temp_raw; /* units of 0.125 °C */
46 int temp_C; /* units of 0.1 °C */ 46 int temp_C; /* units of 0.1 °C */
47 int rated_capacity; /* units of µAh */ 47 int rated_capacity; /* units of µAh */
48 int rem_capacity; /* percentage */ 48 int rem_capacity; /* percentage */
49 int full_active_uAh; /* units of µAh */ 49 int full_active_uAh; /* units of µAh */
50 int empty_uAh; /* units of µAh */ 50 int empty_uAh; /* units of µAh */
51 int life_sec; /* units of seconds */ 51 int life_sec; /* units of seconds */
52 int charge_status; /* POWER_SUPPLY_STATUS_* */ 52 int charge_status; /* POWER_SUPPLY_STATUS_* */
53 53
54 int full_counter; 54 int full_counter;
55 struct power_supply bat; 55 struct power_supply bat;
56 struct device *w1_dev; 56 struct device *w1_dev;
57 struct workqueue_struct *monitor_wqueue; 57 struct workqueue_struct *monitor_wqueue;
58 struct delayed_work monitor_work; 58 struct delayed_work monitor_work;
59 }; 59 };
60 60
61 static unsigned int cache_time = 1000; 61 static unsigned int cache_time = 1000;
62 module_param(cache_time, uint, 0644); 62 module_param(cache_time, uint, 0644);
63 MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); 63 MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
64 64
65 /* Some batteries have their rated capacity stored a N * 10 mAh, while 65 /* Some batteries have their rated capacity stored a N * 10 mAh, while
66 * others use an index into this table. */ 66 * others use an index into this table. */
67 static int rated_capacities[] = { 67 static int rated_capacities[] = {
68 0, 68 0,
69 920, /* Samsung */ 69 920, /* Samsung */
70 920, /* BYD */ 70 920, /* BYD */
71 920, /* Lishen */ 71 920, /* Lishen */
72 920, /* NEC */ 72 920, /* NEC */
73 1440, /* Samsung */ 73 1440, /* Samsung */
74 1440, /* BYD */ 74 1440, /* BYD */
75 1440, /* Lishen */ 75 1440, /* Lishen */
76 1440, /* NEC */ 76 1440, /* NEC */
77 2880, /* Samsung */ 77 2880, /* Samsung */
78 2880, /* BYD */ 78 2880, /* BYD */
79 2880, /* Lishen */ 79 2880, /* Lishen */
80 2880 /* NEC */ 80 2880 /* NEC */
81 }; 81 };
82 82
83 /* array is level at temps 0°C, 10°C, 20°C, 30°C, 40°C 83 /* array is level at temps 0°C, 10°C, 20°C, 30°C, 40°C
84 * temp is in Celsius */ 84 * temp is in Celsius */
85 static int battery_interpolate(int array[], int temp) 85 static int battery_interpolate(int array[], int temp)
86 { 86 {
87 int index, dt; 87 int index, dt;
88 88
89 if (temp <= 0) 89 if (temp <= 0)
90 return array[0]; 90 return array[0];
91 if (temp >= 40) 91 if (temp >= 40)
92 return array[4]; 92 return array[4];
93 93
94 index = temp / 10; 94 index = temp / 10;
95 dt = temp % 10; 95 dt = temp % 10;
96 96
97 return array[index] + (((array[index + 1] - array[index]) * dt) / 10); 97 return array[index] + (((array[index + 1] - array[index]) * dt) / 10);
98 } 98 }
99 99
100 static int ds2760_battery_read_status(struct ds2760_device_info *di) 100 static int ds2760_battery_read_status(struct ds2760_device_info *di)
101 { 101 {
102 int ret, i, start, count, scale[5]; 102 int ret, i, start, count, scale[5];
103 103
104 if (di->update_time && time_before(jiffies, di->update_time + 104 if (di->update_time && time_before(jiffies, di->update_time +
105 msecs_to_jiffies(cache_time))) 105 msecs_to_jiffies(cache_time)))
106 return 0; 106 return 0;
107 107
108 /* The first time we read the entire contents of SRAM/EEPROM, 108 /* The first time we read the entire contents of SRAM/EEPROM,
109 * but after that we just read the interesting bits that change. */ 109 * but after that we just read the interesting bits that change. */
110 if (di->update_time == 0) { 110 if (di->update_time == 0) {
111 start = 0; 111 start = 0;
112 count = DS2760_DATA_SIZE; 112 count = DS2760_DATA_SIZE;
113 } else { 113 } else {
114 start = DS2760_VOLTAGE_MSB; 114 start = DS2760_VOLTAGE_MSB;
115 count = DS2760_TEMP_LSB - start + 1; 115 count = DS2760_TEMP_LSB - start + 1;
116 } 116 }
117 117
118 ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count); 118 ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count);
119 if (ret != count) { 119 if (ret != count) {
120 dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n", 120 dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n",
121 di->w1_dev); 121 di->w1_dev);
122 return 1; 122 return 1;
123 } 123 }
124 124
125 di->update_time = jiffies; 125 di->update_time = jiffies;
126 126
127 /* DS2760 reports voltage in units of 4.88mV, but the battery class 127 /* DS2760 reports voltage in units of 4.88mV, but the battery class
128 * reports in units of uV, so convert by multiplying by 4880. */ 128 * reports in units of uV, so convert by multiplying by 4880. */
129 di->voltage_raw = (di->raw[DS2760_VOLTAGE_MSB] << 3) | 129 di->voltage_raw = (di->raw[DS2760_VOLTAGE_MSB] << 3) |
130 (di->raw[DS2760_VOLTAGE_LSB] >> 5); 130 (di->raw[DS2760_VOLTAGE_LSB] >> 5);
131 di->voltage_uV = di->voltage_raw * 4880; 131 di->voltage_uV = di->voltage_raw * 4880;
132 132
133 /* DS2760 reports current in signed units of 0.625mA, but the battery 133 /* DS2760 reports current in signed units of 0.625mA, but the battery
134 * class reports in units of µA, so convert by multiplying by 625. */ 134 * class reports in units of µA, so convert by multiplying by 625. */
135 di->current_raw = 135 di->current_raw =
136 (((signed char)di->raw[DS2760_CURRENT_MSB]) << 5) | 136 (((signed char)di->raw[DS2760_CURRENT_MSB]) << 5) |
137 (di->raw[DS2760_CURRENT_LSB] >> 3); 137 (di->raw[DS2760_CURRENT_LSB] >> 3);
138 di->current_uA = di->current_raw * 625; 138 di->current_uA = di->current_raw * 625;
139 139
140 /* DS2760 reports accumulated current in signed units of 0.25mAh. */ 140 /* DS2760 reports accumulated current in signed units of 0.25mAh. */
141 di->accum_current_raw = 141 di->accum_current_raw =
142 (((signed char)di->raw[DS2760_CURRENT_ACCUM_MSB]) << 8) | 142 (((signed char)di->raw[DS2760_CURRENT_ACCUM_MSB]) << 8) |
143 di->raw[DS2760_CURRENT_ACCUM_LSB]; 143 di->raw[DS2760_CURRENT_ACCUM_LSB];
144 di->accum_current_uAh = di->accum_current_raw * 250; 144 di->accum_current_uAh = di->accum_current_raw * 250;
145 145
146 /* DS2760 reports temperature in signed units of 0.125°C, but the 146 /* DS2760 reports temperature in signed units of 0.125°C, but the
147 * battery class reports in units of 1/10 °C, so we convert by 147 * battery class reports in units of 1/10 °C, so we convert by
148 * multiplying by .125 * 10 = 1.25. */ 148 * multiplying by .125 * 10 = 1.25. */
149 di->temp_raw = (((signed char)di->raw[DS2760_TEMP_MSB]) << 3) | 149 di->temp_raw = (((signed char)di->raw[DS2760_TEMP_MSB]) << 3) |
150 (di->raw[DS2760_TEMP_LSB] >> 5); 150 (di->raw[DS2760_TEMP_LSB] >> 5);
151 di->temp_C = di->temp_raw + (di->temp_raw / 4); 151 di->temp_C = di->temp_raw + (di->temp_raw / 4);
152 152
153 /* At least some battery monitors (e.g. HP iPAQ) store the battery's 153 /* At least some battery monitors (e.g. HP iPAQ) store the battery's
154 * maximum rated capacity. */ 154 * maximum rated capacity. */
155 if (di->raw[DS2760_RATED_CAPACITY] < ARRAY_SIZE(rated_capacities)) 155 if (di->raw[DS2760_RATED_CAPACITY] < ARRAY_SIZE(rated_capacities))
156 di->rated_capacity = rated_capacities[ 156 di->rated_capacity = rated_capacities[
157 (unsigned int)di->raw[DS2760_RATED_CAPACITY]]; 157 (unsigned int)di->raw[DS2760_RATED_CAPACITY]];
158 else 158 else
159 di->rated_capacity = di->raw[DS2760_RATED_CAPACITY] * 10; 159 di->rated_capacity = di->raw[DS2760_RATED_CAPACITY] * 10;
160 160
161 di->rated_capacity *= 1000; /* convert to µAh */ 161 di->rated_capacity *= 1000; /* convert to µAh */
162 162
163 /* Calculate the full level at the present temperature. */ 163 /* Calculate the full level at the present temperature. */
164 di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 | 164 di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 |
165 di->raw[DS2760_ACTIVE_FULL + 1]; 165 di->raw[DS2760_ACTIVE_FULL + 1];
166 166
167 scale[0] = di->raw[DS2760_ACTIVE_FULL] << 8 | 167 scale[0] = di->raw[DS2760_ACTIVE_FULL] << 8 |
168 di->raw[DS2760_ACTIVE_FULL + 1]; 168 di->raw[DS2760_ACTIVE_FULL + 1];
169 for (i = 1; i < 5; i++) 169 for (i = 1; i < 5; i++)
170 scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i]; 170 scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i];
171 171
172 di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10); 172 di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10);
173 di->full_active_uAh *= 1000; /* convert to µAh */ 173 di->full_active_uAh *= 1000; /* convert to µAh */
174 174
175 /* Calculate the empty level at the present temperature. */ 175 /* Calculate the empty level at the present temperature. */
176 scale[4] = di->raw[DS2760_ACTIVE_EMPTY + 4]; 176 scale[4] = di->raw[DS2760_ACTIVE_EMPTY + 4];
177 for (i = 3; i >= 0; i--) 177 for (i = 3; i >= 0; i--)
178 scale[i] = scale[i + 1] + di->raw[DS2760_ACTIVE_EMPTY + i]; 178 scale[i] = scale[i + 1] + di->raw[DS2760_ACTIVE_EMPTY + i];
179 179
180 di->empty_uAh = battery_interpolate(scale, di->temp_C / 10); 180 di->empty_uAh = battery_interpolate(scale, di->temp_C / 10);
181 di->empty_uAh *= 1000; /* convert to µAh */ 181 di->empty_uAh *= 1000; /* convert to µAh */
182 182
183 /* From Maxim Application Note 131: remaining capacity = 183 /* From Maxim Application Note 131: remaining capacity =
184 * ((ICA - Empty Value) / (Full Value - Empty Value)) x 100% */ 184 * ((ICA - Empty Value) / (Full Value - Empty Value)) x 100% */
185 di->rem_capacity = ((di->accum_current_uAh - di->empty_uAh) * 100L) / 185 di->rem_capacity = ((di->accum_current_uAh - di->empty_uAh) * 100L) /
186 (di->full_active_uAh - di->empty_uAh); 186 (di->full_active_uAh - di->empty_uAh);
187 187
188 if (di->rem_capacity < 0) 188 if (di->rem_capacity < 0)
189 di->rem_capacity = 0; 189 di->rem_capacity = 0;
190 if (di->rem_capacity > 100) 190 if (di->rem_capacity > 100)
191 di->rem_capacity = 100; 191 di->rem_capacity = 100;
192 192
193 if (di->current_uA) 193 if (di->current_uA)
194 di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * 194 di->life_sec = -((di->accum_current_uAh - di->empty_uAh) *
195 3600L) / di->current_uA; 195 3600L) / di->current_uA;
196 else 196 else
197 di->life_sec = 0; 197 di->life_sec = 0;
198 198
199 return 0; 199 return 0;
200 } 200 }
201 201
202 static void ds2760_battery_update_status(struct ds2760_device_info *di) 202 static void ds2760_battery_update_status(struct ds2760_device_info *di)
203 { 203 {
204 int old_charge_status = di->charge_status; 204 int old_charge_status = di->charge_status;
205 205
206 ds2760_battery_read_status(di); 206 ds2760_battery_read_status(di);
207 207
208 if (di->charge_status == POWER_SUPPLY_STATUS_UNKNOWN) 208 if (di->charge_status == POWER_SUPPLY_STATUS_UNKNOWN)
209 di->full_counter = 0; 209 di->full_counter = 0;
210 210
211 if (power_supply_am_i_supplied(&di->bat)) { 211 if (power_supply_am_i_supplied(&di->bat)) {
212 if (di->current_uA > 10000) { 212 if (di->current_uA > 10000) {
213 di->charge_status = POWER_SUPPLY_STATUS_CHARGING; 213 di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
214 di->full_counter = 0; 214 di->full_counter = 0;
215 } else if (di->current_uA < -5000) { 215 } else if (di->current_uA < -5000) {
216 if (di->charge_status != POWER_SUPPLY_STATUS_NOT_CHARGING) 216 if (di->charge_status != POWER_SUPPLY_STATUS_NOT_CHARGING)
217 dev_notice(di->dev, "not enough power to " 217 dev_notice(di->dev, "not enough power to "
218 "charge\n"); 218 "charge\n");
219 di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING; 219 di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING;
220 di->full_counter = 0; 220 di->full_counter = 0;
221 } else if (di->current_uA < 10000 && 221 } else if (di->current_uA < 10000 &&
222 di->charge_status != POWER_SUPPLY_STATUS_FULL) { 222 di->charge_status != POWER_SUPPLY_STATUS_FULL) {
223 223
224 /* Don't consider the battery to be full unless 224 /* Don't consider the battery to be full unless
225 * we've seen the current < 10 mA at least two 225 * we've seen the current < 10 mA at least two
226 * consecutive times. */ 226 * consecutive times. */
227 227
228 di->full_counter++; 228 di->full_counter++;
229 229
230 if (di->full_counter < 2) { 230 if (di->full_counter < 2) {
231 di->charge_status = POWER_SUPPLY_STATUS_CHARGING; 231 di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
232 } else { 232 } else {
233 unsigned char acr[2]; 233 unsigned char acr[2];
234 int acr_val; 234 int acr_val;
235 235
236 /* acr is in units of 0.25 mAh */ 236 /* acr is in units of 0.25 mAh */
237 acr_val = di->full_active_uAh * 4L / 1000; 237 acr_val = di->full_active_uAh * 4L / 1000;
238 238
239 acr[0] = acr_val >> 8; 239 acr[0] = acr_val >> 8;
240 acr[1] = acr_val & 0xff; 240 acr[1] = acr_val & 0xff;
241 241
242 if (w1_ds2760_write(di->w1_dev, acr, 242 if (w1_ds2760_write(di->w1_dev, acr,
243 DS2760_CURRENT_ACCUM_MSB, 2) < 2) 243 DS2760_CURRENT_ACCUM_MSB, 2) < 2)
244 dev_warn(di->dev, 244 dev_warn(di->dev,
245 "ACR reset failed\n"); 245 "ACR reset failed\n");
246 246
247 di->charge_status = POWER_SUPPLY_STATUS_FULL; 247 di->charge_status = POWER_SUPPLY_STATUS_FULL;
248 } 248 }
249 } 249 }
250 } else { 250 } else {
251 di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING; 251 di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
252 di->full_counter = 0; 252 di->full_counter = 0;
253 } 253 }
254 254
255 if (di->charge_status != old_charge_status) 255 if (di->charge_status != old_charge_status)
256 power_supply_changed(&di->bat); 256 power_supply_changed(&di->bat);
257
258 return;
259 } 257 }
260 258
261 static void ds2760_battery_work(struct work_struct *work) 259 static void ds2760_battery_work(struct work_struct *work)
262 { 260 {
263 struct ds2760_device_info *di = container_of(work, 261 struct ds2760_device_info *di = container_of(work,
264 struct ds2760_device_info, monitor_work.work); 262 struct ds2760_device_info, monitor_work.work);
265 const int interval = HZ * 60; 263 const int interval = HZ * 60;
266 264
267 dev_dbg(di->dev, "%s\n", __FUNCTION__); 265 dev_dbg(di->dev, "%s\n", __FUNCTION__);
268 266
269 ds2760_battery_update_status(di); 267 ds2760_battery_update_status(di);
270 queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval); 268 queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval);
271
272 return;
273 } 269 }
274 270
275 #define to_ds2760_device_info(x) container_of((x), struct ds2760_device_info, \ 271 #define to_ds2760_device_info(x) container_of((x), struct ds2760_device_info, \
276 bat); 272 bat);
277 273
278 static void ds2760_battery_external_power_changed(struct power_supply *psy) 274 static void ds2760_battery_external_power_changed(struct power_supply *psy)
279 { 275 {
280 struct ds2760_device_info *di = to_ds2760_device_info(psy); 276 struct ds2760_device_info *di = to_ds2760_device_info(psy);
281 277
282 dev_dbg(di->dev, "%s\n", __FUNCTION__); 278 dev_dbg(di->dev, "%s\n", __FUNCTION__);
283 279
284 cancel_delayed_work(&di->monitor_work); 280 cancel_delayed_work(&di->monitor_work);
285 queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10); 281 queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
286
287 return;
288 } 282 }
289 283
290 static int ds2760_battery_get_property(struct power_supply *psy, 284 static int ds2760_battery_get_property(struct power_supply *psy,
291 enum power_supply_property psp, 285 enum power_supply_property psp,
292 union power_supply_propval *val) 286 union power_supply_propval *val)
293 { 287 {
294 struct ds2760_device_info *di = to_ds2760_device_info(psy); 288 struct ds2760_device_info *di = to_ds2760_device_info(psy);
295 289
296 switch (psp) { 290 switch (psp) {
297 case POWER_SUPPLY_PROP_STATUS: 291 case POWER_SUPPLY_PROP_STATUS:
298 val->intval = di->charge_status; 292 val->intval = di->charge_status;
299 return 0; 293 return 0;
300 default: 294 default:
301 break; 295 break;
302 } 296 }
303 297
304 ds2760_battery_read_status(di); 298 ds2760_battery_read_status(di);
305 299
306 switch (psp) { 300 switch (psp) {
307 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 301 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
308 val->intval = di->voltage_uV; 302 val->intval = di->voltage_uV;
309 break; 303 break;
310 case POWER_SUPPLY_PROP_CURRENT_NOW: 304 case POWER_SUPPLY_PROP_CURRENT_NOW:
311 val->intval = di->current_uA; 305 val->intval = di->current_uA;
312 break; 306 break;
313 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 307 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
314 val->intval = di->rated_capacity; 308 val->intval = di->rated_capacity;
315 break; 309 break;
316 case POWER_SUPPLY_PROP_CHARGE_FULL: 310 case POWER_SUPPLY_PROP_CHARGE_FULL:
317 val->intval = di->full_active_uAh; 311 val->intval = di->full_active_uAh;
318 break; 312 break;
319 case POWER_SUPPLY_PROP_CHARGE_EMPTY: 313 case POWER_SUPPLY_PROP_CHARGE_EMPTY:
320 val->intval = di->empty_uAh; 314 val->intval = di->empty_uAh;
321 break; 315 break;
322 case POWER_SUPPLY_PROP_CHARGE_NOW: 316 case POWER_SUPPLY_PROP_CHARGE_NOW:
323 val->intval = di->accum_current_uAh; 317 val->intval = di->accum_current_uAh;
324 break; 318 break;
325 case POWER_SUPPLY_PROP_TEMP: 319 case POWER_SUPPLY_PROP_TEMP:
326 val->intval = di->temp_C; 320 val->intval = di->temp_C;
327 break; 321 break;
328 default: 322 default:
329 return -EINVAL; 323 return -EINVAL;
330 } 324 }
331 325
332 return 0; 326 return 0;
333 } 327 }
334 328
335 static enum power_supply_property ds2760_battery_props[] = { 329 static enum power_supply_property ds2760_battery_props[] = {
336 POWER_SUPPLY_PROP_STATUS, 330 POWER_SUPPLY_PROP_STATUS,
337 POWER_SUPPLY_PROP_VOLTAGE_NOW, 331 POWER_SUPPLY_PROP_VOLTAGE_NOW,
338 POWER_SUPPLY_PROP_CURRENT_NOW, 332 POWER_SUPPLY_PROP_CURRENT_NOW,
339 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 333 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
340 POWER_SUPPLY_PROP_CHARGE_FULL, 334 POWER_SUPPLY_PROP_CHARGE_FULL,
341 POWER_SUPPLY_PROP_CHARGE_EMPTY, 335 POWER_SUPPLY_PROP_CHARGE_EMPTY,
342 POWER_SUPPLY_PROP_CHARGE_NOW, 336 POWER_SUPPLY_PROP_CHARGE_NOW,
343 POWER_SUPPLY_PROP_TEMP, 337 POWER_SUPPLY_PROP_TEMP,
344 }; 338 };
345 339
346 static int ds2760_battery_probe(struct platform_device *pdev) 340 static int ds2760_battery_probe(struct platform_device *pdev)
347 { 341 {
348 int retval = 0; 342 int retval = 0;
349 struct ds2760_device_info *di; 343 struct ds2760_device_info *di;
350 struct ds2760_platform_data *pdata; 344 struct ds2760_platform_data *pdata;
351 345
352 di = kzalloc(sizeof(*di), GFP_KERNEL); 346 di = kzalloc(sizeof(*di), GFP_KERNEL);
353 if (!di) { 347 if (!di) {
354 retval = -ENOMEM; 348 retval = -ENOMEM;
355 goto di_alloc_failed; 349 goto di_alloc_failed;
356 } 350 }
357 351
358 platform_set_drvdata(pdev, di); 352 platform_set_drvdata(pdev, di);
359 353
360 pdata = pdev->dev.platform_data; 354 pdata = pdev->dev.platform_data;
361 di->dev = &pdev->dev; 355 di->dev = &pdev->dev;
362 di->w1_dev = pdev->dev.parent; 356 di->w1_dev = pdev->dev.parent;
363 di->bat.name = pdev->dev.bus_id; 357 di->bat.name = pdev->dev.bus_id;
364 di->bat.type = POWER_SUPPLY_TYPE_BATTERY; 358 di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
365 di->bat.properties = ds2760_battery_props; 359 di->bat.properties = ds2760_battery_props;
366 di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props); 360 di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props);
367 di->bat.get_property = ds2760_battery_get_property; 361 di->bat.get_property = ds2760_battery_get_property;
368 di->bat.external_power_changed = 362 di->bat.external_power_changed =
369 ds2760_battery_external_power_changed; 363 ds2760_battery_external_power_changed;
370 364
371 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; 365 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
372 366
373 retval = power_supply_register(&pdev->dev, &di->bat); 367 retval = power_supply_register(&pdev->dev, &di->bat);
374 if (retval) { 368 if (retval) {
375 dev_err(di->dev, "failed to register battery"); 369 dev_err(di->dev, "failed to register battery");
376 goto batt_failed; 370 goto batt_failed;
377 } 371 }
378 372
379 INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work); 373 INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work);
380 di->monitor_wqueue = create_singlethread_workqueue(pdev->dev.bus_id); 374 di->monitor_wqueue = create_singlethread_workqueue(pdev->dev.bus_id);
381 if (!di->monitor_wqueue) { 375 if (!di->monitor_wqueue) {
382 retval = -ESRCH; 376 retval = -ESRCH;
383 goto workqueue_failed; 377 goto workqueue_failed;
384 } 378 }
385 queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1); 379 queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1);
386 380
387 goto success; 381 goto success;
388 382
389 workqueue_failed: 383 workqueue_failed:
390 power_supply_unregister(&di->bat); 384 power_supply_unregister(&di->bat);
391 batt_failed: 385 batt_failed:
392 kfree(di); 386 kfree(di);
393 di_alloc_failed: 387 di_alloc_failed:
394 success: 388 success:
395 return retval; 389 return retval;
396 } 390 }
397 391
398 static int ds2760_battery_remove(struct platform_device *pdev) 392 static int ds2760_battery_remove(struct platform_device *pdev)
399 { 393 {
400 struct ds2760_device_info *di = platform_get_drvdata(pdev); 394 struct ds2760_device_info *di = platform_get_drvdata(pdev);
401 395
402 cancel_rearming_delayed_workqueue(di->monitor_wqueue, 396 cancel_rearming_delayed_workqueue(di->monitor_wqueue,
403 &di->monitor_work); 397 &di->monitor_work);
404 destroy_workqueue(di->monitor_wqueue); 398 destroy_workqueue(di->monitor_wqueue);
405 power_supply_unregister(&di->bat); 399 power_supply_unregister(&di->bat);
406 400
407 return 0; 401 return 0;
408 } 402 }
409 403
410 #ifdef CONFIG_PM 404 #ifdef CONFIG_PM
411 405
412 static int ds2760_battery_suspend(struct platform_device *pdev, 406 static int ds2760_battery_suspend(struct platform_device *pdev,
413 pm_message_t state) 407 pm_message_t state)
414 { 408 {
415 struct ds2760_device_info *di = platform_get_drvdata(pdev); 409 struct ds2760_device_info *di = platform_get_drvdata(pdev);
416 410
417 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; 411 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
418 412
419 return 0; 413 return 0;
420 } 414 }
421 415
422 static int ds2760_battery_resume(struct platform_device *pdev) 416 static int ds2760_battery_resume(struct platform_device *pdev)
423 { 417 {
424 struct ds2760_device_info *di = platform_get_drvdata(pdev); 418 struct ds2760_device_info *di = platform_get_drvdata(pdev);
425 419
426 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; 420 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
427 power_supply_changed(&di->bat); 421 power_supply_changed(&di->bat);
428 422
429 cancel_delayed_work(&di->monitor_work); 423 cancel_delayed_work(&di->monitor_work);
430 queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ); 424 queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ);
431 425
432 return 0; 426 return 0;
433 } 427 }
434 428
435 #else 429 #else
436 430
437 #define ds2760_battery_suspend NULL 431 #define ds2760_battery_suspend NULL
438 #define ds2760_battery_resume NULL 432 #define ds2760_battery_resume NULL
439 433
440 #endif /* CONFIG_PM */ 434 #endif /* CONFIG_PM */
441 435
442 static struct platform_driver ds2760_battery_driver = { 436 static struct platform_driver ds2760_battery_driver = {
443 .driver = { 437 .driver = {
444 .name = "ds2760-battery", 438 .name = "ds2760-battery",
445 }, 439 },
446 .probe = ds2760_battery_probe, 440 .probe = ds2760_battery_probe,
447 .remove = ds2760_battery_remove, 441 .remove = ds2760_battery_remove,
448 .suspend = ds2760_battery_suspend, 442 .suspend = ds2760_battery_suspend,
449 .resume = ds2760_battery_resume, 443 .resume = ds2760_battery_resume,
450 }; 444 };
451 445
452 static int __init ds2760_battery_init(void) 446 static int __init ds2760_battery_init(void)
453 { 447 {
454 return platform_driver_register(&ds2760_battery_driver); 448 return platform_driver_register(&ds2760_battery_driver);
455 } 449 }
456 450
457 static void __exit ds2760_battery_exit(void) 451 static void __exit ds2760_battery_exit(void)
458 { 452 {
459 platform_driver_unregister(&ds2760_battery_driver); 453 platform_driver_unregister(&ds2760_battery_driver);
460 return;
461 } 454 }
462 455
463 module_init(ds2760_battery_init); 456 module_init(ds2760_battery_init);
464 module_exit(ds2760_battery_exit); 457 module_exit(ds2760_battery_exit);
465 458
466 MODULE_LICENSE("GPL"); 459 MODULE_LICENSE("GPL");
467 MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " 460 MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
468 "Matt Reimer <mreimer@vpop.net>, " 461 "Matt Reimer <mreimer@vpop.net>, "
469 "Anton Vorontsov <cbou@mail.ru>"); 462 "Anton Vorontsov <cbou@mail.ru>");
470 MODULE_DESCRIPTION("ds2760 battery driver"); 463 MODULE_DESCRIPTION("ds2760 battery driver");
471 464
drivers/power/olpc_battery.c
1 /* 1 /*
2 * Battery driver for One Laptop Per Child board. 2 * Battery driver for One Laptop Per Child board.
3 * 3 *
4 * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> 4 * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11 #include <linux/module.h> 11 #include <linux/module.h>
12 #include <linux/err.h> 12 #include <linux/err.h>
13 #include <linux/platform_device.h> 13 #include <linux/platform_device.h>
14 #include <linux/power_supply.h> 14 #include <linux/power_supply.h>
15 #include <linux/jiffies.h> 15 #include <linux/jiffies.h>
16 #include <linux/sched.h> 16 #include <linux/sched.h>
17 #include <asm/olpc.h> 17 #include <asm/olpc.h>
18 18
19 19
20 #define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */ 20 #define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */
21 #define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */ 21 #define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */
22 #define EC_BAT_ACR 0x12 22 #define EC_BAT_ACR 0x12
23 #define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */ 23 #define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */
24 #define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */ 24 #define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */
25 #define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */ 25 #define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */
26 #define EC_BAT_SOC 0x16 /* uint8_t, percentage */ 26 #define EC_BAT_SOC 0x16 /* uint8_t, percentage */
27 #define EC_BAT_SERIAL 0x17 /* uint8_t[6] */ 27 #define EC_BAT_SERIAL 0x17 /* uint8_t[6] */
28 #define EC_BAT_EEPROM 0x18 /* uint8_t adr as input, uint8_t output */ 28 #define EC_BAT_EEPROM 0x18 /* uint8_t adr as input, uint8_t output */
29 #define EC_BAT_ERRCODE 0x1f /* uint8_t, bitmask */ 29 #define EC_BAT_ERRCODE 0x1f /* uint8_t, bitmask */
30 30
31 #define BAT_STAT_PRESENT 0x01 31 #define BAT_STAT_PRESENT 0x01
32 #define BAT_STAT_FULL 0x02 32 #define BAT_STAT_FULL 0x02
33 #define BAT_STAT_LOW 0x04 33 #define BAT_STAT_LOW 0x04
34 #define BAT_STAT_DESTROY 0x08 34 #define BAT_STAT_DESTROY 0x08
35 #define BAT_STAT_AC 0x10 35 #define BAT_STAT_AC 0x10
36 #define BAT_STAT_CHARGING 0x20 36 #define BAT_STAT_CHARGING 0x20
37 #define BAT_STAT_DISCHARGING 0x40 37 #define BAT_STAT_DISCHARGING 0x40
38 38
39 #define BAT_ERR_INFOFAIL 0x02 39 #define BAT_ERR_INFOFAIL 0x02
40 #define BAT_ERR_OVERVOLTAGE 0x04 40 #define BAT_ERR_OVERVOLTAGE 0x04
41 #define BAT_ERR_OVERTEMP 0x05 41 #define BAT_ERR_OVERTEMP 0x05
42 #define BAT_ERR_GAUGESTOP 0x06 42 #define BAT_ERR_GAUGESTOP 0x06
43 #define BAT_ERR_OUT_OF_CONTROL 0x07 43 #define BAT_ERR_OUT_OF_CONTROL 0x07
44 #define BAT_ERR_ID_FAIL 0x09 44 #define BAT_ERR_ID_FAIL 0x09
45 #define BAT_ERR_ACR_FAIL 0x10 45 #define BAT_ERR_ACR_FAIL 0x10
46 46
47 #define BAT_ADDR_MFR_TYPE 0x5F 47 #define BAT_ADDR_MFR_TYPE 0x5F
48 48
49 /********************************************************************* 49 /*********************************************************************
50 * Power 50 * Power
51 *********************************************************************/ 51 *********************************************************************/
52 52
53 static int olpc_ac_get_prop(struct power_supply *psy, 53 static int olpc_ac_get_prop(struct power_supply *psy,
54 enum power_supply_property psp, 54 enum power_supply_property psp,
55 union power_supply_propval *val) 55 union power_supply_propval *val)
56 { 56 {
57 int ret = 0; 57 int ret = 0;
58 uint8_t status; 58 uint8_t status;
59 59
60 switch (psp) { 60 switch (psp) {
61 case POWER_SUPPLY_PROP_ONLINE: 61 case POWER_SUPPLY_PROP_ONLINE:
62 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1); 62 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1);
63 if (ret) 63 if (ret)
64 return ret; 64 return ret;
65 65
66 val->intval = !!(status & BAT_STAT_AC); 66 val->intval = !!(status & BAT_STAT_AC);
67 break; 67 break;
68 default: 68 default:
69 ret = -EINVAL; 69 ret = -EINVAL;
70 break; 70 break;
71 } 71 }
72 return ret; 72 return ret;
73 } 73 }
74 74
75 static enum power_supply_property olpc_ac_props[] = { 75 static enum power_supply_property olpc_ac_props[] = {
76 POWER_SUPPLY_PROP_ONLINE, 76 POWER_SUPPLY_PROP_ONLINE,
77 }; 77 };
78 78
79 static struct power_supply olpc_ac = { 79 static struct power_supply olpc_ac = {
80 .name = "olpc-ac", 80 .name = "olpc-ac",
81 .type = POWER_SUPPLY_TYPE_MAINS, 81 .type = POWER_SUPPLY_TYPE_MAINS,
82 .properties = olpc_ac_props, 82 .properties = olpc_ac_props,
83 .num_properties = ARRAY_SIZE(olpc_ac_props), 83 .num_properties = ARRAY_SIZE(olpc_ac_props),
84 .get_property = olpc_ac_get_prop, 84 .get_property = olpc_ac_get_prop,
85 }; 85 };
86 86
87 /********************************************************************* 87 /*********************************************************************
88 * Battery properties 88 * Battery properties
89 *********************************************************************/ 89 *********************************************************************/
90 static int olpc_bat_get_property(struct power_supply *psy, 90 static int olpc_bat_get_property(struct power_supply *psy,
91 enum power_supply_property psp, 91 enum power_supply_property psp,
92 union power_supply_propval *val) 92 union power_supply_propval *val)
93 { 93 {
94 int ret = 0; 94 int ret = 0;
95 int16_t ec_word; 95 int16_t ec_word;
96 uint8_t ec_byte; 96 uint8_t ec_byte;
97 97
98 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1); 98 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);
99 if (ret) 99 if (ret)
100 return ret; 100 return ret;
101 101
102 /* Theoretically there's a race here -- the battery could be 102 /* Theoretically there's a race here -- the battery could be
103 removed immediately after we check whether it's present, and 103 removed immediately after we check whether it's present, and
104 then we query for some other property of the now-absent battery. 104 then we query for some other property of the now-absent battery.
105 It doesn't matter though -- the EC will return the last-known 105 It doesn't matter though -- the EC will return the last-known
106 information, and it's as if we just ran that _little_ bit faster 106 information, and it's as if we just ran that _little_ bit faster
107 and managed to read it out before the battery went away. */ 107 and managed to read it out before the battery went away. */
108 if (!(ec_byte & BAT_STAT_PRESENT) && psp != POWER_SUPPLY_PROP_PRESENT) 108 if (!(ec_byte & BAT_STAT_PRESENT) && psp != POWER_SUPPLY_PROP_PRESENT)
109 return -ENODEV; 109 return -ENODEV;
110 110
111 switch (psp) { 111 switch (psp) {
112 case POWER_SUPPLY_PROP_STATUS: 112 case POWER_SUPPLY_PROP_STATUS:
113 if (olpc_platform_info.ecver > 0x44) { 113 if (olpc_platform_info.ecver > 0x44) {
114 if (ec_byte & BAT_STAT_CHARGING) 114 if (ec_byte & BAT_STAT_CHARGING)
115 val->intval = POWER_SUPPLY_STATUS_CHARGING; 115 val->intval = POWER_SUPPLY_STATUS_CHARGING;
116 else if (ec_byte & BAT_STAT_DISCHARGING) 116 else if (ec_byte & BAT_STAT_DISCHARGING)
117 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 117 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
118 else if (ec_byte & BAT_STAT_FULL) 118 else if (ec_byte & BAT_STAT_FULL)
119 val->intval = POWER_SUPPLY_STATUS_FULL; 119 val->intval = POWER_SUPPLY_STATUS_FULL;
120 else /* er,... */ 120 else /* er,... */
121 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; 121 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
122 } else { 122 } else {
123 /* Older EC didn't report charge/discharge bits */ 123 /* Older EC didn't report charge/discharge bits */
124 if (!(ec_byte & BAT_STAT_AC)) /* No AC means discharging */ 124 if (!(ec_byte & BAT_STAT_AC)) /* No AC means discharging */
125 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 125 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
126 else if (ec_byte & BAT_STAT_FULL) 126 else if (ec_byte & BAT_STAT_FULL)
127 val->intval = POWER_SUPPLY_STATUS_FULL; 127 val->intval = POWER_SUPPLY_STATUS_FULL;
128 else /* Not _necessarily_ true but EC doesn't tell all yet */ 128 else /* Not _necessarily_ true but EC doesn't tell all yet */
129 val->intval = POWER_SUPPLY_STATUS_CHARGING; 129 val->intval = POWER_SUPPLY_STATUS_CHARGING;
130 break; 130 break;
131 } 131 }
132 case POWER_SUPPLY_PROP_PRESENT: 132 case POWER_SUPPLY_PROP_PRESENT:
133 val->intval = !!(ec_byte & BAT_STAT_PRESENT); 133 val->intval = !!(ec_byte & BAT_STAT_PRESENT);
134 break; 134 break;
135 135
136 case POWER_SUPPLY_PROP_HEALTH: 136 case POWER_SUPPLY_PROP_HEALTH:
137 if (ec_byte & BAT_STAT_DESTROY) 137 if (ec_byte & BAT_STAT_DESTROY)
138 val->intval = POWER_SUPPLY_HEALTH_DEAD; 138 val->intval = POWER_SUPPLY_HEALTH_DEAD;
139 else { 139 else {
140 ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1); 140 ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);
141 if (ret) 141 if (ret)
142 return ret; 142 return ret;
143 143
144 switch (ec_byte) { 144 switch (ec_byte) {
145 case 0: 145 case 0:
146 val->intval = POWER_SUPPLY_HEALTH_GOOD; 146 val->intval = POWER_SUPPLY_HEALTH_GOOD;
147 break; 147 break;
148 148
149 case BAT_ERR_OVERTEMP: 149 case BAT_ERR_OVERTEMP:
150 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; 150 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
151 break; 151 break;
152 152
153 case BAT_ERR_OVERVOLTAGE: 153 case BAT_ERR_OVERVOLTAGE:
154 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; 154 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
155 break; 155 break;
156 156
157 case BAT_ERR_INFOFAIL: 157 case BAT_ERR_INFOFAIL:
158 case BAT_ERR_OUT_OF_CONTROL: 158 case BAT_ERR_OUT_OF_CONTROL:
159 case BAT_ERR_ID_FAIL: 159 case BAT_ERR_ID_FAIL:
160 case BAT_ERR_ACR_FAIL: 160 case BAT_ERR_ACR_FAIL:
161 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; 161 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
162 break; 162 break;
163 163
164 default: 164 default:
165 /* Eep. We don't know this failure code */ 165 /* Eep. We don't know this failure code */
166 return -EIO; 166 return -EIO;
167 } 167 }
168 } 168 }
169 break; 169 break;
170 170
171 case POWER_SUPPLY_PROP_MANUFACTURER: 171 case POWER_SUPPLY_PROP_MANUFACTURER:
172 ec_byte = BAT_ADDR_MFR_TYPE; 172 ec_byte = BAT_ADDR_MFR_TYPE;
173 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); 173 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
174 if (ret) 174 if (ret)
175 return ret; 175 return ret;
176 176
177 switch (ec_byte >> 4) { 177 switch (ec_byte >> 4) {
178 case 1: 178 case 1:
179 val->strval = "Gold Peak"; 179 val->strval = "Gold Peak";
180 break; 180 break;
181 case 2: 181 case 2:
182 val->strval = "BYD"; 182 val->strval = "BYD";
183 break; 183 break;
184 default: 184 default:
185 val->strval = "Unknown"; 185 val->strval = "Unknown";
186 break; 186 break;
187 } 187 }
188 break; 188 break;
189 case POWER_SUPPLY_PROP_TECHNOLOGY: 189 case POWER_SUPPLY_PROP_TECHNOLOGY:
190 ec_byte = BAT_ADDR_MFR_TYPE; 190 ec_byte = BAT_ADDR_MFR_TYPE;
191 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1); 191 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
192 if (ret) 192 if (ret)
193 return ret; 193 return ret;
194 194
195 switch (ec_byte & 0xf) { 195 switch (ec_byte & 0xf) {
196 case 1: 196 case 1:
197 val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH; 197 val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;
198 break; 198 break;
199 case 2: 199 case 2:
200 val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe; 200 val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe;
201 break; 201 break;
202 default: 202 default:
203 val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; 203 val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
204 break; 204 break;
205 } 205 }
206 break; 206 break;
207 case POWER_SUPPLY_PROP_VOLTAGE_AVG: 207 case POWER_SUPPLY_PROP_VOLTAGE_AVG:
208 ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2); 208 ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
209 if (ret) 209 if (ret)
210 return ret; 210 return ret;
211 211
212 ec_word = be16_to_cpu(ec_word); 212 ec_word = be16_to_cpu(ec_word);
213 val->intval = ec_word * 9760L / 32; 213 val->intval = ec_word * 9760L / 32;
214 break; 214 break;
215 case POWER_SUPPLY_PROP_CURRENT_AVG: 215 case POWER_SUPPLY_PROP_CURRENT_AVG:
216 ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2); 216 ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
217 if (ret) 217 if (ret)
218 return ret; 218 return ret;
219 219
220 ec_word = be16_to_cpu(ec_word); 220 ec_word = be16_to_cpu(ec_word);
221 val->intval = ec_word * 15625L / 120; 221 val->intval = ec_word * 15625L / 120;
222 break; 222 break;
223 case POWER_SUPPLY_PROP_CAPACITY: 223 case POWER_SUPPLY_PROP_CAPACITY:
224 ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1); 224 ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);
225 if (ret) 225 if (ret)
226 return ret; 226 return ret;
227 val->intval = ec_byte; 227 val->intval = ec_byte;
228 break; 228 break;
229 case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 229 case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
230 if (ec_byte & BAT_STAT_FULL) 230 if (ec_byte & BAT_STAT_FULL)
231 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 231 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
232 else if (ec_byte & BAT_STAT_LOW) 232 else if (ec_byte & BAT_STAT_LOW)
233 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 233 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
234 else 234 else
235 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 235 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
236 break; 236 break;
237 case POWER_SUPPLY_PROP_TEMP: 237 case POWER_SUPPLY_PROP_TEMP:
238 ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2); 238 ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
239 if (ret) 239 if (ret)
240 return ret; 240 return ret;
241 ec_word = be16_to_cpu(ec_word); 241 ec_word = be16_to_cpu(ec_word);
242 val->intval = ec_word * 100 / 256; 242 val->intval = ec_word * 100 / 256;
243 break; 243 break;
244 case POWER_SUPPLY_PROP_TEMP_AMBIENT: 244 case POWER_SUPPLY_PROP_TEMP_AMBIENT:
245 ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2); 245 ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
246 if (ret) 246 if (ret)
247 return ret; 247 return ret;
248 248
249 ec_word = be16_to_cpu(ec_word); 249 ec_word = be16_to_cpu(ec_word);
250 val->intval = ec_word * 100 / 256; 250 val->intval = ec_word * 100 / 256;
251 break; 251 break;
252 default: 252 default:
253 ret = -EINVAL; 253 ret = -EINVAL;
254 break; 254 break;
255 } 255 }
256 256
257 return ret; 257 return ret;
258 } 258 }
259 259
260 static enum power_supply_property olpc_bat_props[] = { 260 static enum power_supply_property olpc_bat_props[] = {
261 POWER_SUPPLY_PROP_STATUS, 261 POWER_SUPPLY_PROP_STATUS,
262 POWER_SUPPLY_PROP_PRESENT, 262 POWER_SUPPLY_PROP_PRESENT,
263 POWER_SUPPLY_PROP_HEALTH, 263 POWER_SUPPLY_PROP_HEALTH,
264 POWER_SUPPLY_PROP_TECHNOLOGY, 264 POWER_SUPPLY_PROP_TECHNOLOGY,
265 POWER_SUPPLY_PROP_VOLTAGE_AVG, 265 POWER_SUPPLY_PROP_VOLTAGE_AVG,
266 POWER_SUPPLY_PROP_CURRENT_AVG, 266 POWER_SUPPLY_PROP_CURRENT_AVG,
267 POWER_SUPPLY_PROP_CAPACITY, 267 POWER_SUPPLY_PROP_CAPACITY,
268 POWER_SUPPLY_PROP_CAPACITY_LEVEL, 268 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
269 POWER_SUPPLY_PROP_TEMP, 269 POWER_SUPPLY_PROP_TEMP,
270 POWER_SUPPLY_PROP_TEMP_AMBIENT, 270 POWER_SUPPLY_PROP_TEMP_AMBIENT,
271 POWER_SUPPLY_PROP_MANUFACTURER, 271 POWER_SUPPLY_PROP_MANUFACTURER,
272 }; 272 };
273 273
274 /********************************************************************* 274 /*********************************************************************
275 * Initialisation 275 * Initialisation
276 *********************************************************************/ 276 *********************************************************************/
277 277
278 static struct platform_device *bat_pdev; 278 static struct platform_device *bat_pdev;
279 279
280 static struct power_supply olpc_bat = { 280 static struct power_supply olpc_bat = {
281 .properties = olpc_bat_props, 281 .properties = olpc_bat_props,
282 .num_properties = ARRAY_SIZE(olpc_bat_props), 282 .num_properties = ARRAY_SIZE(olpc_bat_props),
283 .get_property = olpc_bat_get_property, 283 .get_property = olpc_bat_get_property,
284 .use_for_apm = 1, 284 .use_for_apm = 1,
285 }; 285 };
286 286
287 void olpc_battery_trigger_uevent(unsigned long cause) 287 void olpc_battery_trigger_uevent(unsigned long cause)
288 { 288 {
289 if (cause & EC_SCI_SRC_ACPWR) 289 if (cause & EC_SCI_SRC_ACPWR)
290 kobject_uevent(&olpc_ac.dev->kobj, KOBJ_CHANGE); 290 kobject_uevent(&olpc_ac.dev->kobj, KOBJ_CHANGE);
291 if (cause & (EC_SCI_SRC_BATERR|EC_SCI_SRC_BATSOC|EC_SCI_SRC_BATTERY)) 291 if (cause & (EC_SCI_SRC_BATERR|EC_SCI_SRC_BATSOC|EC_SCI_SRC_BATTERY))
292 kobject_uevent(&olpc_bat.dev->kobj, KOBJ_CHANGE); 292 kobject_uevent(&olpc_bat.dev->kobj, KOBJ_CHANGE);
293 } 293 }
294 294
295 static int __init olpc_bat_init(void) 295 static int __init olpc_bat_init(void)
296 { 296 {
297 int ret = 0; 297 int ret = 0;
298 uint8_t status; 298 uint8_t status;
299 299
300 if (!olpc_platform_info.ecver) 300 if (!olpc_platform_info.ecver)
301 return -ENXIO; 301 return -ENXIO;
302 if (olpc_platform_info.ecver < 0x43) { 302 if (olpc_platform_info.ecver < 0x43) {
303 printk(KERN_NOTICE "OLPC EC version 0x%02x too old for battery driver.\n", olpc_platform_info.ecver); 303 printk(KERN_NOTICE "OLPC EC version 0x%02x too old for battery driver.\n", olpc_platform_info.ecver);
304 return -ENXIO; 304 return -ENXIO;
305 } 305 }
306 306
307 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1); 307 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1);
308 if (ret) 308 if (ret)
309 return ret; 309 return ret;
310 310
311 /* Ignore the status. It doesn't actually matter */ 311 /* Ignore the status. It doesn't actually matter */
312 312
313 bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0); 313 bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0);
314 if (IS_ERR(bat_pdev)) 314 if (IS_ERR(bat_pdev))
315 return PTR_ERR(bat_pdev); 315 return PTR_ERR(bat_pdev);
316 316
317 ret = power_supply_register(&bat_pdev->dev, &olpc_ac); 317 ret = power_supply_register(&bat_pdev->dev, &olpc_ac);
318 if (ret) 318 if (ret)
319 goto ac_failed; 319 goto ac_failed;
320 320
321 olpc_bat.name = bat_pdev->name; 321 olpc_bat.name = bat_pdev->name;
322 322
323 ret = power_supply_register(&bat_pdev->dev, &olpc_bat); 323 ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
324 if (ret) 324 if (ret)
325 goto battery_failed; 325 goto battery_failed;
326 326
327 olpc_register_battery_callback(&olpc_battery_trigger_uevent); 327 olpc_register_battery_callback(&olpc_battery_trigger_uevent);
328 goto success; 328 goto success;
329 329
330 battery_failed: 330 battery_failed:
331 power_supply_unregister(&olpc_ac); 331 power_supply_unregister(&olpc_ac);
332 ac_failed: 332 ac_failed:
333 platform_device_unregister(bat_pdev); 333 platform_device_unregister(bat_pdev);
334 success: 334 success:
335 return ret; 335 return ret;
336 } 336 }
337 337
338 static void __exit olpc_bat_exit(void) 338 static void __exit olpc_bat_exit(void)
339 { 339 {
340 olpc_deregister_battery_callback(); 340 olpc_deregister_battery_callback();
341 power_supply_unregister(&olpc_bat); 341 power_supply_unregister(&olpc_bat);
342 power_supply_unregister(&olpc_ac); 342 power_supply_unregister(&olpc_ac);
343 platform_device_unregister(bat_pdev); 343 platform_device_unregister(bat_pdev);
344 return;
345 } 344 }
346 345
347 module_init(olpc_bat_init); 346 module_init(olpc_bat_init);
348 module_exit(olpc_bat_exit); 347 module_exit(olpc_bat_exit);
349 348
350 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 349 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
351 MODULE_LICENSE("GPL"); 350 MODULE_LICENSE("GPL");
352 MODULE_DESCRIPTION("Battery driver for One Laptop Per Child 'XO' machine"); 351 MODULE_DESCRIPTION("Battery driver for One Laptop Per Child 'XO' machine");
353 352
drivers/power/pda_power.c
1 /* 1 /*
2 * Common power driver for PDAs and phones with one or two external 2 * Common power driver for PDAs and phones with one or two external
3 * power supplies (AC/USB) connected to main and backup batteries, 3 * power supplies (AC/USB) connected to main and backup batteries,
4 * and optional builtin charger. 4 * and optional builtin charger.
5 * 5 *
6 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> 6 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as 9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation. 10 * published by the Free Software Foundation.
11 */ 11 */
12 12
13 #include <linux/module.h> 13 #include <linux/module.h>
14 #include <linux/platform_device.h> 14 #include <linux/platform_device.h>
15 #include <linux/interrupt.h> 15 #include <linux/interrupt.h>
16 #include <linux/power_supply.h> 16 #include <linux/power_supply.h>
17 #include <linux/pda_power.h> 17 #include <linux/pda_power.h>
18 #include <linux/timer.h> 18 #include <linux/timer.h>
19 #include <linux/jiffies.h> 19 #include <linux/jiffies.h>
20 20
21 static inline unsigned int get_irq_flags(struct resource *res) 21 static inline unsigned int get_irq_flags(struct resource *res)
22 { 22 {
23 unsigned int flags = IRQF_DISABLED | IRQF_SHARED; 23 unsigned int flags = IRQF_DISABLED | IRQF_SHARED;
24 24
25 flags |= res->flags & IRQF_TRIGGER_MASK; 25 flags |= res->flags & IRQF_TRIGGER_MASK;
26 26
27 return flags; 27 return flags;
28 } 28 }
29 29
30 static struct device *dev; 30 static struct device *dev;
31 static struct pda_power_pdata *pdata; 31 static struct pda_power_pdata *pdata;
32 static struct resource *ac_irq, *usb_irq; 32 static struct resource *ac_irq, *usb_irq;
33 static struct timer_list charger_timer; 33 static struct timer_list charger_timer;
34 static struct timer_list supply_timer; 34 static struct timer_list supply_timer;
35 35
36 static int pda_power_get_property(struct power_supply *psy, 36 static int pda_power_get_property(struct power_supply *psy,
37 enum power_supply_property psp, 37 enum power_supply_property psp,
38 union power_supply_propval *val) 38 union power_supply_propval *val)
39 { 39 {
40 switch (psp) { 40 switch (psp) {
41 case POWER_SUPPLY_PROP_ONLINE: 41 case POWER_SUPPLY_PROP_ONLINE:
42 if (psy->type == POWER_SUPPLY_TYPE_MAINS) 42 if (psy->type == POWER_SUPPLY_TYPE_MAINS)
43 val->intval = pdata->is_ac_online ? 43 val->intval = pdata->is_ac_online ?
44 pdata->is_ac_online() : 0; 44 pdata->is_ac_online() : 0;
45 else 45 else
46 val->intval = pdata->is_usb_online ? 46 val->intval = pdata->is_usb_online ?
47 pdata->is_usb_online() : 0; 47 pdata->is_usb_online() : 0;
48 break; 48 break;
49 default: 49 default:
50 return -EINVAL; 50 return -EINVAL;
51 } 51 }
52 return 0; 52 return 0;
53 } 53 }
54 54
55 static enum power_supply_property pda_power_props[] = { 55 static enum power_supply_property pda_power_props[] = {
56 POWER_SUPPLY_PROP_ONLINE, 56 POWER_SUPPLY_PROP_ONLINE,
57 }; 57 };
58 58
59 static char *pda_power_supplied_to[] = { 59 static char *pda_power_supplied_to[] = {
60 "main-battery", 60 "main-battery",
61 "backup-battery", 61 "backup-battery",
62 }; 62 };
63 63
64 static struct power_supply pda_power_supplies[] = { 64 static struct power_supply pda_power_supplies[] = {
65 { 65 {
66 .name = "ac", 66 .name = "ac",
67 .type = POWER_SUPPLY_TYPE_MAINS, 67 .type = POWER_SUPPLY_TYPE_MAINS,
68 .supplied_to = pda_power_supplied_to, 68 .supplied_to = pda_power_supplied_to,
69 .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), 69 .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
70 .properties = pda_power_props, 70 .properties = pda_power_props,
71 .num_properties = ARRAY_SIZE(pda_power_props), 71 .num_properties = ARRAY_SIZE(pda_power_props),
72 .get_property = pda_power_get_property, 72 .get_property = pda_power_get_property,
73 }, 73 },
74 { 74 {
75 .name = "usb", 75 .name = "usb",
76 .type = POWER_SUPPLY_TYPE_USB, 76 .type = POWER_SUPPLY_TYPE_USB,
77 .supplied_to = pda_power_supplied_to, 77 .supplied_to = pda_power_supplied_to,
78 .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), 78 .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
79 .properties = pda_power_props, 79 .properties = pda_power_props,
80 .num_properties = ARRAY_SIZE(pda_power_props), 80 .num_properties = ARRAY_SIZE(pda_power_props),
81 .get_property = pda_power_get_property, 81 .get_property = pda_power_get_property,
82 }, 82 },
83 }; 83 };
84 84
85 static void update_charger(void) 85 static void update_charger(void)
86 { 86 {
87 if (!pdata->set_charge) 87 if (!pdata->set_charge)
88 return; 88 return;
89 89
90 if (pdata->is_ac_online && pdata->is_ac_online()) { 90 if (pdata->is_ac_online && pdata->is_ac_online()) {
91 dev_dbg(dev, "charger on (AC)\n"); 91 dev_dbg(dev, "charger on (AC)\n");
92 pdata->set_charge(PDA_POWER_CHARGE_AC); 92 pdata->set_charge(PDA_POWER_CHARGE_AC);
93 } else if (pdata->is_usb_online && pdata->is_usb_online()) { 93 } else if (pdata->is_usb_online && pdata->is_usb_online()) {
94 dev_dbg(dev, "charger on (USB)\n"); 94 dev_dbg(dev, "charger on (USB)\n");
95 pdata->set_charge(PDA_POWER_CHARGE_USB); 95 pdata->set_charge(PDA_POWER_CHARGE_USB);
96 } else { 96 } else {
97 dev_dbg(dev, "charger off\n"); 97 dev_dbg(dev, "charger off\n");
98 pdata->set_charge(0); 98 pdata->set_charge(0);
99 } 99 }
100
101 return;
102 } 100 }
103 101
104 static void supply_timer_func(unsigned long power_supply_ptr) 102 static void supply_timer_func(unsigned long power_supply_ptr)
105 { 103 {
106 void *power_supply = (void *)power_supply_ptr; 104 void *power_supply = (void *)power_supply_ptr;
107 105
108 power_supply_changed(power_supply); 106 power_supply_changed(power_supply);
109 return;
110 } 107 }
111 108
112 static void charger_timer_func(unsigned long power_supply_ptr) 109 static void charger_timer_func(unsigned long power_supply_ptr)
113 { 110 {
114 update_charger(); 111 update_charger();
115 112
116 /* Okay, charger set. Now wait a bit before notifying supplicants, 113 /* Okay, charger set. Now wait a bit before notifying supplicants,
117 * charge power should stabilize. */ 114 * charge power should stabilize. */
118 supply_timer.data = power_supply_ptr; 115 supply_timer.data = power_supply_ptr;
119 mod_timer(&supply_timer, 116 mod_timer(&supply_timer,
120 jiffies + msecs_to_jiffies(pdata->wait_for_charger)); 117 jiffies + msecs_to_jiffies(pdata->wait_for_charger));
121 return;
122 } 118 }
123 119
124 static irqreturn_t power_changed_isr(int irq, void *power_supply) 120 static irqreturn_t power_changed_isr(int irq, void *power_supply)
125 { 121 {
126 /* Wait a bit before reading ac/usb line status and setting charger, 122 /* Wait a bit before reading ac/usb line status and setting charger,
127 * because ac/usb status readings may lag from irq. */ 123 * because ac/usb status readings may lag from irq. */
128 charger_timer.data = (unsigned long)power_supply; 124 charger_timer.data = (unsigned long)power_supply;
129 mod_timer(&charger_timer, 125 mod_timer(&charger_timer,
130 jiffies + msecs_to_jiffies(pdata->wait_for_status)); 126 jiffies + msecs_to_jiffies(pdata->wait_for_status));
131 return IRQ_HANDLED; 127 return IRQ_HANDLED;
132 } 128 }
133 129
134 static int pda_power_probe(struct platform_device *pdev) 130 static int pda_power_probe(struct platform_device *pdev)
135 { 131 {
136 int ret = 0; 132 int ret = 0;
137 133
138 dev = &pdev->dev; 134 dev = &pdev->dev;
139 135
140 if (pdev->id != -1) { 136 if (pdev->id != -1) {
141 dev_err(dev, "it's meaningless to register several " 137 dev_err(dev, "it's meaningless to register several "
142 "pda_powers; use id = -1\n"); 138 "pda_powers; use id = -1\n");
143 ret = -EINVAL; 139 ret = -EINVAL;
144 goto wrongid; 140 goto wrongid;
145 } 141 }
146 142
147 pdata = pdev->dev.platform_data; 143 pdata = pdev->dev.platform_data;
148 144
149 update_charger(); 145 update_charger();
150 146
151 if (!pdata->wait_for_status) 147 if (!pdata->wait_for_status)
152 pdata->wait_for_status = 500; 148 pdata->wait_for_status = 500;
153 149
154 if (!pdata->wait_for_charger) 150 if (!pdata->wait_for_charger)
155 pdata->wait_for_charger = 500; 151 pdata->wait_for_charger = 500;
156 152
157 setup_timer(&charger_timer, charger_timer_func, 0); 153 setup_timer(&charger_timer, charger_timer_func, 0);
158 setup_timer(&supply_timer, supply_timer_func, 0); 154 setup_timer(&supply_timer, supply_timer_func, 0);
159 155
160 ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); 156 ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
161 usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); 157 usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
162 if (!ac_irq && !usb_irq) { 158 if (!ac_irq && !usb_irq) {
163 dev_err(dev, "no ac/usb irq specified\n"); 159 dev_err(dev, "no ac/usb irq specified\n");
164 ret = -ENODEV; 160 ret = -ENODEV;
165 goto noirqs; 161 goto noirqs;
166 } 162 }
167 163
168 if (pdata->supplied_to) { 164 if (pdata->supplied_to) {
169 pda_power_supplies[0].supplied_to = pdata->supplied_to; 165 pda_power_supplies[0].supplied_to = pdata->supplied_to;
170 pda_power_supplies[1].supplied_to = pdata->supplied_to; 166 pda_power_supplies[1].supplied_to = pdata->supplied_to;
171 pda_power_supplies[0].num_supplicants = pdata->num_supplicants; 167 pda_power_supplies[0].num_supplicants = pdata->num_supplicants;
172 pda_power_supplies[1].num_supplicants = pdata->num_supplicants; 168 pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
173 } 169 }
174 170
175 ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]); 171 ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
176 if (ret) { 172 if (ret) {
177 dev_err(dev, "failed to register %s power supply\n", 173 dev_err(dev, "failed to register %s power supply\n",
178 pda_power_supplies[0].name); 174 pda_power_supplies[0].name);
179 goto supply0_failed; 175 goto supply0_failed;
180 } 176 }
181 177
182 ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]); 178 ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
183 if (ret) { 179 if (ret) {
184 dev_err(dev, "failed to register %s power supply\n", 180 dev_err(dev, "failed to register %s power supply\n",
185 pda_power_supplies[1].name); 181 pda_power_supplies[1].name);
186 goto supply1_failed; 182 goto supply1_failed;
187 } 183 }
188 184
189 if (ac_irq) { 185 if (ac_irq) {
190 ret = request_irq(ac_irq->start, power_changed_isr, 186 ret = request_irq(ac_irq->start, power_changed_isr,
191 get_irq_flags(ac_irq), ac_irq->name, 187 get_irq_flags(ac_irq), ac_irq->name,
192 &pda_power_supplies[0]); 188 &pda_power_supplies[0]);
193 if (ret) { 189 if (ret) {
194 dev_err(dev, "request ac irq failed\n"); 190 dev_err(dev, "request ac irq failed\n");
195 goto ac_irq_failed; 191 goto ac_irq_failed;
196 } 192 }
197 } 193 }
198 194
199 if (usb_irq) { 195 if (usb_irq) {
200 ret = request_irq(usb_irq->start, power_changed_isr, 196 ret = request_irq(usb_irq->start, power_changed_isr,
201 get_irq_flags(usb_irq), usb_irq->name, 197 get_irq_flags(usb_irq), usb_irq->name,
202 &pda_power_supplies[1]); 198 &pda_power_supplies[1]);
203 if (ret) { 199 if (ret) {
204 dev_err(dev, "request usb irq failed\n"); 200 dev_err(dev, "request usb irq failed\n");
205 goto usb_irq_failed; 201 goto usb_irq_failed;
206 } 202 }
207 } 203 }
208 204
209 goto success; 205 goto success;
210 206
211 usb_irq_failed: 207 usb_irq_failed:
212 if (ac_irq) 208 if (ac_irq)
213 free_irq(ac_irq->start, &pda_power_supplies[0]); 209 free_irq(ac_irq->start, &pda_power_supplies[0]);
214 ac_irq_failed: 210 ac_irq_failed:
215 power_supply_unregister(&pda_power_supplies[1]); 211 power_supply_unregister(&pda_power_supplies[1]);
216 supply1_failed: 212 supply1_failed:
217 power_supply_unregister(&pda_power_supplies[0]); 213 power_supply_unregister(&pda_power_supplies[0]);
218 supply0_failed: 214 supply0_failed:
219 noirqs: 215 noirqs:
220 wrongid: 216 wrongid:
221 success: 217 success:
222 return ret; 218 return ret;
223 } 219 }
224 220
225 static int pda_power_remove(struct platform_device *pdev) 221 static int pda_power_remove(struct platform_device *pdev)
226 { 222 {
227 if (usb_irq) 223 if (usb_irq)
228 free_irq(usb_irq->start, &pda_power_supplies[1]); 224 free_irq(usb_irq->start, &pda_power_supplies[1]);
229 if (ac_irq) 225 if (ac_irq)
230 free_irq(ac_irq->start, &pda_power_supplies[0]); 226 free_irq(ac_irq->start, &pda_power_supplies[0]);
231 del_timer_sync(&charger_timer); 227 del_timer_sync(&charger_timer);
232 del_timer_sync(&supply_timer); 228 del_timer_sync(&supply_timer);
233 power_supply_unregister(&pda_power_supplies[1]); 229 power_supply_unregister(&pda_power_supplies[1]);
234 power_supply_unregister(&pda_power_supplies[0]); 230 power_supply_unregister(&pda_power_supplies[0]);
235 return 0; 231 return 0;
236 } 232 }
237 233
238 static struct platform_driver pda_power_pdrv = { 234 static struct platform_driver pda_power_pdrv = {
239 .driver = { 235 .driver = {
240 .name = "pda-power", 236 .name = "pda-power",
241 }, 237 },
242 .probe = pda_power_probe, 238 .probe = pda_power_probe,
243 .remove = pda_power_remove, 239 .remove = pda_power_remove,
244 }; 240 };
245 241
246 static int __init pda_power_init(void) 242 static int __init pda_power_init(void)
247 { 243 {
248 return platform_driver_register(&pda_power_pdrv); 244 return platform_driver_register(&pda_power_pdrv);
249 } 245 }
250 246
251 static void __exit pda_power_exit(void) 247 static void __exit pda_power_exit(void)
252 { 248 {
253 platform_driver_unregister(&pda_power_pdrv); 249 platform_driver_unregister(&pda_power_pdrv);
254 return;
255 } 250 }
256 251
257 module_init(pda_power_init); 252 module_init(pda_power_init);
258 module_exit(pda_power_exit); 253 module_exit(pda_power_exit);
259 MODULE_LICENSE("GPL"); 254 MODULE_LICENSE("GPL");
260 MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>"); 255 MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");
261 256
drivers/power/pmu_battery.c
1 /* 1 /*
2 * Battery class driver for Apple PMU 2 * Battery class driver for Apple PMU
3 * 3 *
4 * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> 4 * Copyright © 2006 David Woodhouse <dwmw2@infradead.org>
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. 8 * published by the Free Software Foundation.
9 */ 9 */
10 10
11 #include <linux/module.h> 11 #include <linux/module.h>
12 #include <linux/platform_device.h> 12 #include <linux/platform_device.h>
13 #include <linux/err.h> 13 #include <linux/err.h>
14 #include <linux/power_supply.h> 14 #include <linux/power_supply.h>
15 #include <linux/adb.h> 15 #include <linux/adb.h>
16 #include <linux/pmu.h> 16 #include <linux/pmu.h>
17 17
18 static struct pmu_battery_dev { 18 static struct pmu_battery_dev {
19 struct power_supply bat; 19 struct power_supply bat;
20 struct pmu_battery_info *pbi; 20 struct pmu_battery_info *pbi;
21 char name[16]; 21 char name[16];
22 int propval; 22 int propval;
23 } *pbats[PMU_MAX_BATTERIES]; 23 } *pbats[PMU_MAX_BATTERIES];
24 24
25 #define to_pmu_battery_dev(x) container_of(x, struct pmu_battery_dev, bat) 25 #define to_pmu_battery_dev(x) container_of(x, struct pmu_battery_dev, bat)
26 26
27 /********************************************************************* 27 /*********************************************************************
28 * Power 28 * Power
29 *********************************************************************/ 29 *********************************************************************/
30 30
31 static int pmu_get_ac_prop(struct power_supply *psy, 31 static int pmu_get_ac_prop(struct power_supply *psy,
32 enum power_supply_property psp, 32 enum power_supply_property psp,
33 union power_supply_propval *val) 33 union power_supply_propval *val)
34 { 34 {
35 switch (psp) { 35 switch (psp) {
36 case POWER_SUPPLY_PROP_ONLINE: 36 case POWER_SUPPLY_PROP_ONLINE:
37 val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) || 37 val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) ||
38 (pmu_battery_count == 0); 38 (pmu_battery_count == 0);
39 break; 39 break;
40 default: 40 default:
41 return -EINVAL; 41 return -EINVAL;
42 } 42 }
43 43
44 return 0; 44 return 0;
45 } 45 }
46 46
47 static enum power_supply_property pmu_ac_props[] = { 47 static enum power_supply_property pmu_ac_props[] = {
48 POWER_SUPPLY_PROP_ONLINE, 48 POWER_SUPPLY_PROP_ONLINE,
49 }; 49 };
50 50
51 static struct power_supply pmu_ac = { 51 static struct power_supply pmu_ac = {
52 .name = "pmu-ac", 52 .name = "pmu-ac",
53 .type = POWER_SUPPLY_TYPE_MAINS, 53 .type = POWER_SUPPLY_TYPE_MAINS,
54 .properties = pmu_ac_props, 54 .properties = pmu_ac_props,
55 .num_properties = ARRAY_SIZE(pmu_ac_props), 55 .num_properties = ARRAY_SIZE(pmu_ac_props),
56 .get_property = pmu_get_ac_prop, 56 .get_property = pmu_get_ac_prop,
57 }; 57 };
58 58
59 /********************************************************************* 59 /*********************************************************************
60 * Battery properties 60 * Battery properties
61 *********************************************************************/ 61 *********************************************************************/
62 62
63 static char *pmu_batt_types[] = { 63 static char *pmu_batt_types[] = {
64 "Smart", "Comet", "Hooper", "Unknown" 64 "Smart", "Comet", "Hooper", "Unknown"
65 }; 65 };
66 66
67 static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi) 67 static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi)
68 { 68 {
69 switch (pbi->flags & PMU_BATT_TYPE_MASK) { 69 switch (pbi->flags & PMU_BATT_TYPE_MASK) {
70 case PMU_BATT_TYPE_SMART: 70 case PMU_BATT_TYPE_SMART:
71 return pmu_batt_types[0]; 71 return pmu_batt_types[0];
72 case PMU_BATT_TYPE_COMET: 72 case PMU_BATT_TYPE_COMET:
73 return pmu_batt_types[1]; 73 return pmu_batt_types[1];
74 case PMU_BATT_TYPE_HOOPER: 74 case PMU_BATT_TYPE_HOOPER:
75 return pmu_batt_types[2]; 75 return pmu_batt_types[2];
76 default: break; 76 default: break;
77 } 77 }
78 return pmu_batt_types[3]; 78 return pmu_batt_types[3];
79 } 79 }
80 80
81 static int pmu_bat_get_property(struct power_supply *psy, 81 static int pmu_bat_get_property(struct power_supply *psy,
82 enum power_supply_property psp, 82 enum power_supply_property psp,
83 union power_supply_propval *val) 83 union power_supply_propval *val)
84 { 84 {
85 struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy); 85 struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy);
86 struct pmu_battery_info *pbi = pbat->pbi; 86 struct pmu_battery_info *pbi = pbat->pbi;
87 87
88 switch (psp) { 88 switch (psp) {
89 case POWER_SUPPLY_PROP_STATUS: 89 case POWER_SUPPLY_PROP_STATUS:
90 if (pbi->flags & PMU_BATT_CHARGING) 90 if (pbi->flags & PMU_BATT_CHARGING)
91 val->intval = POWER_SUPPLY_STATUS_CHARGING; 91 val->intval = POWER_SUPPLY_STATUS_CHARGING;
92 else 92 else
93 val->intval = POWER_SUPPLY_STATUS_DISCHARGING; 93 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
94 break; 94 break;
95 case POWER_SUPPLY_PROP_PRESENT: 95 case POWER_SUPPLY_PROP_PRESENT:
96 val->intval = !!(pbi->flags & PMU_BATT_PRESENT); 96 val->intval = !!(pbi->flags & PMU_BATT_PRESENT);
97 break; 97 break;
98 case POWER_SUPPLY_PROP_MODEL_NAME: 98 case POWER_SUPPLY_PROP_MODEL_NAME:
99 val->strval = pmu_bat_get_model_name(pbi); 99 val->strval = pmu_bat_get_model_name(pbi);
100 break; 100 break;
101 case POWER_SUPPLY_PROP_ENERGY_AVG: 101 case POWER_SUPPLY_PROP_ENERGY_AVG:
102 val->intval = pbi->charge * 1000; /* mWh -> µWh */ 102 val->intval = pbi->charge * 1000; /* mWh -> µWh */
103 break; 103 break;
104 case POWER_SUPPLY_PROP_ENERGY_FULL: 104 case POWER_SUPPLY_PROP_ENERGY_FULL:
105 val->intval = pbi->max_charge * 1000; /* mWh -> µWh */ 105 val->intval = pbi->max_charge * 1000; /* mWh -> µWh */
106 break; 106 break;
107 case POWER_SUPPLY_PROP_CURRENT_AVG: 107 case POWER_SUPPLY_PROP_CURRENT_AVG:
108 val->intval = pbi->amperage * 1000; /* mA -> µA */ 108 val->intval = pbi->amperage * 1000; /* mA -> µA */
109 break; 109 break;
110 case POWER_SUPPLY_PROP_VOLTAGE_AVG: 110 case POWER_SUPPLY_PROP_VOLTAGE_AVG:
111 val->intval = pbi->voltage * 1000; /* mV -> µV */ 111 val->intval = pbi->voltage * 1000; /* mV -> µV */
112 break; 112 break;
113 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 113 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
114 val->intval = pbi->time_remaining; 114 val->intval = pbi->time_remaining;
115 break; 115 break;
116 default: 116 default:
117 return -EINVAL; 117 return -EINVAL;
118 } 118 }
119 119
120 return 0; 120 return 0;
121 } 121 }
122 122
123 static enum power_supply_property pmu_bat_props[] = { 123 static enum power_supply_property pmu_bat_props[] = {
124 POWER_SUPPLY_PROP_STATUS, 124 POWER_SUPPLY_PROP_STATUS,
125 POWER_SUPPLY_PROP_PRESENT, 125 POWER_SUPPLY_PROP_PRESENT,
126 POWER_SUPPLY_PROP_MODEL_NAME, 126 POWER_SUPPLY_PROP_MODEL_NAME,
127 POWER_SUPPLY_PROP_ENERGY_AVG, 127 POWER_SUPPLY_PROP_ENERGY_AVG,
128 POWER_SUPPLY_PROP_ENERGY_FULL, 128 POWER_SUPPLY_PROP_ENERGY_FULL,
129 POWER_SUPPLY_PROP_CURRENT_AVG, 129 POWER_SUPPLY_PROP_CURRENT_AVG,
130 POWER_SUPPLY_PROP_VOLTAGE_AVG, 130 POWER_SUPPLY_PROP_VOLTAGE_AVG,
131 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 131 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
132 }; 132 };
133 133
134 /********************************************************************* 134 /*********************************************************************
135 * Initialisation 135 * Initialisation
136 *********************************************************************/ 136 *********************************************************************/
137 137
138 static struct platform_device *bat_pdev; 138 static struct platform_device *bat_pdev;
139 139
140 static int __init pmu_bat_init(void) 140 static int __init pmu_bat_init(void)
141 { 141 {
142 int ret; 142 int ret;
143 int i; 143 int i;
144 144
145 bat_pdev = platform_device_register_simple("pmu-battery", 145 bat_pdev = platform_device_register_simple("pmu-battery",
146 0, NULL, 0); 146 0, NULL, 0);
147 if (IS_ERR(bat_pdev)) { 147 if (IS_ERR(bat_pdev)) {
148 ret = PTR_ERR(bat_pdev); 148 ret = PTR_ERR(bat_pdev);
149 goto pdev_register_failed; 149 goto pdev_register_failed;
150 } 150 }
151 151
152 ret = power_supply_register(&bat_pdev->dev, &pmu_ac); 152 ret = power_supply_register(&bat_pdev->dev, &pmu_ac);
153 if (ret) 153 if (ret)
154 goto ac_register_failed; 154 goto ac_register_failed;
155 155
156 for (i = 0; i < pmu_battery_count; i++) { 156 for (i = 0; i < pmu_battery_count; i++) {
157 struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat), 157 struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat),
158 GFP_KERNEL); 158 GFP_KERNEL);
159 if (!pbat) 159 if (!pbat)
160 break; 160 break;
161 161
162 sprintf(pbat->name, "PMU battery %d", i); 162 sprintf(pbat->name, "PMU battery %d", i);
163 pbat->bat.name = pbat->name; 163 pbat->bat.name = pbat->name;
164 pbat->bat.properties = pmu_bat_props; 164 pbat->bat.properties = pmu_bat_props;
165 pbat->bat.num_properties = ARRAY_SIZE(pmu_bat_props); 165 pbat->bat.num_properties = ARRAY_SIZE(pmu_bat_props);
166 pbat->bat.get_property = pmu_bat_get_property; 166 pbat->bat.get_property = pmu_bat_get_property;
167 pbat->pbi = &pmu_batteries[i]; 167 pbat->pbi = &pmu_batteries[i];
168 168
169 ret = power_supply_register(&bat_pdev->dev, &pbat->bat); 169 ret = power_supply_register(&bat_pdev->dev, &pbat->bat);
170 if (ret) { 170 if (ret) {
171 kfree(pbat); 171 kfree(pbat);
172 goto battery_register_failed; 172 goto battery_register_failed;
173 } 173 }
174 pbats[i] = pbat; 174 pbats[i] = pbat;
175 } 175 }
176 176
177 goto success; 177 goto success;
178 178
179 battery_register_failed: 179 battery_register_failed:
180 while (i--) { 180 while (i--) {
181 if (!pbats[i]) 181 if (!pbats[i])
182 continue; 182 continue;
183 power_supply_unregister(&pbats[i]->bat); 183 power_supply_unregister(&pbats[i]->bat);
184 kfree(pbats[i]); 184 kfree(pbats[i]);
185 } 185 }
186 power_supply_unregister(&pmu_ac); 186 power_supply_unregister(&pmu_ac);
187 ac_register_failed: 187 ac_register_failed:
188 platform_device_unregister(bat_pdev); 188 platform_device_unregister(bat_pdev);
189 pdev_register_failed: 189 pdev_register_failed:
190 success: 190 success:
191 return ret; 191 return ret;
192 } 192 }
193 193
194 static void __exit pmu_bat_exit(void) 194 static void __exit pmu_bat_exit(void)
195 { 195 {
196 int i; 196 int i;
197 197
198 for (i = 0; i < PMU_MAX_BATTERIES; i++) { 198 for (i = 0; i < PMU_MAX_BATTERIES; i++) {
199 if (!pbats[i]) 199 if (!pbats[i])
200 continue; 200 continue;
201 power_supply_unregister(&pbats[i]->bat); 201 power_supply_unregister(&pbats[i]->bat);
202 kfree(pbats[i]); 202 kfree(pbats[i]);
203 } 203 }
204 power_supply_unregister(&pmu_ac); 204 power_supply_unregister(&pmu_ac);
205 platform_device_unregister(bat_pdev); 205 platform_device_unregister(bat_pdev);
206
207 return;
208 } 206 }
209 207
210 module_init(pmu_bat_init); 208 module_init(pmu_bat_init);
211 module_exit(pmu_bat_exit); 209 module_exit(pmu_bat_exit);
212 210
213 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 211 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
214 MODULE_LICENSE("GPL"); 212 MODULE_LICENSE("GPL");
215 MODULE_DESCRIPTION("PMU battery driver"); 213 MODULE_DESCRIPTION("PMU battery driver");
216 214
drivers/power/power_supply_core.c
1 /* 1 /*
2 * Universal power supply monitor class 2 * Universal power supply monitor class
3 * 3 *
4 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> 4 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
5 * Copyright © 2004 Szabolcs Gyurko 5 * Copyright © 2004 Szabolcs Gyurko
6 * Copyright © 2003 Ian Molton <spyro@f2s.com> 6 * Copyright © 2003 Ian Molton <spyro@f2s.com>
7 * 7 *
8 * Modified: 2004, Oct Szabolcs Gyurko 8 * Modified: 2004, Oct Szabolcs Gyurko
9 * 9 *
10 * You may use this code as per GPL version 2 10 * You may use this code as per GPL version 2
11 */ 11 */
12 12
13 #include <linux/module.h> 13 #include <linux/module.h>
14 #include <linux/types.h> 14 #include <linux/types.h>
15 #include <linux/init.h> 15 #include <linux/init.h>
16 #include <linux/device.h> 16 #include <linux/device.h>
17 #include <linux/err.h> 17 #include <linux/err.h>
18 #include <linux/power_supply.h> 18 #include <linux/power_supply.h>
19 #include "power_supply.h" 19 #include "power_supply.h"
20 20
21 struct class *power_supply_class; 21 struct class *power_supply_class;
22 22
23 static void power_supply_changed_work(struct work_struct *work) 23 static void power_supply_changed_work(struct work_struct *work)
24 { 24 {
25 struct power_supply *psy = container_of(work, struct power_supply, 25 struct power_supply *psy = container_of(work, struct power_supply,
26 changed_work); 26 changed_work);
27 int i; 27 int i;
28 28
29 dev_dbg(psy->dev, "%s\n", __FUNCTION__); 29 dev_dbg(psy->dev, "%s\n", __FUNCTION__);
30 30
31 for (i = 0; i < psy->num_supplicants; i++) { 31 for (i = 0; i < psy->num_supplicants; i++) {
32 struct device *dev; 32 struct device *dev;
33 33
34 down(&power_supply_class->sem); 34 down(&power_supply_class->sem);
35 list_for_each_entry(dev, &power_supply_class->devices, node) { 35 list_for_each_entry(dev, &power_supply_class->devices, node) {
36 struct power_supply *pst = dev_get_drvdata(dev); 36 struct power_supply *pst = dev_get_drvdata(dev);
37 37
38 if (!strcmp(psy->supplied_to[i], pst->name)) { 38 if (!strcmp(psy->supplied_to[i], pst->name)) {
39 if (pst->external_power_changed) 39 if (pst->external_power_changed)
40 pst->external_power_changed(pst); 40 pst->external_power_changed(pst);
41 } 41 }
42 } 42 }
43 up(&power_supply_class->sem); 43 up(&power_supply_class->sem);
44 } 44 }
45 45
46 power_supply_update_leds(psy); 46 power_supply_update_leds(psy);
47 47
48 kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); 48 kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
49
50 return;
51 } 49 }
52 50
53 void power_supply_changed(struct power_supply *psy) 51 void power_supply_changed(struct power_supply *psy)
54 { 52 {
55 dev_dbg(psy->dev, "%s\n", __FUNCTION__); 53 dev_dbg(psy->dev, "%s\n", __FUNCTION__);
56 54
57 schedule_work(&psy->changed_work); 55 schedule_work(&psy->changed_work);
58
59 return;
60 } 56 }
61 57
62 int power_supply_am_i_supplied(struct power_supply *psy) 58 int power_supply_am_i_supplied(struct power_supply *psy)
63 { 59 {
64 union power_supply_propval ret = {0,}; 60 union power_supply_propval ret = {0,};
65 struct device *dev; 61 struct device *dev;
66 62
67 down(&power_supply_class->sem); 63 down(&power_supply_class->sem);
68 list_for_each_entry(dev, &power_supply_class->devices, node) { 64 list_for_each_entry(dev, &power_supply_class->devices, node) {
69 struct power_supply *epsy = dev_get_drvdata(dev); 65 struct power_supply *epsy = dev_get_drvdata(dev);
70 int i; 66 int i;
71 67
72 for (i = 0; i < epsy->num_supplicants; i++) { 68 for (i = 0; i < epsy->num_supplicants; i++) {
73 if (!strcmp(epsy->supplied_to[i], psy->name)) { 69 if (!strcmp(epsy->supplied_to[i], psy->name)) {
74 if (epsy->get_property(epsy, 70 if (epsy->get_property(epsy,
75 POWER_SUPPLY_PROP_ONLINE, &ret)) 71 POWER_SUPPLY_PROP_ONLINE, &ret))
76 continue; 72 continue;
77 if (ret.intval) 73 if (ret.intval)
78 goto out; 74 goto out;
79 } 75 }
80 } 76 }
81 } 77 }
82 out: 78 out:
83 up(&power_supply_class->sem); 79 up(&power_supply_class->sem);
84 80
85 dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval); 81 dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval);
86 82
87 return ret.intval; 83 return ret.intval;
88 } 84 }
89 85
90 int power_supply_register(struct device *parent, struct power_supply *psy) 86 int power_supply_register(struct device *parent, struct power_supply *psy)
91 { 87 {
92 int rc = 0; 88 int rc = 0;
93 89
94 psy->dev = device_create(power_supply_class, parent, 0, 90 psy->dev = device_create(power_supply_class, parent, 0,
95 "%s", psy->name); 91 "%s", psy->name);
96 if (IS_ERR(psy->dev)) { 92 if (IS_ERR(psy->dev)) {
97 rc = PTR_ERR(psy->dev); 93 rc = PTR_ERR(psy->dev);
98 goto dev_create_failed; 94 goto dev_create_failed;
99 } 95 }
100 96
101 dev_set_drvdata(psy->dev, psy); 97 dev_set_drvdata(psy->dev, psy);
102 98
103 INIT_WORK(&psy->changed_work, power_supply_changed_work); 99 INIT_WORK(&psy->changed_work, power_supply_changed_work);
104 100
105 rc = power_supply_create_attrs(psy); 101 rc = power_supply_create_attrs(psy);
106 if (rc) 102 if (rc)
107 goto create_attrs_failed; 103 goto create_attrs_failed;
108 104
109 rc = power_supply_create_triggers(psy); 105 rc = power_supply_create_triggers(psy);
110 if (rc) 106 if (rc)
111 goto create_triggers_failed; 107 goto create_triggers_failed;
112 108
113 power_supply_changed(psy); 109 power_supply_changed(psy);
114 110
115 goto success; 111 goto success;
116 112
117 create_triggers_failed: 113 create_triggers_failed:
118 power_supply_remove_attrs(psy); 114 power_supply_remove_attrs(psy);
119 create_attrs_failed: 115 create_attrs_failed:
120 device_unregister(psy->dev); 116 device_unregister(psy->dev);
121 dev_create_failed: 117 dev_create_failed:
122 success: 118 success:
123 return rc; 119 return rc;
124 } 120 }
125 121
126 void power_supply_unregister(struct power_supply *psy) 122 void power_supply_unregister(struct power_supply *psy)
127 { 123 {
128 flush_scheduled_work(); 124 flush_scheduled_work();
129 power_supply_remove_triggers(psy); 125 power_supply_remove_triggers(psy);
130 power_supply_remove_attrs(psy); 126 power_supply_remove_attrs(psy);
131 device_unregister(psy->dev); 127 device_unregister(psy->dev);
132 return;
133 } 128 }
134 129
135 static int __init power_supply_class_init(void) 130 static int __init power_supply_class_init(void)
136 { 131 {
137 power_supply_class = class_create(THIS_MODULE, "power_supply"); 132 power_supply_class = class_create(THIS_MODULE, "power_supply");
138 133
139 if (IS_ERR(power_supply_class)) 134 if (IS_ERR(power_supply_class))
140 return PTR_ERR(power_supply_class); 135 return PTR_ERR(power_supply_class);
141 136
142 power_supply_class->dev_uevent = power_supply_uevent; 137 power_supply_class->dev_uevent = power_supply_uevent;
143 138
144 return 0; 139 return 0;
145 } 140 }
146 141
147 static void __exit power_supply_class_exit(void) 142 static void __exit power_supply_class_exit(void)
148 { 143 {
149 class_destroy(power_supply_class); 144 class_destroy(power_supply_class);
150 return;
151 } 145 }
152 146
153 EXPORT_SYMBOL_GPL(power_supply_changed); 147 EXPORT_SYMBOL_GPL(power_supply_changed);
154 EXPORT_SYMBOL_GPL(power_supply_am_i_supplied); 148 EXPORT_SYMBOL_GPL(power_supply_am_i_supplied);
155 EXPORT_SYMBOL_GPL(power_supply_register); 149 EXPORT_SYMBOL_GPL(power_supply_register);
156 EXPORT_SYMBOL_GPL(power_supply_unregister); 150 EXPORT_SYMBOL_GPL(power_supply_unregister);
157 151
158 /* exported for the APM Power driver, APM emulation */ 152 /* exported for the APM Power driver, APM emulation */
159 EXPORT_SYMBOL_GPL(power_supply_class); 153 EXPORT_SYMBOL_GPL(power_supply_class);
160 154
161 subsys_initcall(power_supply_class_init); 155 subsys_initcall(power_supply_class_init);
162 module_exit(power_supply_class_exit); 156 module_exit(power_supply_class_exit);
163 157
164 MODULE_DESCRIPTION("Universal power supply monitor class"); 158 MODULE_DESCRIPTION("Universal power supply monitor class");
165 MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, " 159 MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, "
166 "Szabolcs Gyurko, " 160 "Szabolcs Gyurko, "
167 "Anton Vorontsov <cbou@mail.ru>"); 161 "Anton Vorontsov <cbou@mail.ru>");
168 MODULE_LICENSE("GPL"); 162 MODULE_LICENSE("GPL");
169 163
drivers/power/power_supply_leds.c
1 /* 1 /*
2 * LEDs triggers for power supply class 2 * LEDs triggers for power supply class
3 * 3 *
4 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> 4 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
5 * Copyright © 2004 Szabolcs Gyurko 5 * Copyright © 2004 Szabolcs Gyurko
6 * Copyright © 2003 Ian Molton <spyro@f2s.com> 6 * Copyright © 2003 Ian Molton <spyro@f2s.com>
7 * 7 *
8 * Modified: 2004, Oct Szabolcs Gyurko 8 * Modified: 2004, Oct Szabolcs Gyurko
9 * 9 *
10 * You may use this code as per GPL version 2 10 * You may use this code as per GPL version 2
11 */ 11 */
12 12
13 #include <linux/power_supply.h> 13 #include <linux/power_supply.h>
14 14
15 /* Battery specific LEDs triggers. */ 15 /* Battery specific LEDs triggers. */
16 16
17 static void power_supply_update_bat_leds(struct power_supply *psy) 17 static void power_supply_update_bat_leds(struct power_supply *psy)
18 { 18 {
19 union power_supply_propval status; 19 union power_supply_propval status;
20 20
21 if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) 21 if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
22 return; 22 return;
23 23
24 dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval); 24 dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval);
25 25
26 switch (status.intval) { 26 switch (status.intval) {
27 case POWER_SUPPLY_STATUS_FULL: 27 case POWER_SUPPLY_STATUS_FULL:
28 led_trigger_event(psy->charging_full_trig, LED_FULL); 28 led_trigger_event(psy->charging_full_trig, LED_FULL);
29 led_trigger_event(psy->charging_trig, LED_OFF); 29 led_trigger_event(psy->charging_trig, LED_OFF);
30 led_trigger_event(psy->full_trig, LED_FULL); 30 led_trigger_event(psy->full_trig, LED_FULL);
31 break; 31 break;
32 case POWER_SUPPLY_STATUS_CHARGING: 32 case POWER_SUPPLY_STATUS_CHARGING:
33 led_trigger_event(psy->charging_full_trig, LED_FULL); 33 led_trigger_event(psy->charging_full_trig, LED_FULL);
34 led_trigger_event(psy->charging_trig, LED_FULL); 34 led_trigger_event(psy->charging_trig, LED_FULL);
35 led_trigger_event(psy->full_trig, LED_OFF); 35 led_trigger_event(psy->full_trig, LED_OFF);
36 break; 36 break;
37 default: 37 default:
38 led_trigger_event(psy->charging_full_trig, LED_OFF); 38 led_trigger_event(psy->charging_full_trig, LED_OFF);
39 led_trigger_event(psy->charging_trig, LED_OFF); 39 led_trigger_event(psy->charging_trig, LED_OFF);
40 led_trigger_event(psy->full_trig, LED_OFF); 40 led_trigger_event(psy->full_trig, LED_OFF);
41 break; 41 break;
42 } 42 }
43
44 return;
45 } 43 }
46 44
47 static int power_supply_create_bat_triggers(struct power_supply *psy) 45 static int power_supply_create_bat_triggers(struct power_supply *psy)
48 { 46 {
49 int rc = 0; 47 int rc = 0;
50 48
51 psy->charging_full_trig_name = kmalloc(strlen(psy->name) + 49 psy->charging_full_trig_name = kmalloc(strlen(psy->name) +
52 sizeof("-charging-or-full"), GFP_KERNEL); 50 sizeof("-charging-or-full"), GFP_KERNEL);
53 if (!psy->charging_full_trig_name) 51 if (!psy->charging_full_trig_name)
54 goto charging_full_failed; 52 goto charging_full_failed;
55 53
56 psy->charging_trig_name = kmalloc(strlen(psy->name) + 54 psy->charging_trig_name = kmalloc(strlen(psy->name) +
57 sizeof("-charging"), GFP_KERNEL); 55 sizeof("-charging"), GFP_KERNEL);
58 if (!psy->charging_trig_name) 56 if (!psy->charging_trig_name)
59 goto charging_failed; 57 goto charging_failed;
60 58
61 psy->full_trig_name = kmalloc(strlen(psy->name) + 59 psy->full_trig_name = kmalloc(strlen(psy->name) +
62 sizeof("-full"), GFP_KERNEL); 60 sizeof("-full"), GFP_KERNEL);
63 if (!psy->full_trig_name) 61 if (!psy->full_trig_name)
64 goto full_failed; 62 goto full_failed;
65 63
66 strcpy(psy->charging_full_trig_name, psy->name); 64 strcpy(psy->charging_full_trig_name, psy->name);
67 strcat(psy->charging_full_trig_name, "-charging-or-full"); 65 strcat(psy->charging_full_trig_name, "-charging-or-full");
68 strcpy(psy->charging_trig_name, psy->name); 66 strcpy(psy->charging_trig_name, psy->name);
69 strcat(psy->charging_trig_name, "-charging"); 67 strcat(psy->charging_trig_name, "-charging");
70 strcpy(psy->full_trig_name, psy->name); 68 strcpy(psy->full_trig_name, psy->name);
71 strcat(psy->full_trig_name, "-full"); 69 strcat(psy->full_trig_name, "-full");
72 70
73 led_trigger_register_simple(psy->charging_full_trig_name, 71 led_trigger_register_simple(psy->charging_full_trig_name,
74 &psy->charging_full_trig); 72 &psy->charging_full_trig);
75 led_trigger_register_simple(psy->charging_trig_name, 73 led_trigger_register_simple(psy->charging_trig_name,
76 &psy->charging_trig); 74 &psy->charging_trig);
77 led_trigger_register_simple(psy->full_trig_name, 75 led_trigger_register_simple(psy->full_trig_name,
78 &psy->full_trig); 76 &psy->full_trig);
79 77
80 goto success; 78 goto success;
81 79
82 full_failed: 80 full_failed:
83 kfree(psy->charging_trig_name); 81 kfree(psy->charging_trig_name);
84 charging_failed: 82 charging_failed:
85 kfree(psy->charging_full_trig_name); 83 kfree(psy->charging_full_trig_name);
86 charging_full_failed: 84 charging_full_failed:
87 rc = -ENOMEM; 85 rc = -ENOMEM;
88 success: 86 success:
89 return rc; 87 return rc;
90 } 88 }
91 89
92 static void power_supply_remove_bat_triggers(struct power_supply *psy) 90 static void power_supply_remove_bat_triggers(struct power_supply *psy)
93 { 91 {
94 led_trigger_unregister_simple(psy->charging_full_trig); 92 led_trigger_unregister_simple(psy->charging_full_trig);
95 led_trigger_unregister_simple(psy->charging_trig); 93 led_trigger_unregister_simple(psy->charging_trig);
96 led_trigger_unregister_simple(psy->full_trig); 94 led_trigger_unregister_simple(psy->full_trig);
97 kfree(psy->full_trig_name); 95 kfree(psy->full_trig_name);
98 kfree(psy->charging_trig_name); 96 kfree(psy->charging_trig_name);
99 kfree(psy->charging_full_trig_name); 97 kfree(psy->charging_full_trig_name);
100 return;
101 } 98 }
102 99
103 /* Generated power specific LEDs triggers. */ 100 /* Generated power specific LEDs triggers. */
104 101
105 static void power_supply_update_gen_leds(struct power_supply *psy) 102 static void power_supply_update_gen_leds(struct power_supply *psy)
106 { 103 {
107 union power_supply_propval online; 104 union power_supply_propval online;
108 105
109 if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online)) 106 if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
110 return; 107 return;
111 108
112 dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval); 109 dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval);
113 110
114 if (online.intval) 111 if (online.intval)
115 led_trigger_event(psy->online_trig, LED_FULL); 112 led_trigger_event(psy->online_trig, LED_FULL);
116 else 113 else
117 led_trigger_event(psy->online_trig, LED_OFF); 114 led_trigger_event(psy->online_trig, LED_OFF);
118
119 return;
120 } 115 }
121 116
122 static int power_supply_create_gen_triggers(struct power_supply *psy) 117 static int power_supply_create_gen_triggers(struct power_supply *psy)
123 { 118 {
124 int rc = 0; 119 int rc = 0;
125 120
126 psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"), 121 psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"),
127 GFP_KERNEL); 122 GFP_KERNEL);
128 if (!psy->online_trig_name) 123 if (!psy->online_trig_name)
129 goto online_failed; 124 goto online_failed;
130 125
131 strcpy(psy->online_trig_name, psy->name); 126 strcpy(psy->online_trig_name, psy->name);
132 strcat(psy->online_trig_name, "-online"); 127 strcat(psy->online_trig_name, "-online");
133 128
134 led_trigger_register_simple(psy->online_trig_name, &psy->online_trig); 129 led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
135 130
136 goto success; 131 goto success;
137 132
138 online_failed: 133 online_failed:
139 rc = -ENOMEM; 134 rc = -ENOMEM;
140 success: 135 success:
141 return rc; 136 return rc;
142 } 137 }
143 138
144 static void power_supply_remove_gen_triggers(struct power_supply *psy) 139 static void power_supply_remove_gen_triggers(struct power_supply *psy)
145 { 140 {
146 led_trigger_unregister_simple(psy->online_trig); 141 led_trigger_unregister_simple(psy->online_trig);
147 kfree(psy->online_trig_name); 142 kfree(psy->online_trig_name);
148 return;
149 } 143 }
150 144
151 /* Choice what triggers to create&update. */ 145 /* Choice what triggers to create&update. */
152 146
153 void power_supply_update_leds(struct power_supply *psy) 147 void power_supply_update_leds(struct power_supply *psy)
154 { 148 {
155 if (psy->type == POWER_SUPPLY_TYPE_BATTERY) 149 if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
156 power_supply_update_bat_leds(psy); 150 power_supply_update_bat_leds(psy);
157 else 151 else
158 power_supply_update_gen_leds(psy); 152 power_supply_update_gen_leds(psy);
159 return;
160 } 153 }
161 154
162 int power_supply_create_triggers(struct power_supply *psy) 155 int power_supply_create_triggers(struct power_supply *psy)
163 { 156 {
164 if (psy->type == POWER_SUPPLY_TYPE_BATTERY) 157 if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
165 return power_supply_create_bat_triggers(psy); 158 return power_supply_create_bat_triggers(psy);
166 return power_supply_create_gen_triggers(psy); 159 return power_supply_create_gen_triggers(psy);
167 } 160 }
168 161
169 void power_supply_remove_triggers(struct power_supply *psy) 162 void power_supply_remove_triggers(struct power_supply *psy)
170 { 163 {
171 if (psy->type == POWER_SUPPLY_TYPE_BATTERY) 164 if (psy->type == POWER_SUPPLY_TYPE_BATTERY)
172 power_supply_remove_bat_triggers(psy); 165 power_supply_remove_bat_triggers(psy);
173 else 166 else
174 power_supply_remove_gen_triggers(psy); 167 power_supply_remove_gen_triggers(psy);
175 return;
176 } 168 }
177 169
drivers/power/power_supply_sysfs.c
1 /* 1 /*
2 * Sysfs interface for the universal power supply monitor class 2 * Sysfs interface for the universal power supply monitor class
3 * 3 *
4 * Copyright © 2007 David Woodhouse <dwmw2@infradead.org> 4 * Copyright © 2007 David Woodhouse <dwmw2@infradead.org>
5 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> 5 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
6 * Copyright © 2004 Szabolcs Gyurko 6 * Copyright © 2004 Szabolcs Gyurko
7 * Copyright © 2003 Ian Molton <spyro@f2s.com> 7 * Copyright © 2003 Ian Molton <spyro@f2s.com>
8 * 8 *
9 * Modified: 2004, Oct Szabolcs Gyurko 9 * Modified: 2004, Oct Szabolcs Gyurko
10 * 10 *
11 * You may use this code as per GPL version 2 11 * You may use this code as per GPL version 2
12 */ 12 */
13 13
14 #include <linux/ctype.h> 14 #include <linux/ctype.h>
15 #include <linux/power_supply.h> 15 #include <linux/power_supply.h>
16 16
17 /* 17 /*
18 * This is because the name "current" breaks the device attr macro. 18 * This is because the name "current" breaks the device attr macro.
19 * The "current" word resolves to "(get_current())" so instead of 19 * The "current" word resolves to "(get_current())" so instead of
20 * "current" "(get_current())" appears in the sysfs. 20 * "current" "(get_current())" appears in the sysfs.
21 * 21 *
22 * The source of this definition is the device.h which calls __ATTR 22 * The source of this definition is the device.h which calls __ATTR
23 * macro in sysfs.h which calls the __stringify macro. 23 * macro in sysfs.h which calls the __stringify macro.
24 * 24 *
25 * Only modification that the name is not tried to be resolved 25 * Only modification that the name is not tried to be resolved
26 * (as a macro let's say). 26 * (as a macro let's say).
27 */ 27 */
28 28
29 #define POWER_SUPPLY_ATTR(_name) \ 29 #define POWER_SUPPLY_ATTR(_name) \
30 { \ 30 { \
31 .attr = { .name = #_name, .mode = 0444, .owner = THIS_MODULE }, \ 31 .attr = { .name = #_name, .mode = 0444, .owner = THIS_MODULE }, \
32 .show = power_supply_show_property, \ 32 .show = power_supply_show_property, \
33 .store = NULL, \ 33 .store = NULL, \
34 } 34 }
35 35
36 static struct device_attribute power_supply_attrs[]; 36 static struct device_attribute power_supply_attrs[];
37 37
38 static ssize_t power_supply_show_property(struct device *dev, 38 static ssize_t power_supply_show_property(struct device *dev,
39 struct device_attribute *attr, 39 struct device_attribute *attr,
40 char *buf) { 40 char *buf) {
41 static char *status_text[] = { 41 static char *status_text[] = {
42 "Unknown", "Charging", "Discharging", "Not charging", "Full" 42 "Unknown", "Charging", "Discharging", "Not charging", "Full"
43 }; 43 };
44 static char *health_text[] = { 44 static char *health_text[] = {
45 "Unknown", "Good", "Overheat", "Dead", "Over voltage", 45 "Unknown", "Good", "Overheat", "Dead", "Over voltage",
46 "Unspecified failure" 46 "Unspecified failure"
47 }; 47 };
48 static char *technology_text[] = { 48 static char *technology_text[] = {
49 "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd" 49 "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd"
50 }; 50 };
51 static char *capacity_level_text[] = { 51 static char *capacity_level_text[] = {
52 "Unknown", "Critical", "Low", "Normal", "High", "Full" 52 "Unknown", "Critical", "Low", "Normal", "High", "Full"
53 }; 53 };
54 ssize_t ret; 54 ssize_t ret;
55 struct power_supply *psy = dev_get_drvdata(dev); 55 struct power_supply *psy = dev_get_drvdata(dev);
56 const ptrdiff_t off = attr - power_supply_attrs; 56 const ptrdiff_t off = attr - power_supply_attrs;
57 union power_supply_propval value; 57 union power_supply_propval value;
58 58
59 ret = psy->get_property(psy, off, &value); 59 ret = psy->get_property(psy, off, &value);
60 60
61 if (ret < 0) { 61 if (ret < 0) {
62 if (ret != -ENODEV) 62 if (ret != -ENODEV)
63 dev_err(dev, "driver failed to report `%s' property\n", 63 dev_err(dev, "driver failed to report `%s' property\n",
64 attr->attr.name); 64 attr->attr.name);
65 return ret; 65 return ret;
66 } 66 }
67 67
68 if (off == POWER_SUPPLY_PROP_STATUS) 68 if (off == POWER_SUPPLY_PROP_STATUS)
69 return sprintf(buf, "%s\n", status_text[value.intval]); 69 return sprintf(buf, "%s\n", status_text[value.intval]);
70 else if (off == POWER_SUPPLY_PROP_HEALTH) 70 else if (off == POWER_SUPPLY_PROP_HEALTH)
71 return sprintf(buf, "%s\n", health_text[value.intval]); 71 return sprintf(buf, "%s\n", health_text[value.intval]);
72 else if (off == POWER_SUPPLY_PROP_TECHNOLOGY) 72 else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
73 return sprintf(buf, "%s\n", technology_text[value.intval]); 73 return sprintf(buf, "%s\n", technology_text[value.intval]);
74 else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL) 74 else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
75 return sprintf(buf, "%s\n", 75 return sprintf(buf, "%s\n",
76 capacity_level_text[value.intval]); 76 capacity_level_text[value.intval]);
77 else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) 77 else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
78 return sprintf(buf, "%s\n", value.strval); 78 return sprintf(buf, "%s\n", value.strval);
79 79
80 return sprintf(buf, "%d\n", value.intval); 80 return sprintf(buf, "%d\n", value.intval);
81 } 81 }
82 82
83 /* Must be in the same order as POWER_SUPPLY_PROP_* */ 83 /* Must be in the same order as POWER_SUPPLY_PROP_* */
84 static struct device_attribute power_supply_attrs[] = { 84 static struct device_attribute power_supply_attrs[] = {
85 /* Properties of type `int' */ 85 /* Properties of type `int' */
86 POWER_SUPPLY_ATTR(status), 86 POWER_SUPPLY_ATTR(status),
87 POWER_SUPPLY_ATTR(health), 87 POWER_SUPPLY_ATTR(health),
88 POWER_SUPPLY_ATTR(present), 88 POWER_SUPPLY_ATTR(present),
89 POWER_SUPPLY_ATTR(online), 89 POWER_SUPPLY_ATTR(online),
90 POWER_SUPPLY_ATTR(technology), 90 POWER_SUPPLY_ATTR(technology),
91 POWER_SUPPLY_ATTR(voltage_max_design), 91 POWER_SUPPLY_ATTR(voltage_max_design),
92 POWER_SUPPLY_ATTR(voltage_min_design), 92 POWER_SUPPLY_ATTR(voltage_min_design),
93 POWER_SUPPLY_ATTR(voltage_now), 93 POWER_SUPPLY_ATTR(voltage_now),
94 POWER_SUPPLY_ATTR(voltage_avg), 94 POWER_SUPPLY_ATTR(voltage_avg),
95 POWER_SUPPLY_ATTR(current_now), 95 POWER_SUPPLY_ATTR(current_now),
96 POWER_SUPPLY_ATTR(current_avg), 96 POWER_SUPPLY_ATTR(current_avg),
97 POWER_SUPPLY_ATTR(charge_full_design), 97 POWER_SUPPLY_ATTR(charge_full_design),
98 POWER_SUPPLY_ATTR(charge_empty_design), 98 POWER_SUPPLY_ATTR(charge_empty_design),
99 POWER_SUPPLY_ATTR(charge_full), 99 POWER_SUPPLY_ATTR(charge_full),
100 POWER_SUPPLY_ATTR(charge_empty), 100 POWER_SUPPLY_ATTR(charge_empty),
101 POWER_SUPPLY_ATTR(charge_now), 101 POWER_SUPPLY_ATTR(charge_now),
102 POWER_SUPPLY_ATTR(charge_avg), 102 POWER_SUPPLY_ATTR(charge_avg),
103 POWER_SUPPLY_ATTR(energy_full_design), 103 POWER_SUPPLY_ATTR(energy_full_design),
104 POWER_SUPPLY_ATTR(energy_empty_design), 104 POWER_SUPPLY_ATTR(energy_empty_design),
105 POWER_SUPPLY_ATTR(energy_full), 105 POWER_SUPPLY_ATTR(energy_full),
106 POWER_SUPPLY_ATTR(energy_empty), 106 POWER_SUPPLY_ATTR(energy_empty),
107 POWER_SUPPLY_ATTR(energy_now), 107 POWER_SUPPLY_ATTR(energy_now),
108 POWER_SUPPLY_ATTR(energy_avg), 108 POWER_SUPPLY_ATTR(energy_avg),
109 POWER_SUPPLY_ATTR(capacity), 109 POWER_SUPPLY_ATTR(capacity),
110 POWER_SUPPLY_ATTR(capacity_level), 110 POWER_SUPPLY_ATTR(capacity_level),
111 POWER_SUPPLY_ATTR(temp), 111 POWER_SUPPLY_ATTR(temp),
112 POWER_SUPPLY_ATTR(temp_ambient), 112 POWER_SUPPLY_ATTR(temp_ambient),
113 POWER_SUPPLY_ATTR(time_to_empty_now), 113 POWER_SUPPLY_ATTR(time_to_empty_now),
114 POWER_SUPPLY_ATTR(time_to_empty_avg), 114 POWER_SUPPLY_ATTR(time_to_empty_avg),
115 POWER_SUPPLY_ATTR(time_to_full_now), 115 POWER_SUPPLY_ATTR(time_to_full_now),
116 POWER_SUPPLY_ATTR(time_to_full_avg), 116 POWER_SUPPLY_ATTR(time_to_full_avg),
117 /* Properties of type `const char *' */ 117 /* Properties of type `const char *' */
118 POWER_SUPPLY_ATTR(model_name), 118 POWER_SUPPLY_ATTR(model_name),
119 POWER_SUPPLY_ATTR(manufacturer), 119 POWER_SUPPLY_ATTR(manufacturer),
120 }; 120 };
121 121
122 static ssize_t power_supply_show_static_attrs(struct device *dev, 122 static ssize_t power_supply_show_static_attrs(struct device *dev,
123 struct device_attribute *attr, 123 struct device_attribute *attr,
124 char *buf) { 124 char *buf) {
125 static char *type_text[] = { "Battery", "UPS", "Mains", "USB" }; 125 static char *type_text[] = { "Battery", "UPS", "Mains", "USB" };
126 struct power_supply *psy = dev_get_drvdata(dev); 126 struct power_supply *psy = dev_get_drvdata(dev);
127 127
128 return sprintf(buf, "%s\n", type_text[psy->type]); 128 return sprintf(buf, "%s\n", type_text[psy->type]);
129 } 129 }
130 130
131 static struct device_attribute power_supply_static_attrs[] = { 131 static struct device_attribute power_supply_static_attrs[] = {
132 __ATTR(type, 0444, power_supply_show_static_attrs, NULL), 132 __ATTR(type, 0444, power_supply_show_static_attrs, NULL),
133 }; 133 };
134 134
135 int power_supply_create_attrs(struct power_supply *psy) 135 int power_supply_create_attrs(struct power_supply *psy)
136 { 136 {
137 int rc = 0; 137 int rc = 0;
138 int i, j; 138 int i, j;
139 139
140 for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) { 140 for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) {
141 rc = device_create_file(psy->dev, 141 rc = device_create_file(psy->dev,
142 &power_supply_static_attrs[i]); 142 &power_supply_static_attrs[i]);
143 if (rc) 143 if (rc)
144 goto statics_failed; 144 goto statics_failed;
145 } 145 }
146 146
147 for (j = 0; j < psy->num_properties; j++) { 147 for (j = 0; j < psy->num_properties; j++) {
148 rc = device_create_file(psy->dev, 148 rc = device_create_file(psy->dev,
149 &power_supply_attrs[psy->properties[j]]); 149 &power_supply_attrs[psy->properties[j]]);
150 if (rc) 150 if (rc)
151 goto dynamics_failed; 151 goto dynamics_failed;
152 } 152 }
153 153
154 goto succeed; 154 goto succeed;
155 155
156 dynamics_failed: 156 dynamics_failed:
157 while (j--) 157 while (j--)
158 device_remove_file(psy->dev, 158 device_remove_file(psy->dev,
159 &power_supply_attrs[psy->properties[j]]); 159 &power_supply_attrs[psy->properties[j]]);
160 statics_failed: 160 statics_failed:
161 while (i--) 161 while (i--)
162 device_remove_file(psy->dev, 162 device_remove_file(psy->dev,
163 &power_supply_static_attrs[psy->properties[i]]); 163 &power_supply_static_attrs[psy->properties[i]]);
164 succeed: 164 succeed:
165 return rc; 165 return rc;
166 } 166 }
167 167
168 void power_supply_remove_attrs(struct power_supply *psy) 168 void power_supply_remove_attrs(struct power_supply *psy)
169 { 169 {
170 int i; 170 int i;
171 171
172 for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) 172 for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++)
173 device_remove_file(psy->dev, 173 device_remove_file(psy->dev,
174 &power_supply_static_attrs[i]); 174 &power_supply_static_attrs[i]);
175 175
176 for (i = 0; i < psy->num_properties; i++) 176 for (i = 0; i < psy->num_properties; i++)
177 device_remove_file(psy->dev, 177 device_remove_file(psy->dev,
178 &power_supply_attrs[psy->properties[i]]); 178 &power_supply_attrs[psy->properties[i]]);
179
180 return;
181 } 179 }
182 180
183 static char *kstruprdup(const char *str, gfp_t gfp) 181 static char *kstruprdup(const char *str, gfp_t gfp)
184 { 182 {
185 char *ret, *ustr; 183 char *ret, *ustr;
186 184
187 ustr = ret = kmalloc(strlen(str) + 1, gfp); 185 ustr = ret = kmalloc(strlen(str) + 1, gfp);
188 186
189 if (!ret) 187 if (!ret)
190 return NULL; 188 return NULL;
191 189
192 while (*str) 190 while (*str)
193 *ustr++ = toupper(*str++); 191 *ustr++ = toupper(*str++);
194 192
195 *ustr = 0; 193 *ustr = 0;
196 194
197 return ret; 195 return ret;
198 } 196 }
199 197
200 int power_supply_uevent(struct device *dev, char **envp, int num_envp, 198 int power_supply_uevent(struct device *dev, char **envp, int num_envp,
201 char *buffer, int buffer_size) 199 char *buffer, int buffer_size)
202 { 200 {
203 struct power_supply *psy = dev_get_drvdata(dev); 201 struct power_supply *psy = dev_get_drvdata(dev);
204 int i = 0, length = 0, ret = 0, j; 202 int i = 0, length = 0, ret = 0, j;
205 char *prop_buf; 203 char *prop_buf;
206 char *attrname; 204 char *attrname;
207 205
208 dev_dbg(dev, "uevent\n"); 206 dev_dbg(dev, "uevent\n");
209 207
210 if (!psy) { 208 if (!psy) {
211 dev_dbg(dev, "No power supply yet\n"); 209 dev_dbg(dev, "No power supply yet\n");
212 return ret; 210 return ret;
213 } 211 }
214 212
215 dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name); 213 dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
216 214
217 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, 215 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
218 &length, "POWER_SUPPLY_NAME=%s", psy->name); 216 &length, "POWER_SUPPLY_NAME=%s", psy->name);
219 if (ret) 217 if (ret)
220 return ret; 218 return ret;
221 219
222 prop_buf = (char *)get_zeroed_page(GFP_KERNEL); 220 prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
223 if (!prop_buf) 221 if (!prop_buf)
224 return -ENOMEM; 222 return -ENOMEM;
225 223
226 for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) { 224 for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) {
227 struct device_attribute *attr; 225 struct device_attribute *attr;
228 char *line; 226 char *line;
229 227
230 attr = &power_supply_static_attrs[j]; 228 attr = &power_supply_static_attrs[j];
231 229
232 ret = power_supply_show_static_attrs(dev, attr, prop_buf); 230 ret = power_supply_show_static_attrs(dev, attr, prop_buf);
233 if (ret < 0) 231 if (ret < 0)
234 goto out; 232 goto out;
235 233
236 line = strchr(prop_buf, '\n'); 234 line = strchr(prop_buf, '\n');
237 if (line) 235 if (line)
238 *line = 0; 236 *line = 0;
239 237
240 attrname = kstruprdup(attr->attr.name, GFP_KERNEL); 238 attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
241 if (!attrname) { 239 if (!attrname) {
242 ret = -ENOMEM; 240 ret = -ENOMEM;
243 goto out; 241 goto out;
244 } 242 }
245 243
246 dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf); 244 dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
247 245
248 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, 246 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
249 &length, "POWER_SUPPLY_%s=%s", 247 &length, "POWER_SUPPLY_%s=%s",
250 attrname, prop_buf); 248 attrname, prop_buf);
251 kfree(attrname); 249 kfree(attrname);
252 if (ret) 250 if (ret)
253 goto out; 251 goto out;
254 } 252 }
255 253
256 dev_dbg(dev, "%zd dynamic props\n", psy->num_properties); 254 dev_dbg(dev, "%zd dynamic props\n", psy->num_properties);
257 255
258 for (j = 0; j < psy->num_properties; j++) { 256 for (j = 0; j < psy->num_properties; j++) {
259 struct device_attribute *attr; 257 struct device_attribute *attr;
260 char *line; 258 char *line;
261 259
262 attr = &power_supply_attrs[psy->properties[j]]; 260 attr = &power_supply_attrs[psy->properties[j]];
263 261
264 ret = power_supply_show_property(dev, attr, prop_buf); 262 ret = power_supply_show_property(dev, attr, prop_buf);
265 if (ret == -ENODEV) { 263 if (ret == -ENODEV) {
266 /* When a battery is absent, we expect -ENODEV. Don't abort; 264 /* When a battery is absent, we expect -ENODEV. Don't abort;
267 send the uevent with at least the the PRESENT=0 property */ 265 send the uevent with at least the the PRESENT=0 property */
268 ret = 0; 266 ret = 0;
269 continue; 267 continue;
270 } 268 }
271 269
272 if (ret < 0) 270 if (ret < 0)
273 goto out; 271 goto out;
274 272
275 line = strchr(prop_buf, '\n'); 273 line = strchr(prop_buf, '\n');
276 if (line) 274 if (line)
277 *line = 0; 275 *line = 0;
278 276
279 attrname = kstruprdup(attr->attr.name, GFP_KERNEL); 277 attrname = kstruprdup(attr->attr.name, GFP_KERNEL);
280 if (!attrname) { 278 if (!attrname) {
281 ret = -ENOMEM; 279 ret = -ENOMEM;
282 goto out; 280 goto out;
283 } 281 }
284 282
285 dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf); 283 dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
286 284
287 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, 285 ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
288 &length, "POWER_SUPPLY_%s=%s", 286 &length, "POWER_SUPPLY_%s=%s",
289 attrname, prop_buf); 287 attrname, prop_buf);
290 kfree(attrname); 288 kfree(attrname);
291 if (ret) 289 if (ret)
292 goto out; 290 goto out;
293 } 291 }
294 292
295 out: 293 out:
296 free_page((unsigned long)prop_buf); 294 free_page((unsigned long)prop_buf);
297 295
298 return ret; 296 return ret;
299 } 297 }
300 298
drivers/w1/slaves/w1_ds2760.c
1 /* 1 /*
2 * 1-Wire implementation for the ds2760 chip 2 * 1-Wire implementation for the ds2760 chip
3 * 3 *
4 * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> 4 * Copyright © 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
5 * 5 *
6 * Use consistent with the GNU GPL is permitted, 6 * Use consistent with the GNU GPL is permitted,
7 * provided that this copyright notice is 7 * provided that this copyright notice is
8 * preserved in its entirety in all copies and derived works. 8 * preserved in its entirety in all copies and derived works.
9 * 9 *
10 */ 10 */
11 11
12 #include <linux/kernel.h> 12 #include <linux/kernel.h>
13 #include <linux/module.h> 13 #include <linux/module.h>
14 #include <linux/device.h> 14 #include <linux/device.h>
15 #include <linux/types.h> 15 #include <linux/types.h>
16 #include <linux/platform_device.h> 16 #include <linux/platform_device.h>
17 #include <linux/mutex.h> 17 #include <linux/mutex.h>
18 #include <linux/idr.h> 18 #include <linux/idr.h>
19 19
20 #include "../w1.h" 20 #include "../w1.h"
21 #include "../w1_int.h" 21 #include "../w1_int.h"
22 #include "../w1_family.h" 22 #include "../w1_family.h"
23 #include "w1_ds2760.h" 23 #include "w1_ds2760.h"
24 24
25 static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count, 25 static int w1_ds2760_io(struct device *dev, char *buf, int addr, size_t count,
26 int io) 26 int io)
27 { 27 {
28 struct w1_slave *sl = container_of(dev, struct w1_slave, dev); 28 struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
29 29
30 if (!dev) 30 if (!dev)
31 return 0; 31 return 0;
32 32
33 mutex_lock(&sl->master->mutex); 33 mutex_lock(&sl->master->mutex);
34 34
35 if (addr > DS2760_DATA_SIZE || addr < 0) { 35 if (addr > DS2760_DATA_SIZE || addr < 0) {
36 count = 0; 36 count = 0;
37 goto out; 37 goto out;
38 } 38 }
39 if (addr + count > DS2760_DATA_SIZE) 39 if (addr + count > DS2760_DATA_SIZE)
40 count = DS2760_DATA_SIZE - addr; 40 count = DS2760_DATA_SIZE - addr;
41 41
42 if (!w1_reset_select_slave(sl)) { 42 if (!w1_reset_select_slave(sl)) {
43 if (!io) { 43 if (!io) {
44 w1_write_8(sl->master, W1_DS2760_READ_DATA); 44 w1_write_8(sl->master, W1_DS2760_READ_DATA);
45 w1_write_8(sl->master, addr); 45 w1_write_8(sl->master, addr);
46 count = w1_read_block(sl->master, buf, count); 46 count = w1_read_block(sl->master, buf, count);
47 } else { 47 } else {
48 w1_write_8(sl->master, W1_DS2760_WRITE_DATA); 48 w1_write_8(sl->master, W1_DS2760_WRITE_DATA);
49 w1_write_8(sl->master, addr); 49 w1_write_8(sl->master, addr);
50 w1_write_block(sl->master, buf, count); 50 w1_write_block(sl->master, buf, count);
51 /* XXX w1_write_block returns void, not n_written */ 51 /* XXX w1_write_block returns void, not n_written */
52 } 52 }
53 } 53 }
54 54
55 out: 55 out:
56 mutex_unlock(&sl->master->mutex); 56 mutex_unlock(&sl->master->mutex);
57 57
58 return count; 58 return count;
59 } 59 }
60 60
61 int w1_ds2760_read(struct device *dev, char *buf, int addr, size_t count) 61 int w1_ds2760_read(struct device *dev, char *buf, int addr, size_t count)
62 { 62 {
63 return w1_ds2760_io(dev, buf, addr, count, 0); 63 return w1_ds2760_io(dev, buf, addr, count, 0);
64 } 64 }
65 65
66 int w1_ds2760_write(struct device *dev, char *buf, int addr, size_t count) 66 int w1_ds2760_write(struct device *dev, char *buf, int addr, size_t count)
67 { 67 {
68 return w1_ds2760_io(dev, buf, addr, count, 1); 68 return w1_ds2760_io(dev, buf, addr, count, 1);
69 } 69 }
70 70
71 static ssize_t w1_ds2760_read_bin(struct kobject *kobj, char *buf, loff_t off, 71 static ssize_t w1_ds2760_read_bin(struct kobject *kobj, char *buf, loff_t off,
72 size_t count) 72 size_t count)
73 { 73 {
74 struct device *dev = container_of(kobj, struct device, kobj); 74 struct device *dev = container_of(kobj, struct device, kobj);
75 return w1_ds2760_read(dev, buf, off, count); 75 return w1_ds2760_read(dev, buf, off, count);
76 } 76 }
77 77
78 static struct bin_attribute w1_ds2760_bin_attr = { 78 static struct bin_attribute w1_ds2760_bin_attr = {
79 .attr = { 79 .attr = {
80 .name = "w1_slave", 80 .name = "w1_slave",
81 .mode = S_IRUGO, 81 .mode = S_IRUGO,
82 .owner = THIS_MODULE, 82 .owner = THIS_MODULE,
83 }, 83 },
84 .size = DS2760_DATA_SIZE, 84 .size = DS2760_DATA_SIZE,
85 .read = w1_ds2760_read_bin, 85 .read = w1_ds2760_read_bin,
86 }; 86 };
87 87
88 static DEFINE_IDR(bat_idr); 88 static DEFINE_IDR(bat_idr);
89 static DEFINE_MUTEX(bat_idr_lock); 89 static DEFINE_MUTEX(bat_idr_lock);
90 90
91 static int new_bat_id(void) 91 static int new_bat_id(void)
92 { 92 {
93 int ret; 93 int ret;
94 94
95 while (1) { 95 while (1) {
96 int id; 96 int id;
97 97
98 ret = idr_pre_get(&bat_idr, GFP_KERNEL); 98 ret = idr_pre_get(&bat_idr, GFP_KERNEL);
99 if (ret == 0) 99 if (ret == 0)
100 return -ENOMEM; 100 return -ENOMEM;
101 101
102 mutex_lock(&bat_idr_lock); 102 mutex_lock(&bat_idr_lock);
103 ret = idr_get_new(&bat_idr, NULL, &id); 103 ret = idr_get_new(&bat_idr, NULL, &id);
104 mutex_unlock(&bat_idr_lock); 104 mutex_unlock(&bat_idr_lock);
105 105
106 if (ret == 0) { 106 if (ret == 0) {
107 ret = id & MAX_ID_MASK; 107 ret = id & MAX_ID_MASK;
108 break; 108 break;
109 } else if (ret == -EAGAIN) { 109 } else if (ret == -EAGAIN) {
110 continue; 110 continue;
111 } else { 111 } else {
112 break; 112 break;
113 } 113 }
114 } 114 }
115 115
116 return ret; 116 return ret;
117 } 117 }
118 118
119 static void release_bat_id(int id) 119 static void release_bat_id(int id)
120 { 120 {
121 mutex_lock(&bat_idr_lock); 121 mutex_lock(&bat_idr_lock);
122 idr_remove(&bat_idr, id); 122 idr_remove(&bat_idr, id);
123 mutex_unlock(&bat_idr_lock); 123 mutex_unlock(&bat_idr_lock);
124
125 return;
126 } 124 }
127 125
128 static int w1_ds2760_add_slave(struct w1_slave *sl) 126 static int w1_ds2760_add_slave(struct w1_slave *sl)
129 { 127 {
130 int ret; 128 int ret;
131 int id; 129 int id;
132 struct platform_device *pdev; 130 struct platform_device *pdev;
133 131
134 id = new_bat_id(); 132 id = new_bat_id();
135 if (id < 0) { 133 if (id < 0) {
136 ret = id; 134 ret = id;
137 goto noid; 135 goto noid;
138 } 136 }
139 137
140 pdev = platform_device_alloc("ds2760-battery", id); 138 pdev = platform_device_alloc("ds2760-battery", id);
141 if (!pdev) { 139 if (!pdev) {
142 ret = -ENOMEM; 140 ret = -ENOMEM;
143 goto pdev_alloc_failed; 141 goto pdev_alloc_failed;
144 } 142 }
145 pdev->dev.parent = &sl->dev; 143 pdev->dev.parent = &sl->dev;
146 144
147 ret = platform_device_add(pdev); 145 ret = platform_device_add(pdev);
148 if (ret) 146 if (ret)
149 goto pdev_add_failed; 147 goto pdev_add_failed;
150 148
151 ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr); 149 ret = sysfs_create_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
152 if (ret) 150 if (ret)
153 goto bin_attr_failed; 151 goto bin_attr_failed;
154 152
155 dev_set_drvdata(&sl->dev, pdev); 153 dev_set_drvdata(&sl->dev, pdev);
156 154
157 goto success; 155 goto success;
158 156
159 bin_attr_failed: 157 bin_attr_failed:
160 pdev_add_failed: 158 pdev_add_failed:
161 platform_device_unregister(pdev); 159 platform_device_unregister(pdev);
162 pdev_alloc_failed: 160 pdev_alloc_failed:
163 release_bat_id(id); 161 release_bat_id(id);
164 noid: 162 noid:
165 success: 163 success:
166 return ret; 164 return ret;
167 } 165 }
168 166
169 static void w1_ds2760_remove_slave(struct w1_slave *sl) 167 static void w1_ds2760_remove_slave(struct w1_slave *sl)
170 { 168 {
171 struct platform_device *pdev = dev_get_drvdata(&sl->dev); 169 struct platform_device *pdev = dev_get_drvdata(&sl->dev);
172 int id = pdev->id; 170 int id = pdev->id;
173 171
174 platform_device_unregister(pdev); 172 platform_device_unregister(pdev);
175 release_bat_id(id); 173 release_bat_id(id);
176 sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr); 174 sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
177
178 return;
179 } 175 }
180 176
181 static struct w1_family_ops w1_ds2760_fops = { 177 static struct w1_family_ops w1_ds2760_fops = {
182 .add_slave = w1_ds2760_add_slave, 178 .add_slave = w1_ds2760_add_slave,
183 .remove_slave = w1_ds2760_remove_slave, 179 .remove_slave = w1_ds2760_remove_slave,
184 }; 180 };
185 181
186 static struct w1_family w1_ds2760_family = { 182 static struct w1_family w1_ds2760_family = {
187 .fid = W1_FAMILY_DS2760, 183 .fid = W1_FAMILY_DS2760,
188 .fops = &w1_ds2760_fops, 184 .fops = &w1_ds2760_fops,
189 }; 185 };
190 186
191 static int __init w1_ds2760_init(void) 187 static int __init w1_ds2760_init(void)
192 { 188 {
193 printk(KERN_INFO "1-Wire driver for the DS2760 battery monitor " 189 printk(KERN_INFO "1-Wire driver for the DS2760 battery monitor "
194 " chip - (c) 2004-2005, Szabolcs Gyurko\n"); 190 " chip - (c) 2004-2005, Szabolcs Gyurko\n");
195 idr_init(&bat_idr); 191 idr_init(&bat_idr);
196 return w1_register_family(&w1_ds2760_family); 192 return w1_register_family(&w1_ds2760_family);
197 } 193 }
198 194
199 static void __exit w1_ds2760_exit(void) 195 static void __exit w1_ds2760_exit(void)
200 { 196 {
201 w1_unregister_family(&w1_ds2760_family); 197 w1_unregister_family(&w1_ds2760_family);
202 idr_destroy(&bat_idr); 198 idr_destroy(&bat_idr);
203 } 199 }
204 200
205 EXPORT_SYMBOL(w1_ds2760_read); 201 EXPORT_SYMBOL(w1_ds2760_read);
206 EXPORT_SYMBOL(w1_ds2760_write); 202 EXPORT_SYMBOL(w1_ds2760_write);
207 203
208 module_init(w1_ds2760_init); 204 module_init(w1_ds2760_init);
209 module_exit(w1_ds2760_exit); 205 module_exit(w1_ds2760_exit);
210 206
211 MODULE_LICENSE("GPL"); 207 MODULE_LICENSE("GPL");
212 MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>"); 208 MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>");
213 MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip"); 209 MODULE_DESCRIPTION("1-wire Driver Dallas 2760 battery monitor chip");
214 210