13f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend/*
2db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy *  sbs.c - ACPI Smart Battery System Driver ($Revision: 2.0 $)
33f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *
4db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy *  Copyright (c) 2007 Alexey Starikovskiy <astarikovskiy@suse.de>
5db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy *  Copyright (c) 2005-2007 Vladimir Lebedev <vladimir.p.lebedev@intel.com>
63f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  Copyright (c) 2005 Rich Townsend <rhdt@bartol.udel.edu>
73f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *
83f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
93f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *
103f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  This program is free software; you can redistribute it and/or modify
113f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  it under the terms of the GNU General Public License as published by
123f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  the Free Software Foundation; either version 2 of the License, or (at
133f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  your option) any later version.
143f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *
153f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  This program is distributed in the hope that it will be useful, but
163f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  WITHOUT ANY WARRANTY; without even the implied warranty of
173f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
183f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  General Public License for more details.
193f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *
203f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  You should have received a copy of the GNU General Public License along
213f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  with this program; if not, write to the Free Software Foundation, Inc.,
223f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
233f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend *
243f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
253f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend */
263f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
273f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#include <linux/init.h>
285a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
293f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#include <linux/module.h>
303f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#include <linux/moduleparam.h>
313f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#include <linux/kernel.h>
3294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
33fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
343f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#include <linux/proc_fs.h>
353f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#include <linux/seq_file.h>
363f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#include <asm/uaccess.h>
3766e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy#endif
3894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
393f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#include <linux/acpi.h>
406d15702cc07503b74494dc4f1ddb15f354987b14Vladimir Lebedev#include <linux/timer.h>
41722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev#include <linux/jiffies.h>
423f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#include <linux/delay.h>
4394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy#include <linux/power_supply.h>
4494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
4591087dfa51a29b3c190e99339c4c32eb13646c51Alexey Starikovskiy#include "sbshc.h"
4691087dfa51a29b3c190e99339c4c32eb13646c51Alexey Starikovskiy
47a192a9580bcc41692be1f36b77c3b681827f566aLen Brown#define PREFIX "ACPI: "
48a192a9580bcc41692be1f36b77c3b681827f566aLen Brown
493f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#define ACPI_SBS_CLASS			"sbs"
503f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#define ACPI_AC_CLASS			"ac_adapter"
513f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#define ACPI_BATTERY_CLASS		"battery"
523f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#define ACPI_SBS_DEVICE_NAME		"Smart Battery System"
533f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#define ACPI_SBS_FILE_INFO		"info"
543f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#define ACPI_SBS_FILE_STATE		"state"
553f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#define ACPI_SBS_FILE_ALARM		"alarm"
563f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#define ACPI_BATTERY_DIR_NAME		"BAT%i"
573f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend#define ACPI_AC_DIR_NAME		"AC0"
583f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
59db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy#define ACPI_SBS_NOTIFY_STATUS		0x80
60db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy#define ACPI_SBS_NOTIFY_INFO		0x81
613f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
62db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey StarikovskiyMODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
633f86b83243d59bb50caf5938d284d22e10d082a4Rich TownsendMODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
643f86b83243d59bb50caf5938d284d22e10d082a4Rich TownsendMODULE_LICENSE("GPL");
653f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
66db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic unsigned int cache_time = 1000;
67db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiymodule_param(cache_time, uint, 0644);
68db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey StarikovskiyMODULE_PARM_DESC(cache_time, "cache time in milliseconds");
696d15702cc07503b74494dc4f1ddb15f354987b14Vladimir Lebedev
706d15702cc07503b74494dc4f1ddb15f354987b14Vladimir Lebedevextern struct proc_dir_entry *acpi_lock_ac_dir(void);
716d15702cc07503b74494dc4f1ddb15f354987b14Vladimir Lebedevextern struct proc_dir_entry *acpi_lock_battery_dir(void);
726d15702cc07503b74494dc4f1ddb15f354987b14Vladimir Lebedevextern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
736d15702cc07503b74494dc4f1ddb15f354987b14Vladimir Lebedevextern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
746d15702cc07503b74494dc4f1ddb15f354987b14Vladimir Lebedev
75db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy#define MAX_SBS_BAT			4
766d15702cc07503b74494dc4f1ddb15f354987b14Vladimir Lebedev#define ACPI_SBS_BLOCK_MAX		32
776d15702cc07503b74494dc4f1ddb15f354987b14Vladimir Lebedev
781ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renningerstatic const struct acpi_device_id sbs_device_ids[] = {
7991087dfa51a29b3c190e99339c4c32eb13646c51Alexey Starikovskiy	{"ACPI0002", 0},
801ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger	{"", 0},
811ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger};
821ba90e3a87c46500623afdc3898573e4a5ebb21bThomas RenningerMODULE_DEVICE_TABLE(acpi, sbs_device_ids);
831ba90e3a87c46500623afdc3898573e4a5ebb21bThomas Renninger
843f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstruct acpi_battery {
8594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	struct power_supply bat;
863f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	struct acpi_sbs *sbs;
87fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
8889862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	struct proc_dir_entry *proc_entry;
8966e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy#endif
90db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	unsigned long update_time;
91db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	char name[8];
9289862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	char manufacturer_name[ACPI_SBS_BLOCK_MAX];
9389862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	char device_name[ACPI_SBS_BLOCK_MAX];
9489862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	char device_chemistry[ACPI_SBS_BLOCK_MAX];
9594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	u16 alarm_capacity;
9689862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u16 full_charge_capacity;
9789862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u16 design_capacity;
9889862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u16 design_voltage;
9989862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u16 serial_number;
100db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u16 cycle_count;
101db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u16 temp_now;
10289862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u16 voltage_now;
1037faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy	s16 rate_now;
1047faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy	s16 rate_avg;
10589862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u16 capacity_now;
106db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u16 state_of_charge;
10789862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u16 state;
10889862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u16 mode;
109db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u16 spec;
11089862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u8 id;
11189862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u8 present:1;
112037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik	u8 have_sysfs_alarm:1;
1133f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend};
1143f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
115497888cf69bf607ac1fe061a6437e0a670b0022fPhil Carmody#define to_acpi_battery(x) container_of(x, struct acpi_battery, bat)
11694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
1173f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstruct acpi_sbs {
11894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	struct power_supply charger;
1193f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	struct acpi_device *device;
12091087dfa51a29b3c190e99339c4c32eb13646c51Alexey Starikovskiy	struct acpi_smb_hc *hc;
121db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	struct mutex lock;
122fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
123db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	struct proc_dir_entry *charger_entry;
12466e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy#endif
1253f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	struct acpi_battery battery[MAX_SBS_BAT];
126db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u8 batteries_supported:4;
12789862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u8 manager_present:1;
12889862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	u8 charger_present:1;
1293f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend};
1303f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
13194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy#define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger)
13294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
1331dd5c715e5b7524da8c1030f5cf1ea903e45c457Lan Tianyustatic int acpi_sbs_remove(struct acpi_device *device, int type);
1341dd5c715e5b7524da8c1030f5cf1ea903e45c457Lan Tianyustatic int acpi_battery_get_state(struct acpi_battery *battery);
1351dd5c715e5b7524da8c1030f5cf1ea903e45c457Lan Tianyu
136db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic inline int battery_scale(int log)
137722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev{
138db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	int scale = 1;
139db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	while (log--)
140db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		scale *= 10;
141db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	return scale;
142722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev}
143722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev
144db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic inline int acpi_battery_vscale(struct acpi_battery *battery)
145722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev{
146db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	return battery_scale((battery->spec & 0x0f00) >> 8);
147722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev}
148722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev
149db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic inline int acpi_battery_ipscale(struct acpi_battery *battery)
150722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev{
151db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	return battery_scale((battery->spec & 0xf000) >> 12);
152722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev}
153722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev
154db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic inline int acpi_battery_mode(struct acpi_battery *battery)
155722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev{
156db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	return (battery->mode & 0x8000);
157722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev}
1583f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
159db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic inline int acpi_battery_scale(struct acpi_battery *battery)
1603f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
161db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	return (acpi_battery_mode(battery) ? 10 : 1) *
162db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	    acpi_battery_ipscale(battery);
1633f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
1643f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
16594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiystatic int sbs_get_ac_property(struct power_supply *psy,
16694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			       enum power_supply_property psp,
16794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			       union power_supply_propval *val)
16894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy{
16994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	struct acpi_sbs *sbs = to_acpi_sbs(psy);
17094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	switch (psp) {
17194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_ONLINE:
17294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->intval = sbs->charger_present;
17394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
17494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	default:
17594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		return -EINVAL;
17694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	}
17794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	return 0;
17894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy}
17994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
18094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiystatic int acpi_battery_technology(struct acpi_battery *battery)
18194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy{
18294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	if (!strcasecmp("NiCd", battery->device_chemistry))
18394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		return POWER_SUPPLY_TECHNOLOGY_NiCd;
18494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	if (!strcasecmp("NiMH", battery->device_chemistry))
18594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		return POWER_SUPPLY_TECHNOLOGY_NiMH;
18694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	if (!strcasecmp("LION", battery->device_chemistry))
18794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		return POWER_SUPPLY_TECHNOLOGY_LION;
18894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	if (!strcasecmp("LiP", battery->device_chemistry))
18994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		return POWER_SUPPLY_TECHNOLOGY_LIPO;
19094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
19194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy}
19294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
19394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiystatic int acpi_sbs_battery_get_property(struct power_supply *psy,
19494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy					 enum power_supply_property psp,
19594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy					 union power_supply_propval *val)
19694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy{
19794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	struct acpi_battery *battery = to_acpi_battery(psy);
19894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
19994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	if ((!battery->present) && psp != POWER_SUPPLY_PROP_PRESENT)
20094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		return -ENODEV;
2011dd5c715e5b7524da8c1030f5cf1ea903e45c457Lan Tianyu
2021dd5c715e5b7524da8c1030f5cf1ea903e45c457Lan Tianyu	acpi_battery_get_state(battery);
20394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	switch (psp) {
20494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_STATUS:
2057faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy		if (battery->rate_now < 0)
20694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
2077faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy		else if (battery->rate_now > 0)
20894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			val->intval = POWER_SUPPLY_STATUS_CHARGING;
20994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		else
21094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			val->intval = POWER_SUPPLY_STATUS_FULL;
21194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
21294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_PRESENT:
21394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->intval = battery->present;
21494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
21594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_TECHNOLOGY:
21694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->intval = acpi_battery_technology(battery);
21794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
21816698857fba1b10af4890055272975adf5686e83Alexey Starikovskiy	case POWER_SUPPLY_PROP_CYCLE_COUNT:
21916698857fba1b10af4890055272975adf5686e83Alexey Starikovskiy		val->intval = battery->cycle_count;
22016698857fba1b10af4890055272975adf5686e83Alexey Starikovskiy		break;
22194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
22294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->intval = battery->design_voltage *
22394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			acpi_battery_vscale(battery) * 1000;
22494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
22594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
22694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->intval = battery->voltage_now *
22794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy				acpi_battery_vscale(battery) * 1000;
22894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
22994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_CURRENT_NOW:
2307faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy	case POWER_SUPPLY_PROP_POWER_NOW:
2317faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy		val->intval = abs(battery->rate_now) *
23294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy				acpi_battery_ipscale(battery) * 1000;
233e4108292cc5b5ca07abc83af31a78338362810caLan Tianyu		val->intval *= (acpi_battery_mode(battery)) ?
234e4108292cc5b5ca07abc83af31a78338362810caLan Tianyu				(battery->voltage_now *
235e4108292cc5b5ca07abc83af31a78338362810caLan Tianyu				acpi_battery_vscale(battery) / 1000) : 1;
23694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
23794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_CURRENT_AVG:
2387faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy	case POWER_SUPPLY_PROP_POWER_AVG:
2397faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy		val->intval = abs(battery->rate_avg) *
24094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy				acpi_battery_ipscale(battery) * 1000;
241e4108292cc5b5ca07abc83af31a78338362810caLan Tianyu		val->intval *= (acpi_battery_mode(battery)) ?
242e4108292cc5b5ca07abc83af31a78338362810caLan Tianyu				(battery->voltage_now *
243e4108292cc5b5ca07abc83af31a78338362810caLan Tianyu				acpi_battery_vscale(battery) / 1000) : 1;
24494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
24594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_CAPACITY:
24694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->intval = battery->state_of_charge;
24794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
24894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
24994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
25094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->intval = battery->design_capacity *
25194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			acpi_battery_scale(battery) * 1000;
25294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
25394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_CHARGE_FULL:
25494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_ENERGY_FULL:
25594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->intval = battery->full_charge_capacity *
25694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			acpi_battery_scale(battery) * 1000;
25794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
25894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_CHARGE_NOW:
25994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_ENERGY_NOW:
26094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->intval = battery->capacity_now *
26194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy				acpi_battery_scale(battery) * 1000;
26294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
26394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_TEMP:
26494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->intval = battery->temp_now - 2730;	// dK -> dC
26594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
26694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_MODEL_NAME:
26794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->strval = battery->device_name;
26894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
26994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	case POWER_SUPPLY_PROP_MANUFACTURER:
27094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		val->strval = battery->manufacturer_name;
27194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		break;
27294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	default:
27394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		return -EINVAL;
27494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	}
27594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	return 0;
27694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy}
27794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
27894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiystatic enum power_supply_property sbs_ac_props[] = {
27994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_ONLINE,
28094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy};
28194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
28294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiystatic enum power_supply_property sbs_charge_battery_props[] = {
28394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_STATUS,
28494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_PRESENT,
28594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_TECHNOLOGY,
28616698857fba1b10af4890055272975adf5686e83Alexey Starikovskiy	POWER_SUPPLY_PROP_CYCLE_COUNT,
28794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
28894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_VOLTAGE_NOW,
28994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_CURRENT_NOW,
29094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_CURRENT_AVG,
29194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_CAPACITY,
29294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
29394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_CHARGE_FULL,
29494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_CHARGE_NOW,
29594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_TEMP,
29694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_MODEL_NAME,
29794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_MANUFACTURER,
29894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy};
29994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
30094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiystatic enum power_supply_property sbs_energy_battery_props[] = {
30194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_STATUS,
30294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_PRESENT,
30394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_TECHNOLOGY,
30494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
30594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_VOLTAGE_NOW,
30694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_CURRENT_NOW,
30794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_CURRENT_AVG,
3087faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy	POWER_SUPPLY_PROP_POWER_NOW,
3097faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy	POWER_SUPPLY_PROP_POWER_AVG,
31094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_CAPACITY,
31194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
31294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_ENERGY_FULL,
31394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_ENERGY_NOW,
31494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_TEMP,
31594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_MODEL_NAME,
31694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	POWER_SUPPLY_PROP_MANUFACTURER,
31794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy};
3187faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy
31994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
320db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy/* --------------------------------------------------------------------------
321db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy                            Smart Battery System Management
322db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy   -------------------------------------------------------------------------- */
3233f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
324db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystruct acpi_battery_reader {
325db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u8 command;		/* command for battery */
326db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u8 mode;		/* word or block? */
327db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	size_t offset;		/* offset inside struct acpi_sbs_battery */
328db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy};
3293f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
330db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic struct acpi_battery_reader info_readers[] = {
331db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x01, SMBUS_READ_WORD, offsetof(struct acpi_battery, alarm_capacity)},
332db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x03, SMBUS_READ_WORD, offsetof(struct acpi_battery, mode)},
333db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x10, SMBUS_READ_WORD, offsetof(struct acpi_battery, full_charge_capacity)},
334db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x17, SMBUS_READ_WORD, offsetof(struct acpi_battery, cycle_count)},
335db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x18, SMBUS_READ_WORD, offsetof(struct acpi_battery, design_capacity)},
336db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x19, SMBUS_READ_WORD, offsetof(struct acpi_battery, design_voltage)},
337db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x1a, SMBUS_READ_WORD, offsetof(struct acpi_battery, spec)},
338db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x1c, SMBUS_READ_WORD, offsetof(struct acpi_battery, serial_number)},
339db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x20, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, manufacturer_name)},
340db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x21, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, device_name)},
341db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x22, SMBUS_READ_BLOCK, offsetof(struct acpi_battery, device_chemistry)},
342db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy};
3433f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
344db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic struct acpi_battery_reader state_readers[] = {
345db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x08, SMBUS_READ_WORD, offsetof(struct acpi_battery, temp_now)},
346db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x09, SMBUS_READ_WORD, offsetof(struct acpi_battery, voltage_now)},
3477faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy	{0x0a, SMBUS_READ_WORD, offsetof(struct acpi_battery, rate_now)},
3487faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy	{0x0b, SMBUS_READ_WORD, offsetof(struct acpi_battery, rate_avg)},
349db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x0f, SMBUS_READ_WORD, offsetof(struct acpi_battery, capacity_now)},
350db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x0e, SMBUS_READ_WORD, offsetof(struct acpi_battery, state_of_charge)},
351db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	{0x16, SMBUS_READ_WORD, offsetof(struct acpi_battery, state)},
352db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy};
3533f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
354db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic int acpi_manager_get_info(struct acpi_sbs *sbs)
3553f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
3563f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	int result = 0;
357db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u16 battery_system_info;
3583f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
359db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER,
36094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy				 0x04, (u8 *)&battery_system_info);
361db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (!result)
362db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		sbs->batteries_supported = battery_system_info & 0x000f;
363635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return result;
3643f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
3653f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
3663f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_battery_get_info(struct acpi_battery *battery)
3673f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
368db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	int i, result = 0;
3693f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
370db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	for (i = 0; i < ARRAY_SIZE(info_readers); ++i) {
37194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		result = acpi_smbus_read(battery->sbs->hc,
37294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy					 info_readers[i].mode,
37394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy					 ACPI_SBS_BATTERY,
37494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy					 info_readers[i].command,
37594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy					 (u8 *) battery +
37694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy						info_readers[i].offset);
377db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		if (result)
378db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			break;
3793f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
380635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return result;
3813f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
3823f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
3833f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_battery_get_state(struct acpi_battery *battery)
3843f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
385db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	int i, result = 0;
3863f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
38794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	if (battery->update_time &&
38894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	    time_before(jiffies, battery->update_time +
389db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				msecs_to_jiffies(cache_time)))
390db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		return 0;
391db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	for (i = 0; i < ARRAY_SIZE(state_readers); ++i) {
392db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		result = acpi_smbus_read(battery->sbs->hc,
393db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy					 state_readers[i].mode,
394db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy					 ACPI_SBS_BATTERY,
395db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy					 state_readers[i].command,
396db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				         (u8 *)battery +
397db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy						state_readers[i].offset);
398db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		if (result)
3993f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend			goto end;
4003f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
4013f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend      end:
402db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	battery->update_time = jiffies;
403635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return result;
4043f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
4053f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
406db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic int acpi_battery_get_alarm(struct acpi_battery *battery)
4073f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
408db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD,
409db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				 ACPI_SBS_BATTERY, 0x01,
41094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy				 (u8 *)&battery->alarm_capacity);
4113f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
4123f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
413db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic int acpi_battery_set_alarm(struct acpi_battery *battery)
4143f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
415db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	struct acpi_sbs *sbs = battery->sbs;
41694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	u16 value, sel = 1 << (battery->id + 12);
41794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
41894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	int ret;
41994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
4203f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
421db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (sbs->manager_present) {
42294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		ret = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER,
423db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				0x01, (u8 *)&value);
42494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		if (ret)
42594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			goto end;
42694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		if ((value & 0xf000) != sel) {
42794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			value &= 0x0fff;
42894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			value |= sel;
42994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD,
43094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy					 ACPI_SBS_MANAGER,
43194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy					 0x01, (u8 *)&value, 2);
43294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		if (ret)
43394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			goto end;
43494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		}
4353f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
43694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY,
43794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy				0x01, (u8 *)&battery->alarm_capacity, 2);
43894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy      end:
43994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	return ret;
4403f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
4413f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
4423f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_ac_get_present(struct acpi_sbs *sbs)
4433f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
444db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	int result;
445db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u16 status;
4463f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
447db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_CHARGER,
448db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				 0x13, (u8 *) & status);
449db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (!result)
450db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		sbs->charger_present = (status >> 15) & 0x1;
451635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return result;
4523f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
4533f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
4548bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiystatic ssize_t acpi_battery_alarm_show(struct device *dev,
4558bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy					struct device_attribute *attr,
4568bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy					char *buf)
4578bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy{
4588bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
4598bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy	acpi_battery_get_alarm(battery);
4608bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy	return sprintf(buf, "%d\n", battery->alarm_capacity *
4618bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy				acpi_battery_scale(battery) * 1000);
4628bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy}
4638bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy
4648bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiystatic ssize_t acpi_battery_alarm_store(struct device *dev,
4658bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy					struct device_attribute *attr,
4668bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy					const char *buf, size_t count)
4678bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy{
4688bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy	unsigned long x;
4698bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
4708bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy	if (sscanf(buf, "%ld\n", &x) == 1)
4718bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy		battery->alarm_capacity = x /
4728bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy			(1000 * acpi_battery_scale(battery));
4738bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy	if (battery->present)
4748bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy		acpi_battery_set_alarm(battery);
4758bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy	return count;
4768bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy}
4778bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy
4788bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiystatic struct device_attribute alarm_attr = {
47901e8ef11bc1a74e65678ed55795f59266d4add01Parag Warudkar	.attr = {.name = "alarm", .mode = 0644},
4808bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy	.show = acpi_battery_alarm_show,
4818bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy	.store = acpi_battery_alarm_store,
4828bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy};
4838bd955320661cfd03ab8d5574d96aa684acd38f6Alexey Starikovskiy
4843f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend/* --------------------------------------------------------------------------
4853f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend                              FS Interface (/proc/acpi)
4863f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend   -------------------------------------------------------------------------- */
4873f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
488fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
4893f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend/* Generic Routines */
4903f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int
491db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiyacpi_sbs_add_fs(struct proc_dir_entry **dir,
49294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		struct proc_dir_entry *parent_dir,
49394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		char *dir_name,
494070d8eb1f6b789206486ea6a4a1bb7745d86d314Jan Engelhardt		const struct file_operations *info_fops,
495070d8eb1f6b789206486ea6a4a1bb7745d86d314Jan Engelhardt		const struct file_operations *state_fops,
496070d8eb1f6b789206486ea6a4a1bb7745d86d314Jan Engelhardt		const struct file_operations *alarm_fops, void *data)
4973f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
4986d855fcdd24d2491455527c4999b4d04363f1980Zhang Rui	printk(KERN_WARNING PREFIX "Deprecated procfs I/F for SBS is loaded,"
4996d855fcdd24d2491455527c4999b4d04363f1980Zhang Rui			" please retry with CONFIG_ACPI_PROCFS_POWER cleared\n");
5003f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	if (!*dir) {
5013f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		*dir = proc_mkdir(dir_name, parent_dir);
5023f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		if (!*dir) {
503635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown			return -ENODEV;
5043f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		}
5053f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
5063f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
5073f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	/* 'info' [R] */
508cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev	if (info_fops)
509cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev		proc_create_data(ACPI_SBS_FILE_INFO, S_IRUGO, *dir,
510cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev				 info_fops, data);
5113f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
5123f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	/* 'state' [R] */
513cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev	if (state_fops)
514cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev		proc_create_data(ACPI_SBS_FILE_STATE, S_IRUGO, *dir,
515cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev				 state_fops, data);
5163f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
5173f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	/* 'alarm' [R/W] */
518cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev	if (alarm_fops)
519cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev		proc_create_data(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir,
520cf7acfab032ff262f42954328cdfd20a5d9aaaacDenis V. Lunev				 alarm_fops, data);
521635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return 0;
5223f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
5233f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
5243f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic void
525db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiyacpi_sbs_remove_fs(struct proc_dir_entry **dir,
5263f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend			   struct proc_dir_entry *parent_dir)
5273f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
5283f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	if (*dir) {
5293f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		remove_proc_entry(ACPI_SBS_FILE_INFO, *dir);
5303f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		remove_proc_entry(ACPI_SBS_FILE_STATE, *dir);
5313f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		remove_proc_entry(ACPI_SBS_FILE_ALARM, *dir);
5323f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		remove_proc_entry((*dir)->name, parent_dir);
5333f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		*dir = NULL;
5343f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
5353f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
5363f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
5373f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend/* Smart Battery Interface */
5383f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic struct proc_dir_entry *acpi_battery_dir = NULL;
5393f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
540db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic inline char *acpi_battery_units(struct acpi_battery *battery)
541db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy{
5425a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy	return acpi_battery_mode(battery) ? " mW" : " mA";
543db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy}
544db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy
545db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy
5463f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_battery_read_info(struct seq_file *seq, void *offset)
5473f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
54850dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	struct acpi_battery *battery = seq->private;
549722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	struct acpi_sbs *sbs = battery->sbs;
5503f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	int result = 0;
5513f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
552db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_lock(&sbs->lock);
5533f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
554db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	seq_printf(seq, "present:                 %s\n",
555db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   (battery->present) ? "yes" : "no");
556db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (!battery->present)
557722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		goto end;
5583f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
5595a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy	seq_printf(seq, "design capacity:         %i%sh\n",
560db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   battery->design_capacity * acpi_battery_scale(battery),
561db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   acpi_battery_units(battery));
5625a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy	seq_printf(seq, "last full capacity:      %i%sh\n",
563db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   battery->full_charge_capacity * acpi_battery_scale(battery),
564db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   acpi_battery_units(battery));
5653f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "battery technology:      rechargeable\n");
5663f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "design voltage:          %i mV\n",
567db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   battery->design_voltage * acpi_battery_vscale(battery));
5683f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "design capacity warning: unknown\n");
5693f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "design capacity low:     unknown\n");
57016698857fba1b10af4890055272975adf5686e83Alexey Starikovskiy	seq_printf(seq, "cycle count:		  %i\n", battery->cycle_count);
5713f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "capacity granularity 1:  unknown\n");
5723f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "capacity granularity 2:  unknown\n");
573db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	seq_printf(seq, "model number:            %s\n", battery->device_name);
5743f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "serial number:           %i\n",
57589862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy		   battery->serial_number);
5763f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "battery type:            %s\n",
57789862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy		   battery->device_chemistry);
5783f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "OEM info:                %s\n",
57989862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy		   battery->manufacturer_name);
5803f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend      end:
581db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_unlock(&sbs->lock);
582635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return result;
5833f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
5843f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
5853f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
5863f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
5873f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	return single_open(file, acpi_battery_read_info, PDE(inode)->data);
5883f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
5893f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
5903f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_battery_read_state(struct seq_file *seq, void *offset)
5913f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
592722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	struct acpi_battery *battery = seq->private;
593722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	struct acpi_sbs *sbs = battery->sbs;
5945a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy	int rate;
5953f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
596db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_lock(&sbs->lock);
597db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	seq_printf(seq, "present:                 %s\n",
598db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   (battery->present) ? "yes" : "no");
599db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (!battery->present)
6003f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		goto end;
6013f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
602db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	acpi_battery_get_state(battery);
603db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	seq_printf(seq, "capacity state:          %s\n",
604db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   (battery->state & 0x0010) ? "critical" : "ok");
605db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	seq_printf(seq, "charging state:          %s\n",
6067faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy		   (battery->rate_now < 0) ? "discharging" :
6077faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy		   ((battery->rate_now > 0) ? "charging" : "charged"));
6087faa144a518c456e2057918f030f50100144ccc6Alexey Starikovskiy	rate = abs(battery->rate_now) * acpi_battery_ipscale(battery);
6095a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy	rate *= (acpi_battery_mode(battery))?(battery->voltage_now *
6105a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy			acpi_battery_vscale(battery)/1000):1;
6115a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy	seq_printf(seq, "present rate:            %d%s\n", rate,
6125a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy		   acpi_battery_units(battery));
6135a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy	seq_printf(seq, "remaining capacity:      %i%sh\n",
614db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   battery->capacity_now * acpi_battery_scale(battery),
615db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   acpi_battery_units(battery));
6163f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "present voltage:         %i mV\n",
617db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		   battery->voltage_now * acpi_battery_vscale(battery));
6183f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
6193f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend      end:
620db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_unlock(&sbs->lock);
6215a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy	return 0;
6223f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
6233f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
6243f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
6253f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
6263f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	return single_open(file, acpi_battery_read_state, PDE(inode)->data);
6273f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
6283f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
6293f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
6303f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
63150dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	struct acpi_battery *battery = seq->private;
632722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	struct acpi_sbs *sbs = battery->sbs;
6333f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	int result = 0;
6343f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
635db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_lock(&sbs->lock);
6363f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
63789862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	if (!battery->present) {
6383f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		seq_printf(seq, "present:                 no\n");
6393f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		goto end;
6403f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
6413f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
642db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	acpi_battery_get_alarm(battery);
6433f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "alarm:                   ");
644db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (battery->alarm_capacity)
6455a21e4fe587ebb793bf3a1c02755f8a845170328Alexey Starikovskiy		seq_printf(seq, "%i%sh\n",
646db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			   battery->alarm_capacity *
647db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			   acpi_battery_scale(battery),
648db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			   acpi_battery_units(battery));
649db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	else
6503f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		seq_printf(seq, "disabled\n");
6513f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend      end:
652db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_unlock(&sbs->lock);
653635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return result;
6543f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
6553f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
6563f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic ssize_t
6573f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendacpi_battery_write_alarm(struct file *file, const char __user * buffer,
6583f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend			 size_t count, loff_t * ppos)
6593f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
66050dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	struct seq_file *seq = file->private_data;
66150dd096973f1d95aa03c6a6d9e148d706b62b68eJan Engelhardt	struct acpi_battery *battery = seq->private;
662722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	struct acpi_sbs *sbs = battery->sbs;
6633f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	char alarm_string[12] = { '\0' };
664db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	int result = 0;
665db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_lock(&sbs->lock);
66689862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	if (!battery->present) {
6673f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		result = -ENODEV;
6683f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		goto end;
6693f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
6703f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	if (count > sizeof(alarm_string) - 1) {
6713f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		result = -EINVAL;
6723f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		goto end;
6733f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
6743f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	if (copy_from_user(alarm_string, buffer, count)) {
6753f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		result = -EFAULT;
6763f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		goto end;
6773f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
6783f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	alarm_string[count] = 0;
67994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0) /
68094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy					acpi_battery_scale(battery);
681db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	acpi_battery_set_alarm(battery);
6823f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend      end:
683db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_unlock(&sbs->lock);
684db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (result)
685635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown		return result;
686db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	return count;
6873f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
6883f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
6893f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
6903f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
6913f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
6923f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
6933f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
694070d8eb1f6b789206486ea6a4a1bb7745d86d314Jan Engelhardtstatic const struct file_operations acpi_battery_info_fops = {
6953f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.open = acpi_battery_info_open_fs,
6963f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.read = seq_read,
6973f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.llseek = seq_lseek,
6983f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.release = single_release,
6993f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.owner = THIS_MODULE,
7003f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend};
7013f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
702070d8eb1f6b789206486ea6a4a1bb7745d86d314Jan Engelhardtstatic const struct file_operations acpi_battery_state_fops = {
7033f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.open = acpi_battery_state_open_fs,
7043f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.read = seq_read,
7053f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.llseek = seq_lseek,
7063f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.release = single_release,
7073f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.owner = THIS_MODULE,
7083f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend};
7093f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
710070d8eb1f6b789206486ea6a4a1bb7745d86d314Jan Engelhardtstatic const struct file_operations acpi_battery_alarm_fops = {
7113f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.open = acpi_battery_alarm_open_fs,
7123f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.read = seq_read,
7133f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.write = acpi_battery_write_alarm,
7143f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.llseek = seq_lseek,
7153f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.release = single_release,
7163f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.owner = THIS_MODULE,
7173f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend};
7183f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
7193f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend/* Legacy AC Adapter Interface */
7203f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
7213f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic struct proc_dir_entry *acpi_ac_dir = NULL;
7223f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
7233f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_ac_read_state(struct seq_file *seq, void *offset)
7243f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
7253f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
726db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	struct acpi_sbs *sbs = seq->private;
7273f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
728db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_lock(&sbs->lock);
7293f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
7303f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	seq_printf(seq, "state:                   %s\n",
73189862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy		   sbs->charger_present ? "on-line" : "off-line");
7323f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
733db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_unlock(&sbs->lock);
734635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return 0;
7353f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
7363f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
7373f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_ac_state_open_fs(struct inode *inode, struct file *file)
7383f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
7393f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	return single_open(file, acpi_ac_read_state, PDE(inode)->data);
7403f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
7413f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
742070d8eb1f6b789206486ea6a4a1bb7745d86d314Jan Engelhardtstatic const struct file_operations acpi_ac_state_fops = {
7433f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.open = acpi_ac_state_open_fs,
7443f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.read = seq_read,
7453f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.llseek = seq_lseek,
7463f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.release = single_release,
7473f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	.owner = THIS_MODULE,
7483f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend};
7493f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
75066e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy#endif
75166e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy
7523f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend/* --------------------------------------------------------------------------
7533f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend                                 Driver Interface
7543f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend   -------------------------------------------------------------------------- */
755db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic int acpi_battery_read(struct acpi_battery *battery)
7563f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
757db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	int result = 0, saved_present = battery->present;
758db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u16 state;
7593f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
760db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (battery->sbs->manager_present) {
761db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		result = acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD,
762db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				ACPI_SBS_MANAGER, 0x01, (u8 *)&state);
763db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		if (!result)
764db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			battery->present = state & (1 << battery->id);
765db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		state &= 0x0fff;
766db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		state |= 1 << (battery->id + 12);
767db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		acpi_smbus_write(battery->sbs->hc, SMBUS_WRITE_WORD,
768db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				  ACPI_SBS_MANAGER, 0x01, (u8 *)&state, 2);
769db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	} else if (battery->id == 0)
770db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		battery->present = 1;
771db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (result || !battery->present)
772db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		return result;
7733f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
774db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (saved_present != battery->present) {
775db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		battery->update_time = 0;
776db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		result = acpi_battery_get_info(battery);
777db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		if (result)
778db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			return result;
779db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	}
780db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	result = acpi_battery_get_state(battery);
781db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	return result;
782db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy}
7833f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
78494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy/* Smart Battery */
785db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic int acpi_battery_add(struct acpi_sbs *sbs, int id)
786db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy{
787db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	struct acpi_battery *battery = &sbs->battery[id];
78894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	int result;
78994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
7903f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	battery->id = id;
7913f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	battery->sbs = sbs;
792db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	result = acpi_battery_read(battery);
793db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (result)
794db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		return result;
7953f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
796db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	sprintf(battery->name, ACPI_BATTERY_DIR_NAME, id);
797fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
798db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	acpi_sbs_add_fs(&battery->proc_entry, acpi_battery_dir,
799db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			battery->name, &acpi_battery_info_fops,
800db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			&acpi_battery_state_fops, &acpi_battery_alarm_fops,
801db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			battery);
80266e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy#endif
80394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	battery->bat.name = battery->name;
80494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
80594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	if (!acpi_battery_mode(battery)) {
80694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		battery->bat.properties = sbs_charge_battery_props;
80794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		battery->bat.num_properties =
80894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		    ARRAY_SIZE(sbs_charge_battery_props);
80994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	} else {
81094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		battery->bat.properties = sbs_energy_battery_props;
81194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		battery->bat.num_properties =
81294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		    ARRAY_SIZE(sbs_energy_battery_props);
81394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	}
81494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	battery->bat.get_property = acpi_sbs_battery_get_property;
81594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	result = power_supply_register(&sbs->device->dev, &battery->bat);
816037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik	if (result)
817037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik		goto end;
818037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik	result = device_create_file(battery->bat.dev, &alarm_attr);
819037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik	if (result)
820037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik		goto end;
821037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik	battery->have_sysfs_alarm = 1;
822037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik      end:
823722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
824db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	       ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
825bbafbecb24190959d77a8fee7bd23798b81e25c2Alexey Starikovskiy	       battery->name, battery->present ? "present" : "absent");
826635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return result;
8273f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
8283f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
8293f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic void acpi_battery_remove(struct acpi_sbs *sbs, int id)
8303f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
831037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik	struct acpi_battery *battery = &sbs->battery[id];
832c19bdb6126a5e1f43b4a4fc3c4b09c926667e5efRakib Mullick
833037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik	if (battery->bat.dev) {
834037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik		if (battery->have_sysfs_alarm)
835037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik			device_remove_file(battery->bat.dev, &alarm_attr);
836037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik		power_supply_unregister(&battery->bat);
8373f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
838c2e46d2e2a8e6ed17fac6154ac7e5fa7fe4efb28Len Brown#ifdef CONFIG_ACPI_PROCFS_POWER
839037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik	if (battery->proc_entry)
840037cbc63fd83162a8ee0c69680207ce4609adbeaJeff Garzik		acpi_sbs_remove_fs(&battery->proc_entry, acpi_battery_dir);
84166e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy#endif
8423f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
8433f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
844db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic int acpi_charger_add(struct acpi_sbs *sbs)
8453f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
8463f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	int result;
8473f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
8483f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	result = acpi_ac_get_present(sbs);
849db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (result)
8503f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		goto end;
851fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
852db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	result = acpi_sbs_add_fs(&sbs->charger_entry, acpi_ac_dir,
853db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				 ACPI_AC_DIR_NAME, NULL,
854db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				 &acpi_ac_state_fops, NULL, sbs);
855db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (result)
8563f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		goto end;
85766e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy#endif
85894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	sbs->charger.name = "sbs-charger";
85994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	sbs->charger.type = POWER_SUPPLY_TYPE_MAINS;
86094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	sbs->charger.properties = sbs_ac_props;
86194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	sbs->charger.num_properties = ARRAY_SIZE(sbs_ac_props);
86294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	sbs->charger.get_property = sbs_get_ac_property;
86394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	power_supply_register(&sbs->device->dev, &sbs->charger);
864722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
865722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	       ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
86689862e3be1ba387c738fc2c3a5875cfd7e51c5a8Alexey Starikovskiy	       ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line");
8673f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend      end:
868635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return result;
8693f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
8703f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
871db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiystatic void acpi_charger_remove(struct acpi_sbs *sbs)
8723f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
87394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	if (sbs->charger.dev)
87494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		power_supply_unregister(&sbs->charger);
875fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
876db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (sbs->charger_entry)
877db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir);
87866e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy#endif
8793f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
8803f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
881e5685b9d35c2cc0a98425b05df30cb837dd1e632Adrian Bunkstatic void acpi_sbs_callback(void *context)
8823f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
883db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	int id;
884db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	struct acpi_sbs *sbs = context;
885db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	struct acpi_battery *bat;
886db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u8 saved_charger_state = sbs->charger_present;
887db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	u8 saved_battery_state;
888db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	acpi_ac_get_present(sbs);
889db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (sbs->charger_present != saved_charger_state) {
89094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy#ifdef CONFIG_ACPI_PROC_EVENT
891db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME,
892db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy					      ACPI_SBS_NOTIFY_STATUS,
893db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy					      sbs->charger_present);
89494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy#endif
89594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE);
8963f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
897db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (sbs->manager_present) {
898db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		for (id = 0; id < MAX_SBS_BAT; ++id) {
899db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			if (!(sbs->batteries_supported & (1 << id)))
900db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				continue;
901db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			bat = &sbs->battery[id];
902db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			saved_battery_state = bat->present;
903db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			acpi_battery_read(bat);
904db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			if (saved_battery_state == bat->present)
905db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				continue;
90694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy#ifdef CONFIG_ACPI_PROC_EVENT
907db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS,
908db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy						      bat->name,
909db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy						      ACPI_SBS_NOTIFY_STATUS,
910db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy						      bat->present);
91194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy#endif
91294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy			kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE);
9133f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		}
9143f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
9153f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
9163f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
9173f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int acpi_sbs_add(struct acpi_device *device)
9183f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
919db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	struct acpi_sbs *sbs;
920db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	int result = 0;
9216d15702cc07503b74494dc4f1ddb15f354987b14Vladimir Lebedev	int id;
9223f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
92336bcbec7ce21e2e8b3143b11a05747330abeca70Burman Yan	sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
9243f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	if (!sbs) {
925722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		result = -ENOMEM;
926722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		goto end;
9273f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
9283f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
929db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_init(&sbs->lock);
930722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev
93191087dfa51a29b3c190e99339c4c32eb13646c51Alexey Starikovskiy	sbs->hc = acpi_driver_data(device->parent);
932db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	sbs->device = device;
9333f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
9343f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
935db89b4f0dbab837d0f3de2c3e9427a8d5393afa3Pavel Machek	device->driver_data = sbs;
9363f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
937db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	result = acpi_charger_add(sbs);
938722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	if (result)
939722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		goto end;
9403f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
941db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	result = acpi_manager_get_info(sbs);
942db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (!result) {
943db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		sbs->manager_present = 1;
944db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		for (id = 0; id < MAX_SBS_BAT; ++id)
945db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy			if ((sbs->batteries_supported & (1 << id)))
946db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy				acpi_battery_add(sbs, id);
947db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	} else
948db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		acpi_battery_add(sbs, 0);
949db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs);
9503f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend      end:
951db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (result)
952db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy		acpi_sbs_remove(device, 0);
953635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return result;
9543f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
9553f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
956722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedevstatic int acpi_sbs_remove(struct acpi_device *device, int type)
9573f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
958cece901481bafbf14de8cbd3a89ae869ea881055Len Brown	struct acpi_sbs *sbs;
9593f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	int id;
9603f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
961db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (!device)
962963497c12acb4d43caa9751b9291b014eea51a1aLebedev, Vladimir P		return -EINVAL;
963722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	sbs = acpi_driver_data(device);
964db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	if (!sbs)
965635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown		return -EINVAL;
966db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_lock(&sbs->lock);
967db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	acpi_smbus_unregister_callback(sbs->hc);
968db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	for (id = 0; id < MAX_SBS_BAT; ++id)
9693f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend		acpi_battery_remove(sbs, id);
970db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	acpi_charger_remove(sbs);
971db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_unlock(&sbs->lock);
972db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	mutex_destroy(&sbs->lock);
9733f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	kfree(sbs);
974635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return 0;
9753f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
9763f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
977722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedevstatic void acpi_sbs_rmdirs(void)
978722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev{
979fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
980722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	if (acpi_ac_dir) {
981722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		acpi_unlock_ac_dir(acpi_ac_dir);
982722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		acpi_ac_dir = NULL;
983722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	}
984722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	if (acpi_battery_dir) {
985722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		acpi_unlock_battery_dir(acpi_battery_dir);
986722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		acpi_battery_dir = NULL;
987722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	}
98866e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy#endif
989722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev}
990722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev
991722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedevstatic int acpi_sbs_resume(struct acpi_device *device)
992722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev{
993722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	struct acpi_sbs *sbs;
994722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	if (!device)
995722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		return -EINVAL;
996722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	sbs = device->driver_data;
997db1c291af7ad748777371f25b9ff92e3e5aba38eAlexey Starikovskiy	acpi_sbs_callback(sbs);
998722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	return 0;
999722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev}
1000722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev
100194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiystatic struct acpi_driver acpi_sbs_driver = {
100294f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	.name = "sbs",
100394f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	.class = ACPI_SBS_CLASS,
100494f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	.ids = sbs_device_ids,
100594f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	.ops = {
100694f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		.add = acpi_sbs_add,
100794f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		.remove = acpi_sbs_remove,
100894f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		.resume = acpi_sbs_resume,
100994f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy		},
101094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy};
101194f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy
10123f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic int __init acpi_sbs_init(void)
10133f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
10143f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	int result = 0;
10153f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
1016b20d2aeb0ad322cbe7fd9120acae6118231b17a3Len Brown	if (acpi_disabled)
1017b20d2aeb0ad322cbe7fd9120acae6118231b17a3Len Brown		return -ENODEV;
1018fdcedbba2f98c94bfbac9f6e712ab765f997b8dcAlexey Starikovskiy#ifdef CONFIG_ACPI_PROCFS_POWER
10193f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	acpi_ac_dir = acpi_lock_ac_dir();
102094f6c0860139da9219255b8ff45ad42117dda859Alexey Starikovskiy	if (!acpi_ac_dir)
1021635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown		return -ENODEV;
10223f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	acpi_battery_dir = acpi_lock_battery_dir();
10233f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	if (!acpi_battery_dir) {
1024722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		acpi_sbs_rmdirs();
1025635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown		return -ENODEV;
10263f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
102766e4b72bfa7347fd1017b9b82dce77a410f2e4a1Alexey Starikovskiy#endif
10283f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	result = acpi_bus_register_driver(&acpi_sbs_driver);
10293f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	if (result < 0) {
1030722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev		acpi_sbs_rmdirs();
1031635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown		return -ENODEV;
10323f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	}
1033635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return 0;
10343f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
10353f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
10363f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendstatic void __exit acpi_sbs_exit(void)
10373f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend{
10383f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend	acpi_bus_unregister_driver(&acpi_sbs_driver);
1039722062334b972c31a3b83dbf7e9b5a58bb2707ddVladimir Lebedev	acpi_sbs_rmdirs();
1040635227ee89929a6e2920fc8aa1cd48f7225d3d93Len Brown	return;
10413f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend}
10423f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsend
10433f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendmodule_init(acpi_sbs_init);
10443f86b83243d59bb50caf5938d284d22e10d082a4Rich Townsendmodule_exit(acpi_sbs_exit);
1045