aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/sbs.c
diff options
context:
space:
mode:
authorAlexey Starikovskiy <astarikovskiy@suse.de>2007-09-26 11:43:48 -0400
committerLen Brown <len.brown@intel.com>2007-09-27 15:50:22 -0400
commit94f6c0860139da9219255b8ff45ad42117dda859 (patch)
treebc61aa08e89467d3b9b22b5f1d640425491a65d5 /drivers/acpi/sbs.c
parentdb1c291af7ad748777371f25b9ff92e3e5aba38e (diff)
ACPI: SBS: Add support for power_supply class (and sysfs)
Add support for power_supply class and sysfs interface of it. Refer to Documentation/power_supply_class.txt for interface description. Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/sbs.c')
-rw-r--r--drivers/acpi/sbs.c314
1 files changed, 233 insertions, 81 deletions
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 3351dea11ff0..c4f9641147c4 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -28,17 +28,20 @@
28#include <linux/module.h> 28#include <linux/module.h>
29#include <linux/moduleparam.h> 29#include <linux/moduleparam.h>
30#include <linux/kernel.h> 30#include <linux/kernel.h>
31
31#include <linux/proc_fs.h> 32#include <linux/proc_fs.h>
32#include <linux/seq_file.h> 33#include <linux/seq_file.h>
33#include <asm/uaccess.h> 34#include <asm/uaccess.h>
35
34#include <linux/acpi.h> 36#include <linux/acpi.h>
35#include <linux/timer.h> 37#include <linux/timer.h>
36#include <linux/jiffies.h> 38#include <linux/jiffies.h>
37#include <linux/delay.h> 39#include <linux/delay.h>
38 40
41#include <linux/power_supply.h>
42
39#include "sbshc.h" 43#include "sbshc.h"
40 44
41#define ACPI_SBS_COMPONENT 0x00080000
42#define ACPI_SBS_CLASS "sbs" 45#define ACPI_SBS_CLASS "sbs"
43#define ACPI_AC_CLASS "ac_adapter" 46#define ACPI_AC_CLASS "ac_adapter"
44#define ACPI_BATTERY_CLASS "battery" 47#define ACPI_BATTERY_CLASS "battery"
@@ -58,8 +61,6 @@ enum acpi_sbs_device_addr {
58#define ACPI_SBS_NOTIFY_STATUS 0x80 61#define ACPI_SBS_NOTIFY_STATUS 0x80
59#define ACPI_SBS_NOTIFY_INFO 0x81 62#define ACPI_SBS_NOTIFY_INFO 0x81
60 63
61ACPI_MODULE_NAME("sbs");
62
63MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); 64MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
64MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); 65MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
65MODULE_LICENSE("GPL"); 66MODULE_LICENSE("GPL");
@@ -76,28 +77,14 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
76#define MAX_SBS_BAT 4 77#define MAX_SBS_BAT 4
77#define ACPI_SBS_BLOCK_MAX 32 78#define ACPI_SBS_BLOCK_MAX 32
78 79
79static int acpi_sbs_add(struct acpi_device *device);
80static int acpi_sbs_remove(struct acpi_device *device, int type);
81static int acpi_sbs_resume(struct acpi_device *device);
82
83static const struct acpi_device_id sbs_device_ids[] = { 80static const struct acpi_device_id sbs_device_ids[] = {
84 {"ACPI0002", 0}, 81 {"ACPI0002", 0},
85 {"", 0}, 82 {"", 0},
86}; 83};
87MODULE_DEVICE_TABLE(acpi, sbs_device_ids); 84MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
88 85
89static struct acpi_driver acpi_sbs_driver = {
90 .name = "sbs",
91 .class = ACPI_SBS_CLASS,
92 .ids = sbs_device_ids,
93 .ops = {
94 .add = acpi_sbs_add,
95 .remove = acpi_sbs_remove,
96 .resume = acpi_sbs_resume,
97 },
98};
99
100struct acpi_battery { 86struct acpi_battery {
87 struct power_supply bat;
101 struct acpi_sbs *sbs; 88 struct acpi_sbs *sbs;
102 struct proc_dir_entry *proc_entry; 89 struct proc_dir_entry *proc_entry;
103 unsigned long update_time; 90 unsigned long update_time;
@@ -105,7 +92,7 @@ struct acpi_battery {
105 char manufacturer_name[ACPI_SBS_BLOCK_MAX]; 92 char manufacturer_name[ACPI_SBS_BLOCK_MAX];
106 char device_name[ACPI_SBS_BLOCK_MAX]; 93 char device_name[ACPI_SBS_BLOCK_MAX];
107 char device_chemistry[ACPI_SBS_BLOCK_MAX]; 94 char device_chemistry[ACPI_SBS_BLOCK_MAX];
108 u32 alarm_capacity; 95 u16 alarm_capacity;
109 u16 full_charge_capacity; 96 u16 full_charge_capacity;
110 u16 design_capacity; 97 u16 design_capacity;
111 u16 design_voltage; 98 u16 design_voltage;
@@ -124,7 +111,10 @@ struct acpi_battery {
124 u8 present:1; 111 u8 present:1;
125}; 112};
126 113
114#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat);
115
127struct acpi_sbs { 116struct acpi_sbs {
117 struct power_supply charger;
128 struct acpi_device *device; 118 struct acpi_device *device;
129 struct acpi_smb_hc *hc; 119 struct acpi_smb_hc *hc;
130 struct mutex lock; 120 struct mutex lock;
@@ -135,6 +125,8 @@ struct acpi_sbs {
135 u8 charger_present:1; 125 u8 charger_present:1;
136}; 126};
137 127
128#define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger)
129
138static inline int battery_scale(int log) 130static inline int battery_scale(int log)
139{ 131{
140 int scale = 1; 132 int scale = 1;
@@ -164,6 +156,144 @@ static inline int acpi_battery_scale(struct acpi_battery *battery)
164 acpi_battery_ipscale(battery); 156 acpi_battery_ipscale(battery);
165} 157}
166 158
159static int sbs_get_ac_property(struct power_supply *psy,
160 enum power_supply_property psp,
161 union power_supply_propval *val)
162{
163 struct acpi_sbs *sbs = to_acpi_sbs(psy);
164 switch (psp) {
165 case POWER_SUPPLY_PROP_ONLINE:
166 val->intval = sbs->charger_present;
167 break;
168 default:
169 return -EINVAL;
170 }
171 return 0;
172}
173
174static int acpi_battery_technology(struct acpi_battery *battery)
175{
176 if (!strcasecmp("NiCd", battery->device_chemistry))
177 return POWER_SUPPLY_TECHNOLOGY_NiCd;
178 if (!strcasecmp("NiMH", battery->device_chemistry))
179 return POWER_SUPPLY_TECHNOLOGY_NiMH;
180 if (!strcasecmp("LION", battery->device_chemistry))
181 return POWER_SUPPLY_TECHNOLOGY_LION;
182 if (!strcasecmp("LiP", battery->device_chemistry))
183 return POWER_SUPPLY_TECHNOLOGY_LIPO;
184 return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
185}
186
187static int acpi_sbs_battery_get_property(struct power_supply *psy,
188 enum power_supply_property psp,
189 union power_supply_propval *val)
190{
191 struct acpi_battery *battery = to_acpi_battery(psy);
192
193 if ((!battery->present) && psp != POWER_SUPPLY_PROP_PRESENT)
194 return -ENODEV;
195 switch (psp) {
196 case POWER_SUPPLY_PROP_STATUS:
197 if (battery->current_now < 0)
198 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
199 else if (battery->current_now > 0)
200 val->intval = POWER_SUPPLY_STATUS_CHARGING;
201 else
202 val->intval = POWER_SUPPLY_STATUS_FULL;
203 break;
204 case POWER_SUPPLY_PROP_PRESENT:
205 val->intval = battery->present;
206 break;
207 case POWER_SUPPLY_PROP_TECHNOLOGY:
208 val->intval = acpi_battery_technology(battery);
209 break;
210 case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
211 val->intval = battery->design_voltage *
212 acpi_battery_vscale(battery) * 1000;
213 break;
214 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
215 val->intval = battery->voltage_now *
216 acpi_battery_vscale(battery) * 1000;
217 break;
218 case POWER_SUPPLY_PROP_CURRENT_NOW:
219 val->intval = abs(battery->current_now) *
220 acpi_battery_ipscale(battery) * 1000;
221 break;
222 case POWER_SUPPLY_PROP_CURRENT_AVG:
223 val->intval = abs(battery->current_avg) *
224 acpi_battery_ipscale(battery) * 1000;
225 break;
226 case POWER_SUPPLY_PROP_CAPACITY:
227 val->intval = battery->state_of_charge;
228 break;
229 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
230 case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
231 val->intval = battery->design_capacity *
232 acpi_battery_scale(battery) * 1000;
233 break;
234 case POWER_SUPPLY_PROP_CHARGE_FULL:
235 case POWER_SUPPLY_PROP_ENERGY_FULL:
236 val->intval = battery->full_charge_capacity *
237 acpi_battery_scale(battery) * 1000;
238 break;
239 case POWER_SUPPLY_PROP_CHARGE_NOW:
240 case POWER_SUPPLY_PROP_ENERGY_NOW:
241 val->intval = battery->capacity_now *
242 acpi_battery_scale(battery) * 1000;
243 break;
244 case POWER_SUPPLY_PROP_TEMP:
245 val->intval = battery->temp_now - 2730; // dK -> dC
246 break;
247 case POWER_SUPPLY_PROP_MODEL_NAME:
248 val->strval = battery->device_name;
249 break;
250 case POWER_SUPPLY_PROP_MANUFACTURER:
251 val->strval = battery->manufacturer_name;
252 break;
253 default:
254 return -EINVAL;
255 }
256 return 0;
257}
258
259static enum power_supply_property sbs_ac_props[] = {
260 POWER_SUPPLY_PROP_ONLINE,
261};
262
263static enum power_supply_property sbs_charge_battery_props[] = {
264 POWER_SUPPLY_PROP_STATUS,
265 POWER_SUPPLY_PROP_PRESENT,
266 POWER_SUPPLY_PROP_TECHNOLOGY,
267 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
268 POWER_SUPPLY_PROP_VOLTAGE_NOW,
269 POWER_SUPPLY_PROP_CURRENT_NOW,
270 POWER_SUPPLY_PROP_CURRENT_AVG,
271 POWER_SUPPLY_PROP_CAPACITY,
272 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
273 POWER_SUPPLY_PROP_CHARGE_FULL,
274 POWER_SUPPLY_PROP_CHARGE_NOW,
275 POWER_SUPPLY_PROP_TEMP,
276 POWER_SUPPLY_PROP_MODEL_NAME,
277 POWER_SUPPLY_PROP_MANUFACTURER,
278};
279
280static enum power_supply_property sbs_energy_battery_props[] = {
281 POWER_SUPPLY_PROP_STATUS,
282 POWER_SUPPLY_PROP_PRESENT,
283 POWER_SUPPLY_PROP_TECHNOLOGY,
284 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
285 POWER_SUPPLY_PROP_VOLTAGE_NOW,
286 POWER_SUPPLY_PROP_CURRENT_NOW,
287 POWER_SUPPLY_PROP_CURRENT_AVG,
288 POWER_SUPPLY_PROP_CAPACITY,
289 POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
290 POWER_SUPPLY_PROP_ENERGY_FULL,
291 POWER_SUPPLY_PROP_ENERGY_NOW,
292 POWER_SUPPLY_PROP_TEMP,
293 POWER_SUPPLY_PROP_MODEL_NAME,
294 POWER_SUPPLY_PROP_MANUFACTURER,
295};
296
167/* -------------------------------------------------------------------------- 297/* --------------------------------------------------------------------------
168 Smart Battery System Management 298 Smart Battery System Management
169 -------------------------------------------------------------------------- */ 299 -------------------------------------------------------------------------- */
@@ -204,7 +334,7 @@ static int acpi_manager_get_info(struct acpi_sbs *sbs)
204 u16 battery_system_info; 334 u16 battery_system_info;
205 335
206 result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, 336 result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER,
207 0x04, (u8 *) & battery_system_info); 337 0x04, (u8 *)&battery_system_info);
208 if (!result) 338 if (!result)
209 sbs->batteries_supported = battery_system_info & 0x000f; 339 sbs->batteries_supported = battery_system_info & 0x000f;
210 return result; 340 return result;
@@ -215,9 +345,12 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
215 int i, result = 0; 345 int i, result = 0;
216 346
217 for (i = 0; i < ARRAY_SIZE(info_readers); ++i) { 347 for (i = 0; i < ARRAY_SIZE(info_readers); ++i) {
218 result = acpi_smbus_read(battery->sbs->hc, info_readers[i].mode, 348 result = acpi_smbus_read(battery->sbs->hc,
219 ACPI_SBS_BATTERY, info_readers[i].command, 349 info_readers[i].mode,
220 (u8 *) battery + info_readers[i].offset); 350 ACPI_SBS_BATTERY,
351 info_readers[i].command,
352 (u8 *) battery +
353 info_readers[i].offset);
221 if (result) 354 if (result)
222 break; 355 break;
223 } 356 }
@@ -228,7 +361,8 @@ static int acpi_battery_get_state(struct acpi_battery *battery)
228{ 361{
229 int i, result = 0; 362 int i, result = 0;
230 363
231 if (time_before(jiffies, battery->update_time + 364 if (battery->update_time &&
365 time_before(jiffies, battery->update_time +
232 msecs_to_jiffies(cache_time))) 366 msecs_to_jiffies(cache_time)))
233 return 0; 367 return 0;
234 for (i = 0; i < ARRAY_SIZE(state_readers); ++i) { 368 for (i = 0; i < ARRAY_SIZE(state_readers); ++i) {
@@ -250,26 +384,36 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery)
250{ 384{
251 return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, 385 return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD,
252 ACPI_SBS_BATTERY, 0x01, 386 ACPI_SBS_BATTERY, 0x01,
253 (u8 *) & battery->alarm_capacity); 387 (u8 *)&battery->alarm_capacity);
254} 388}
255 389
256static int acpi_battery_set_alarm(struct acpi_battery *battery) 390static int acpi_battery_set_alarm(struct acpi_battery *battery)
257{ 391{
258 struct acpi_sbs *sbs = battery->sbs; 392 struct acpi_sbs *sbs = battery->sbs;
259 u16 value; 393 u16 value, sel = 1 << (battery->id + 12);
260 return 0; 394
395 int ret;
396
261 397
262 if (sbs->manager_present) { 398 if (sbs->manager_present) {
263 acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, 399 ret = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER,
264 0x01, (u8 *)&value); 400 0x01, (u8 *)&value);
265 value &= 0x0fff; 401 if (ret)
266 value |= 1 << (battery->id + 12); 402 goto end;
267 acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_MANAGER, 403 if ((value & 0xf000) != sel) {
268 0x01, (u8 *)&value, 2); 404 value &= 0x0fff;
405 value |= sel;
406 ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD,
407 ACPI_SBS_MANAGER,
408 0x01, (u8 *)&value, 2);
409 if (ret)
410 goto end;
411 }
269 } 412 }
270 value = battery->alarm_capacity / (acpi_battery_mode(battery) ? 10 : 1); 413 ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY,
271 return acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY, 414 0x01, (u8 *)&battery->alarm_capacity, 2);
272 0x01, (u8 *)&value, 2); 415 end:
416 return ret;
273} 417}
274 418
275static int acpi_ac_get_present(struct acpi_sbs *sbs) 419static int acpi_ac_get_present(struct acpi_sbs *sbs)
@@ -289,22 +433,19 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs)
289 -------------------------------------------------------------------------- */ 433 -------------------------------------------------------------------------- */
290 434
291/* Generic Routines */ 435/* Generic Routines */
292
293static int 436static int
294acpi_sbs_add_fs(struct proc_dir_entry **dir, 437acpi_sbs_add_fs(struct proc_dir_entry **dir,
295 struct proc_dir_entry *parent_dir, 438 struct proc_dir_entry *parent_dir,
296 char *dir_name, 439 char *dir_name,
297 struct file_operations *info_fops, 440 struct file_operations *info_fops,
298 struct file_operations *state_fops, 441 struct file_operations *state_fops,
299 struct file_operations *alarm_fops, void *data) 442 struct file_operations *alarm_fops, void *data)
300{ 443{
301 struct proc_dir_entry *entry = NULL; 444 struct proc_dir_entry *entry = NULL;
302 445
303 if (!*dir) { 446 if (!*dir) {
304 *dir = proc_mkdir(dir_name, parent_dir); 447 *dir = proc_mkdir(dir_name, parent_dir);
305 if (!*dir) { 448 if (!*dir) {
306 ACPI_EXCEPTION((AE_INFO, AE_ERROR,
307 "proc_mkdir() failed"));
308 return -ENODEV; 449 return -ENODEV;
309 } 450 }
310 (*dir)->owner = THIS_MODULE; 451 (*dir)->owner = THIS_MODULE;
@@ -313,10 +454,7 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir,
313 /* 'info' [R] */ 454 /* 'info' [R] */
314 if (info_fops) { 455 if (info_fops) {
315 entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir); 456 entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
316 if (!entry) { 457 if (entry) {
317 ACPI_EXCEPTION((AE_INFO, AE_ERROR,
318 "create_proc_entry() failed"));
319 } else {
320 entry->proc_fops = info_fops; 458 entry->proc_fops = info_fops;
321 entry->data = data; 459 entry->data = data;
322 entry->owner = THIS_MODULE; 460 entry->owner = THIS_MODULE;
@@ -326,10 +464,7 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir,
326 /* 'state' [R] */ 464 /* 'state' [R] */
327 if (state_fops) { 465 if (state_fops) {
328 entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir); 466 entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
329 if (!entry) { 467 if (entry) {
330 ACPI_EXCEPTION((AE_INFO, AE_ERROR,
331 "create_proc_entry() failed"));
332 } else {
333 entry->proc_fops = state_fops; 468 entry->proc_fops = state_fops;
334 entry->data = data; 469 entry->data = data;
335 entry->owner = THIS_MODULE; 470 entry->owner = THIS_MODULE;
@@ -339,16 +474,12 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir,
339 /* 'alarm' [R/W] */ 474 /* 'alarm' [R/W] */
340 if (alarm_fops) { 475 if (alarm_fops) {
341 entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir); 476 entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
342 if (!entry) { 477 if (entry) {
343 ACPI_EXCEPTION((AE_INFO, AE_ERROR,
344 "create_proc_entry() failed"));
345 } else {
346 entry->proc_fops = alarm_fops; 478 entry->proc_fops = alarm_fops;
347 entry->data = data; 479 entry->data = data;
348 entry->owner = THIS_MODULE; 480 entry->owner = THIS_MODULE;
349 } 481 }
350 } 482 }
351
352 return 0; 483 return 0;
353} 484}
354 485
@@ -356,7 +487,6 @@ static void
356acpi_sbs_remove_fs(struct proc_dir_entry **dir, 487acpi_sbs_remove_fs(struct proc_dir_entry **dir,
357 struct proc_dir_entry *parent_dir) 488 struct proc_dir_entry *parent_dir)
358{ 489{
359
360 if (*dir) { 490 if (*dir) {
361 remove_proc_entry(ACPI_SBS_FILE_INFO, *dir); 491 remove_proc_entry(ACPI_SBS_FILE_INFO, *dir);
362 remove_proc_entry(ACPI_SBS_FILE_STATE, *dir); 492 remove_proc_entry(ACPI_SBS_FILE_STATE, *dir);
@@ -364,11 +494,9 @@ acpi_sbs_remove_fs(struct proc_dir_entry **dir,
364 remove_proc_entry((*dir)->name, parent_dir); 494 remove_proc_entry((*dir)->name, parent_dir);
365 *dir = NULL; 495 *dir = NULL;
366 } 496 }
367
368} 497}
369 498
370/* Smart Battery Interface */ 499/* Smart Battery Interface */
371
372static struct proc_dir_entry *acpi_battery_dir = NULL; 500static struct proc_dir_entry *acpi_battery_dir = NULL;
373 501
374static inline char *acpi_battery_units(struct acpi_battery *battery) 502static inline char *acpi_battery_units(struct acpi_battery *battery)
@@ -506,7 +634,8 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer,
506 goto end; 634 goto end;
507 } 635 }
508 alarm_string[count] = 0; 636 alarm_string[count] = 0;
509 battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0); 637 battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0) /
638 acpi_battery_scale(battery);
510 acpi_battery_set_alarm(battery); 639 acpi_battery_set_alarm(battery);
511 end: 640 end:
512 mutex_unlock(&sbs->lock); 641 mutex_unlock(&sbs->lock);
@@ -579,9 +708,6 @@ static struct file_operations acpi_ac_state_fops = {
579/* -------------------------------------------------------------------------- 708/* --------------------------------------------------------------------------
580 Driver Interface 709 Driver Interface
581 -------------------------------------------------------------------------- */ 710 -------------------------------------------------------------------------- */
582
583/* Smart Battery */
584
585static int acpi_battery_read(struct acpi_battery *battery) 711static int acpi_battery_read(struct acpi_battery *battery)
586{ 712{
587 int result = 0, saved_present = battery->present; 713 int result = 0, saved_present = battery->present;
@@ -611,13 +737,14 @@ static int acpi_battery_read(struct acpi_battery *battery)
611 return result; 737 return result;
612} 738}
613 739
740/* Smart Battery */
614static int acpi_battery_add(struct acpi_sbs *sbs, int id) 741static int acpi_battery_add(struct acpi_sbs *sbs, int id)
615{ 742{
616 int result;
617 struct acpi_battery *battery = &sbs->battery[id]; 743 struct acpi_battery *battery = &sbs->battery[id];
744 int result;
745
618 battery->id = id; 746 battery->id = id;
619 battery->sbs = sbs; 747 battery->sbs = sbs;
620 battery->update_time = 0;
621 result = acpi_battery_read(battery); 748 result = acpi_battery_read(battery);
622 if (result) 749 if (result)
623 return result; 750 return result;
@@ -627,6 +754,19 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
627 battery->name, &acpi_battery_info_fops, 754 battery->name, &acpi_battery_info_fops,
628 &acpi_battery_state_fops, &acpi_battery_alarm_fops, 755 &acpi_battery_state_fops, &acpi_battery_alarm_fops,
629 battery); 756 battery);
757 battery->bat.name = battery->name;
758 battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
759 if (!acpi_battery_mode(battery)) {
760 battery->bat.properties = sbs_charge_battery_props;
761 battery->bat.num_properties =
762 ARRAY_SIZE(sbs_charge_battery_props);
763 } else {
764 battery->bat.properties = sbs_energy_battery_props;
765 battery->bat.num_properties =
766 ARRAY_SIZE(sbs_energy_battery_props);
767 }
768 battery->bat.get_property = acpi_sbs_battery_get_property;
769 result = power_supply_register(&sbs->device->dev, &battery->bat);
630 printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n", 770 printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
631 ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), 771 ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
632 battery->name, sbs->battery->present ? "present" : "absent"); 772 battery->name, sbs->battery->present ? "present" : "absent");
@@ -635,7 +775,8 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
635 775
636static void acpi_battery_remove(struct acpi_sbs *sbs, int id) 776static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
637{ 777{
638 778 if (sbs->battery[id].bat.dev)
779 power_supply_unregister(&sbs->battery[id].bat);
639 if (sbs->battery[id].proc_entry) { 780 if (sbs->battery[id].proc_entry) {
640 acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry), 781 acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry),
641 acpi_battery_dir); 782 acpi_battery_dir);
@@ -654,6 +795,12 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
654 &acpi_ac_state_fops, NULL, sbs); 795 &acpi_ac_state_fops, NULL, sbs);
655 if (result) 796 if (result)
656 goto end; 797 goto end;
798 sbs->charger.name = "sbs-charger";
799 sbs->charger.type = POWER_SUPPLY_TYPE_MAINS;
800 sbs->charger.properties = sbs_ac_props;
801 sbs->charger.num_properties = ARRAY_SIZE(sbs_ac_props);
802 sbs->charger.get_property = sbs_get_ac_property;
803 power_supply_register(&sbs->device->dev, &sbs->charger);
657 printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n", 804 printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
658 ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), 805 ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
659 ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line"); 806 ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line");
@@ -663,7 +810,8 @@ static int acpi_charger_add(struct acpi_sbs *sbs)
663 810
664static void acpi_charger_remove(struct acpi_sbs *sbs) 811static void acpi_charger_remove(struct acpi_sbs *sbs)
665{ 812{
666 813 if (sbs->charger.dev)
814 power_supply_unregister(&sbs->charger);
667 if (sbs->charger_entry) 815 if (sbs->charger_entry)
668 acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir); 816 acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir);
669} 817}
@@ -677,9 +825,12 @@ void acpi_sbs_callback(void *context)
677 u8 saved_battery_state; 825 u8 saved_battery_state;
678 acpi_ac_get_present(sbs); 826 acpi_ac_get_present(sbs);
679 if (sbs->charger_present != saved_charger_state) { 827 if (sbs->charger_present != saved_charger_state) {
828#ifdef CONFIG_ACPI_PROC_EVENT
680 acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, 829 acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME,
681 ACPI_SBS_NOTIFY_STATUS, 830 ACPI_SBS_NOTIFY_STATUS,
682 sbs->charger_present); 831 sbs->charger_present);
832#endif
833 kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
683 } 834 }
684 if (sbs->manager_present) { 835 if (sbs->manager_present) {
685 for (id = 0; id < MAX_SBS_BAT; ++id) { 836 for (id = 0; id < MAX_SBS_BAT; ++id) {
@@ -690,10 +841,13 @@ void acpi_sbs_callback(void *context)
690 acpi_battery_read(bat); 841 acpi_battery_read(bat);
691 if (saved_battery_state == bat->present) 842 if (saved_battery_state == bat->present)
692 continue; 843 continue;
844#ifdef CONFIG_ACPI_PROC_EVENT
693 acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, 845 acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS,
694 bat->name, 846 bat->name,
695 ACPI_SBS_NOTIFY_STATUS, 847 ACPI_SBS_NOTIFY_STATUS,
696 bat->present); 848 bat->present);
849#endif
850 kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE);
697 } 851 }
698 } 852 }
699} 853}
@@ -782,45 +936,43 @@ static int acpi_sbs_resume(struct acpi_device *device)
782 return 0; 936 return 0;
783} 937}
784 938
939static struct acpi_driver acpi_sbs_driver = {
940 .name = "sbs",
941 .class = ACPI_SBS_CLASS,
942 .ids = sbs_device_ids,
943 .ops = {
944 .add = acpi_sbs_add,
945 .remove = acpi_sbs_remove,
946 .resume = acpi_sbs_resume,
947 },
948};
949
785static int __init acpi_sbs_init(void) 950static int __init acpi_sbs_init(void)
786{ 951{
787 int result = 0; 952 int result = 0;
788 953
789 if (acpi_disabled) 954 if (acpi_disabled)
790 return -ENODEV; 955 return -ENODEV;
791
792 acpi_ac_dir = acpi_lock_ac_dir(); 956 acpi_ac_dir = acpi_lock_ac_dir();
793 if (!acpi_ac_dir) { 957 if (!acpi_ac_dir)
794 ACPI_EXCEPTION((AE_INFO, AE_ERROR,
795 "acpi_lock_ac_dir() failed"));
796 return -ENODEV; 958 return -ENODEV;
797 }
798
799 acpi_battery_dir = acpi_lock_battery_dir(); 959 acpi_battery_dir = acpi_lock_battery_dir();
800 if (!acpi_battery_dir) { 960 if (!acpi_battery_dir) {
801 ACPI_EXCEPTION((AE_INFO, AE_ERROR,
802 "acpi_lock_battery_dir() failed"));
803 acpi_sbs_rmdirs(); 961 acpi_sbs_rmdirs();
804 return -ENODEV; 962 return -ENODEV;
805 } 963 }
806
807 result = acpi_bus_register_driver(&acpi_sbs_driver); 964 result = acpi_bus_register_driver(&acpi_sbs_driver);
808 if (result < 0) { 965 if (result < 0) {
809 ACPI_EXCEPTION((AE_INFO, AE_ERROR,
810 "acpi_bus_register_driver() failed"));
811 acpi_sbs_rmdirs(); 966 acpi_sbs_rmdirs();
812 return -ENODEV; 967 return -ENODEV;
813 } 968 }
814
815 return 0; 969 return 0;
816} 970}
817 971
818static void __exit acpi_sbs_exit(void) 972static void __exit acpi_sbs_exit(void)
819{ 973{
820 acpi_bus_unregister_driver(&acpi_sbs_driver); 974 acpi_bus_unregister_driver(&acpi_sbs_driver);
821
822 acpi_sbs_rmdirs(); 975 acpi_sbs_rmdirs();
823
824 return; 976 return;
825} 977}
826 978