Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d15702c authored by Vladimir Lebedev's avatar Vladimir Lebedev Committed by Len Brown
Browse files

ACPI: sbs: use EC rather than I2C



SBS is based on EC function(ec_read/ec_write).
Not needed using of I2C structures/functions ... is removed.
SBS does not depend on I2C now.

Signed-off-by: default avatarVladimir Lebedev <vladimir.p.lebedev@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 8559840c
Loading
Loading
Loading
Loading
+287 −278
Original line number Original line Diff line number Diff line
@@ -30,30 +30,9 @@
#include <linux/seq_file.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <linux/acpi.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/delay.h>


#include "i2c_ec.h"

#define	DEF_CAPACITY_UNIT	3
#define	MAH_CAPACITY_UNIT	1
#define	MWH_CAPACITY_UNIT	2
#define	CAPACITY_UNIT		DEF_CAPACITY_UNIT

#define	REQUEST_UPDATE_MODE	1
#define	QUEUE_UPDATE_MODE	2

#define	DATA_TYPE_COMMON	0
#define	DATA_TYPE_INFO		1
#define	DATA_TYPE_STATE		2
#define	DATA_TYPE_ALARM		3
#define	DATA_TYPE_AC_STATE	4

extern struct proc_dir_entry *acpi_lock_ac_dir(void);
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);

#define ACPI_SBS_COMPONENT		0x00080000
#define ACPI_SBS_COMPONENT		0x00080000
#define ACPI_SBS_CLASS			"sbs"
#define ACPI_SBS_CLASS			"sbs"
#define ACPI_AC_CLASS			"ac_adapter"
#define ACPI_AC_CLASS			"ac_adapter"
@@ -74,15 +53,62 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);


#define _COMPONENT			ACPI_SBS_COMPONENT
#define _COMPONENT			ACPI_SBS_COMPONENT


#define	MAX_SBS_BAT			4
#define	MAX_SMBUS_ERR			1

ACPI_MODULE_NAME("sbs");
ACPI_MODULE_NAME("sbs");


MODULE_AUTHOR("Rich Townsend");
MODULE_AUTHOR("Rich Townsend");
MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");


#define	xmsleep(t)	msleep(t)

#define ACPI_EC_SMB_PRTCL	0x00	/* protocol, PEC */

#define ACPI_EC_SMB_STS		0x01	/* status */
#define ACPI_EC_SMB_ADDR	0x02	/* address */
#define ACPI_EC_SMB_CMD		0x03	/* command */
#define ACPI_EC_SMB_DATA	0x04	/* 32 data registers */
#define ACPI_EC_SMB_BCNT	0x24	/* number of data bytes */

#define ACPI_EC_SMB_STS_DONE	0x80
#define ACPI_EC_SMB_STS_STATUS	0x1f

#define ACPI_EC_SMB_PRTCL_WRITE		0x00
#define ACPI_EC_SMB_PRTCL_READ		0x01
#define ACPI_EC_SMB_PRTCL_WORD_DATA	0x08
#define ACPI_EC_SMB_PRTCL_BLOCK_DATA	0x0a

#define ACPI_EC_SMB_TRANSACTION_SLEEP	1
#define ACPI_EC_SMB_ACCESS_SLEEP1	1
#define ACPI_EC_SMB_ACCESS_SLEEP2	10

#define	DEF_CAPACITY_UNIT	3
#define	MAH_CAPACITY_UNIT	1
#define	MWH_CAPACITY_UNIT	2
#define	CAPACITY_UNIT		DEF_CAPACITY_UNIT

#define	REQUEST_UPDATE_MODE	1
#define	QUEUE_UPDATE_MODE	2

#define	DATA_TYPE_COMMON	0
#define	DATA_TYPE_INFO		1
#define	DATA_TYPE_STATE		2
#define	DATA_TYPE_ALARM		3
#define	DATA_TYPE_AC_STATE	4

extern struct proc_dir_entry *acpi_lock_ac_dir(void);
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);

#define	MAX_SBS_BAT			4
#define ACPI_SBS_BLOCK_MAX		32

#define ACPI_SBS_SMBUS_READ		1
#define ACPI_SBS_SMBUS_WRITE		2

#define ACPI_SBS_WORD_DATA		1
#define ACPI_SBS_BLOCK_DATA		2

static struct semaphore sbs_sem;
static struct semaphore sbs_sem;


#define	UPDATE_MODE		QUEUE_UPDATE_MODE
#define	UPDATE_MODE		QUEUE_UPDATE_MODE
@@ -105,7 +131,6 @@ module_param(update_time2, int, 0);


static int acpi_sbs_add(struct acpi_device *device);
static int acpi_sbs_add(struct acpi_device *device);
static int acpi_sbs_remove(struct acpi_device *device, int type);
static int acpi_sbs_remove(struct acpi_device *device, int type);
static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus);
static void acpi_sbs_update_queue(void *data);
static void acpi_sbs_update_queue(void *data);


static struct acpi_driver acpi_sbs_driver = {
static struct acpi_driver acpi_sbs_driver = {
@@ -126,9 +151,9 @@ struct acpi_battery_info {
	int vscale;
	int vscale;
	int ipscale;
	int ipscale;
	s16 serial_number;
	s16 serial_number;
	char manufacturer_name[I2C_SMBUS_BLOCK_MAX + 3];
	char manufacturer_name[ACPI_SBS_BLOCK_MAX + 3];
	char device_name[I2C_SMBUS_BLOCK_MAX + 3];
	char device_name[ACPI_SBS_BLOCK_MAX + 3];
	char device_chemistry[I2C_SMBUS_BLOCK_MAX + 3];
	char device_chemistry[ACPI_SBS_BLOCK_MAX + 3];
};
};


struct acpi_battery_state {
struct acpi_battery_state {
@@ -158,8 +183,8 @@ struct acpi_battery {


struct acpi_sbs {
struct acpi_sbs {
	acpi_handle handle;
	acpi_handle handle;
	int base;
	struct acpi_device *device;
	struct acpi_device *device;
	struct acpi_ec_smbus *smbus;
	int sbsm_present;
	int sbsm_present;
	int sbsm_batteries_supported;
	int sbsm_batteries_supported;
	int ac_present;
	int ac_present;
@@ -172,6 +197,14 @@ struct acpi_sbs {
	struct timer_list update_timer;
	struct timer_list update_timer;
};
};


union sbs_rw_data {
	u16 word;
	u8 block[ACPI_SBS_BLOCK_MAX + 2];
};

static int acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
			      char read_write, u8 command, int size,
			      union sbs_rw_data *data);
static void acpi_update_delay(struct acpi_sbs *sbs);
static void acpi_update_delay(struct acpi_sbs *sbs);
static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type);
static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type);


@@ -179,155 +212,172 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type);
                               SMBus Communication
                               SMBus Communication
   -------------------------------------------------------------------------- */
   -------------------------------------------------------------------------- */


static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus)
static int acpi_ec_sbs_read(struct acpi_sbs *sbs, u8 address, u8 * data)
{
{
	union i2c_smbus_data data;
	u8 val;
	int result = 0;
	int err;
	char *err_str;
	int err_number;


	data.word = 0;
	err = ec_read(sbs->base + address, &val);
	if (!err) {
		*data = val;
	}
	xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
	return (err);
}


	result = smbus->adapter.algo->
static int acpi_ec_sbs_write(struct acpi_sbs *sbs, u8 address, u8 data)
	    smbus_xfer(&smbus->adapter,
{
		       ACPI_SB_SMBUS_ADDR,
	int err;
		       0, I2C_SMBUS_READ, 0x16, I2C_SMBUS_BLOCK_DATA, &data);


	err_number = (data.word & 0x000f);
	err = ec_write(sbs->base + address, data);
	return (err);
}


	switch (data.word & 0x000f) {
static int
	case 0x0000:
acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
		err_str = "unexpected bus error";
		   char read_write, u8 command, int size,
		break;
		   union sbs_rw_data *data)
	case 0x0001:
{
		err_str = "busy";
	unsigned char protocol, len = 0, temp[2] = { 0, 0 };
		break;
	int i;
	case 0x0002:

		err_str = "reserved command";
	if (read_write == ACPI_SBS_SMBUS_READ) {
		break;
		protocol = ACPI_EC_SMB_PRTCL_READ;
	case 0x0003:
	} else {
		err_str = "unsupported command";
		protocol = ACPI_EC_SMB_PRTCL_WRITE;
		break;
	}
	case 0x0004:

		err_str = "access denied";
	switch (size) {

	case ACPI_SBS_WORD_DATA:
		acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
		if (read_write == ACPI_SBS_SMBUS_WRITE) {
			acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA, data->word);
			acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + 1,
					  data->word >> 8);
		}
		protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA;
		break;
		break;
	case 0x0005:
	case ACPI_SBS_BLOCK_DATA:
		err_str = "overflow/underflow";
		acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
		if (read_write == ACPI_SBS_SMBUS_WRITE) {
			len = min_t(u8, data->block[0], 32);
			acpi_ec_sbs_write(sbs, ACPI_EC_SMB_BCNT, len);
			for (i = 0; i < len; i++)
				acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + i,
						  data->block[i + 1]);
		}
		protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA;
		break;
		break;
	case 0x0006:
	default:
		err_str = "bad size";
		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
				"unsupported transaction %d\n", size));
		return (-1);
	}

	acpi_ec_sbs_write(sbs, ACPI_EC_SMB_ADDR, addr << 1);
	acpi_ec_sbs_write(sbs, ACPI_EC_SMB_PRTCL, protocol);

	acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);

	if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
		xmsleep(ACPI_EC_SMB_ACCESS_SLEEP1);
		acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
	}
	if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
		xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
		acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
	}
	if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
	    || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
				"transaction %d error\n", size));
		return (-1);
	}

	if (read_write == ACPI_SBS_SMBUS_WRITE) {
		return (0);
	}

	switch (size) {

	case ACPI_SBS_WORD_DATA:
		acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA, temp);
		acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + 1, temp + 1);
		data->word = (temp[1] << 8) | temp[0];
		break;
		break;
	case 0x0007:

		err_str = "unknown error";
	case ACPI_SBS_BLOCK_DATA:
		len = 0;
		acpi_ec_sbs_read(sbs, ACPI_EC_SMB_BCNT, &len);
		len = min_t(u8, len, 32);
		for (i = 0; i < len; i++)
			acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + i,
					 data->block + i + 1);
		data->block[0] = len;
		break;
		break;
	default:
	default:
		err_str = "unrecognized error";
		ACPI_EXCEPTION((AE_INFO, AE_ERROR,
				"unsupported transaction %d\n", size));
		return (-1);
	}
	}
	ACPI_DEBUG_PRINT((ACPI_DB_ERROR,

			  "%s: ret %i, err %i\n", err_str, result, err_number));
	return (0);
}
}


static int
static int
acpi_sbs_smbus_read_word(struct acpi_ec_smbus *smbus, int addr, int func,
acpi_sbs_read_word(struct acpi_sbs *sbs, int addr, int func, u16 * word)
			 u16 * word,
			 void (*err_handler) (struct acpi_ec_smbus * smbus))
{
{
	union i2c_smbus_data data;
	union sbs_rw_data data;
	int result = 0;
	int result = 0;
	int i;

	if (err_handler == NULL) {
		err_handler = acpi_battery_smbus_err_handler;
	}


	for (i = 0; i < MAX_SMBUS_ERR; i++) {
	result = acpi_ec_sbs_access(sbs, addr,
		result =
				    ACPI_SBS_SMBUS_READ, func,
		    smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
				    ACPI_SBS_WORD_DATA, &data);
						    I2C_SMBUS_READ, func,
						    I2C_SMBUS_WORD_DATA, &data);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
					  "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
				  "acpi_ec_sbs_access() failed\n"));
					  i));
			if (err_handler) {
				err_handler(smbus);
			}
	} else {
	} else {
		*word = data.word;
		*word = data.word;
			break;
		}
	}
	}


	return result;
	return result;
}
}


static int
static int
acpi_sbs_smbus_read_str(struct acpi_ec_smbus *smbus, int addr, int func,
acpi_sbs_read_str(struct acpi_sbs *sbs, int addr, int func, char *str)
			char *str,
			void (*err_handler) (struct acpi_ec_smbus * smbus))
{
{
	union i2c_smbus_data data;
	union sbs_rw_data data;
	int result = 0;
	int result = 0;
	int i;

	if (err_handler == NULL) {
		err_handler = acpi_battery_smbus_err_handler;
	}


	for (i = 0; i < MAX_SMBUS_ERR; i++) {
	result = acpi_ec_sbs_access(sbs, addr,
		result =
				    ACPI_SBS_SMBUS_READ, func,
		    smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
				    ACPI_SBS_BLOCK_DATA, &data);
						    I2C_SMBUS_READ, func,
						    I2C_SMBUS_BLOCK_DATA,
						    &data);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
					  "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
				  "acpi_ec_sbs_access() failed\n"));
					  i));
			if (err_handler) {
				err_handler(smbus);
			}
	} else {
	} else {
			strncpy(str, (const char *)data.block + 1,
		strncpy(str, (const char *)data.block + 1, data.block[0]);
				data.block[0]);
		str[data.block[0]] = 0;
		str[data.block[0]] = 0;
			break;
		}
	}
	}


	return result;
	return result;
}
}


static int
static int
acpi_sbs_smbus_write_word(struct acpi_ec_smbus *smbus, int addr, int func,
acpi_sbs_write_word(struct acpi_sbs *sbs, int addr, int func, int word)
			  int word,
			  void (*err_handler) (struct acpi_ec_smbus * smbus))
{
{
	union i2c_smbus_data data;
	union sbs_rw_data data;
	int result = 0;
	int result = 0;
	int i;

	if (err_handler == NULL) {
		err_handler = acpi_battery_smbus_err_handler;
	}


	data.word = word;
	data.word = word;


	for (i = 0; i < MAX_SMBUS_ERR; i++) {
	result = acpi_ec_sbs_access(sbs, addr,
		result =
				    ACPI_SBS_SMBUS_WRITE, func,
		    smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
				    ACPI_SBS_WORD_DATA, &data);
						    I2C_SMBUS_WRITE, func,
						    I2C_SMBUS_WORD_DATA, &data);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
					  "try %i: smbus->adapter.algo"
				  "acpi_ec_sbs_access() failed\n"));
					  "->smbus_xfer() failed\n", i));
			if (err_handler) {
				err_handler(smbus);
			}
		} else {
			break;
		}
	}
	}


	return result;
	return result;
@@ -366,12 +416,11 @@ static int acpi_battery_get_present(struct acpi_battery *battery)
	int result = 0;
	int result = 0;
	int is_present = 0;
	int is_present = 0;


	result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
	result = acpi_sbs_read_word(battery->sbs,
					  ACPI_SBSM_SMBUS_ADDR, 0x01,
				    ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
					  &state, NULL);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed"));
				  "acpi_sbs_read_word() failed"));
	}
	}
	if (!result) {
	if (!result) {
		is_present = (state & 0x000f) & (1 << battery->id);
		is_present = (state & 0x000f) & (1 << battery->id);
@@ -393,7 +442,7 @@ static int acpi_ac_is_present(struct acpi_sbs *sbs)


static int acpi_battery_select(struct acpi_battery *battery)
static int acpi_battery_select(struct acpi_battery *battery)
{
{
	struct acpi_ec_smbus *smbus = battery->sbs->smbus;
	struct acpi_sbs *sbs = battery->sbs;
	int result = 0;
	int result = 0;
	s16 state;
	s16 state;
	int foo;
	int foo;
@@ -405,21 +454,19 @@ static int acpi_battery_select(struct acpi_battery *battery)
		 * it causes charging to halt on SBSELs */
		 * it causes charging to halt on SBSELs */


		result =
		result =
		    acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
		    acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
					     &state, NULL);
		if (result) {
		if (result) {
			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
					  "acpi_sbs_smbus_read_word() failed\n"));
					  "acpi_sbs_read_word() failed\n"));
			goto end;
			goto end;
		}
		}


		foo = (state & 0x0fff) | (1 << (battery->id + 12));
		foo = (state & 0x0fff) | (1 << (battery->id + 12));
		result =
		result =
		    acpi_sbs_smbus_write_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
		    acpi_sbs_write_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, foo);
					      foo, NULL);
		if (result) {
		if (result) {
			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
					  "acpi_sbs_smbus_write_word() failed\n"));
					  "acpi_sbs_write_word() failed\n"));
			goto end;
			goto end;
		}
		}
	}
	}
@@ -430,15 +477,14 @@ static int acpi_battery_select(struct acpi_battery *battery)


static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
{
{
	struct acpi_ec_smbus *smbus = sbs->smbus;
	int result = 0;
	int result = 0;
	s16 battery_system_info;
	s16 battery_system_info;


	result = acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x04,
	result = acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x04,
					  &battery_system_info, NULL);
				    &battery_system_info);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


@@ -451,53 +497,48 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs)


static int acpi_battery_get_info(struct acpi_battery *battery)
static int acpi_battery_get_info(struct acpi_battery *battery)
{
{
	struct acpi_ec_smbus *smbus = battery->sbs->smbus;
	struct acpi_sbs *sbs = battery->sbs;
	int result = 0;
	int result = 0;
	s16 battery_mode;
	s16 battery_mode;
	s16 specification_info;
	s16 specification_info;


	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
					  &battery_mode,
				    &battery_mode);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}
	battery->info.capacity_mode = (battery_mode & 0x8000) >> 15;
	battery->info.capacity_mode = (battery_mode & 0x8000) >> 15;


	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x10,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x10,
					  &battery->info.full_charge_capacity,
				    &battery->info.full_charge_capacity);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x18,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x18,
					  &battery->info.design_capacity,
				    &battery->info.design_capacity);
					  &acpi_battery_smbus_err_handler);


	if (result) {
	if (result) {
		goto end;
		goto end;
	}
	}


	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x19,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x19,
					  &battery->info.design_voltage,
				    &battery->info.design_voltage);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1a,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1a,
					  &specification_info,
				    &specification_info);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


@@ -529,37 +570,33 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
		battery->info.ipscale = 1;
		battery->info.ipscale = 1;
	}
	}


	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1c,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1c,
					  &battery->info.serial_number,
				    &battery->info.serial_number);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		goto end;
		goto end;
	}
	}


	result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x20,
	result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x20,
					 battery->info.manufacturer_name,
				   battery->info.manufacturer_name);
					 &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_str() failed\n"));
				  "acpi_sbs_read_str() failed\n"));
		goto end;
		goto end;
	}
	}


	result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x21,
	result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x21,
					 battery->info.device_name,
				   battery->info.device_name);
					 &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_str() failed\n"));
				  "acpi_sbs_read_str() failed\n"));
		goto end;
		goto end;
	}
	}


	result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x22,
	result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x22,
					 battery->info.device_chemistry,
				   battery->info.device_chemistry);
					 &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_str() failed\n"));
				  "acpi_sbs_read_str() failed\n"));
		goto end;
		goto end;
	}
	}


@@ -579,66 +616,60 @@ static void acpi_update_delay(struct acpi_sbs *sbs)


static int acpi_battery_get_state(struct acpi_battery *battery)
static int acpi_battery_get_state(struct acpi_battery *battery)
{
{
	struct acpi_ec_smbus *smbus = battery->sbs->smbus;
	struct acpi_sbs *sbs = battery->sbs;
	int result = 0;
	int result = 0;


	acpi_update_delay(battery->sbs);
	acpi_update_delay(battery->sbs);
	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x09,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x09,
					  &battery->state.voltage,
				    &battery->state.voltage);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


	acpi_update_delay(battery->sbs);
	acpi_update_delay(battery->sbs);
	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0a,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0a,
					  &battery->state.amperage,
				    &battery->state.amperage);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


	acpi_update_delay(battery->sbs);
	acpi_update_delay(battery->sbs);
	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0f,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0f,
					  &battery->state.remaining_capacity,
				    &battery->state.remaining_capacity);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


	acpi_update_delay(battery->sbs);
	acpi_update_delay(battery->sbs);
	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x12,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x12,
					  &battery->state.average_time_to_empty,
				    &battery->state.average_time_to_empty);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


	acpi_update_delay(battery->sbs);
	acpi_update_delay(battery->sbs);
	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x13,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x13,
					  &battery->state.average_time_to_full,
				    &battery->state.average_time_to_full);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


	acpi_update_delay(battery->sbs);
	acpi_update_delay(battery->sbs);
	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x16,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x16,
					  &battery->state.battery_status,
				    &battery->state.battery_status);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


@@ -650,15 +681,14 @@ static int acpi_battery_get_state(struct acpi_battery *battery)


static int acpi_battery_get_alarm(struct acpi_battery *battery)
static int acpi_battery_get_alarm(struct acpi_battery *battery)
{
{
	struct acpi_ec_smbus *smbus = battery->sbs->smbus;
	struct acpi_sbs *sbs = battery->sbs;
	int result = 0;
	int result = 0;


	result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
	result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
					  &battery->alarm.remaining_capacity,
				    &battery->alarm.remaining_capacity);
					  &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


@@ -672,7 +702,7 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery)
static int acpi_battery_set_alarm(struct acpi_battery *battery,
static int acpi_battery_set_alarm(struct acpi_battery *battery,
				  unsigned long alarm)
				  unsigned long alarm)
{
{
	struct acpi_ec_smbus *smbus = battery->sbs->smbus;
	struct acpi_sbs *sbs = battery->sbs;
	int result = 0;
	int result = 0;
	s16 battery_mode;
	s16 battery_mode;
	int foo;
	int foo;
@@ -688,33 +718,29 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,


	if (alarm > 0) {
	if (alarm > 0) {
		result =
		result =
		    acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
		    acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
					     &battery_mode,
				       &battery_mode);
					     &acpi_battery_smbus_err_handler);
		if (result) {
		if (result) {
			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
					  "acpi_sbs_smbus_read_word() failed\n"));
					  "acpi_sbs_read_word() failed\n"));
			goto end;
			goto end;
		}
		}


		result =
		result =
		    acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
		    acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
					      battery_mode & 0xbfff,
					battery_mode & 0xbfff);
					      &acpi_battery_smbus_err_handler);
		if (result) {
		if (result) {
			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
					  "acpi_sbs_smbus_write_word() failed\n"));
					  "acpi_sbs_write_word() failed\n"));
			goto end;
			goto end;
		}
		}
	}
	}


	foo = alarm / (battery->info.capacity_mode ? 10 : 1);
	foo = alarm / (battery->info.capacity_mode ? 10 : 1);
	result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
	result = acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, foo);
					   foo,
					   &acpi_battery_smbus_err_handler);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_write_word() failed\n"));
				  "acpi_sbs_write_word() failed\n"));
		goto end;
		goto end;
	}
	}


@@ -732,12 +758,11 @@ static int acpi_battery_set_mode(struct acpi_battery *battery)
		goto end;
		goto end;
	}
	}


	result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
	result = acpi_sbs_read_word(battery->sbs,
					  ACPI_SB_SMBUS_ADDR, 0x03,
				    ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
					  &battery_mode, NULL);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


@@ -746,21 +771,19 @@ static int acpi_battery_set_mode(struct acpi_battery *battery)
	} else {
	} else {
		battery_mode |= 0x8000;
		battery_mode |= 0x8000;
	}
	}
	result = acpi_sbs_smbus_write_word(battery->sbs->smbus,
	result = acpi_sbs_write_word(battery->sbs,
					   ACPI_SB_SMBUS_ADDR, 0x03,
				     ACPI_SB_SMBUS_ADDR, 0x03, battery_mode);
					   battery_mode, NULL);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_write_word() failed\n"));
				  "acpi_sbs_write_word() failed\n"));
		goto end;
		goto end;
	}
	}


	result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
	result = acpi_sbs_read_word(battery->sbs,
					  ACPI_SB_SMBUS_ADDR, 0x03,
				    ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
					  &battery_mode, NULL);
	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


@@ -813,16 +836,15 @@ static int acpi_battery_init(struct acpi_battery *battery)


static int acpi_ac_get_present(struct acpi_sbs *sbs)
static int acpi_ac_get_present(struct acpi_sbs *sbs)
{
{
	struct acpi_ec_smbus *smbus = sbs->smbus;
	int result = 0;
	int result = 0;
	s16 charger_status;
	s16 charger_status;


	result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x13,
	result = acpi_sbs_read_word(sbs, ACPI_SBC_SMBUS_ADDR, 0x13,
					  &charger_status, NULL);
				    &charger_status);


	if (result) {
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_sbs_smbus_read_word() failed\n"));
				  "acpi_sbs_read_word() failed\n"));
		goto end;
		goto end;
	}
	}


@@ -1567,38 +1589,27 @@ static void acpi_sbs_update_queue(void *data)
static int acpi_sbs_add(struct acpi_device *device)
static int acpi_sbs_add(struct acpi_device *device)
{
{
	struct acpi_sbs *sbs = NULL;
	struct acpi_sbs *sbs = NULL;
	struct acpi_ec_hc *ec_hc = NULL;
	int result;
	int result, remove_result = 0;
	unsigned long sbs_obj;
	unsigned long sbs_obj;
	int id, cnt;
	int id;
	acpi_status status = AE_OK;
	acpi_status status = AE_OK;
	unsigned long val;

	status =
	    acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
	if (ACPI_FAILURE(status)) {
		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n"));
		return -EIO;
	}


	sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
	sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
	if (!sbs) {
	if (!sbs) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));
		return -ENOMEM;
		return -ENOMEM;
	}
	}

	sbs->base = (val & 0xff00ull) >> 8;
	cnt = 0;
	while (cnt < 10) {
		cnt++;
		ec_hc = acpi_get_ec_hc(device);
		if (ec_hc) {
			break;
		}
		msleep(1000);
	}

	if (!ec_hc) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "acpi_get_ec_hc() failed: "
				  "NO driver found for EC HC SMBus\n"));
		result = -ENODEV;
		goto end;
	}


	sbs->device = device;
	sbs->device = device;
	sbs->smbus = ec_hc->smbus;


	strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
	strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
	strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
@@ -1669,11 +1680,7 @@ static int acpi_sbs_add(struct acpi_device *device)


      end:
      end:
	if (result) {
	if (result) {
		remove_result = acpi_sbs_remove(device, 0);
		acpi_sbs_remove(device, 0);
		if (remove_result) {
			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
					  "acpi_sbs_remove() failed\n"));
		}
	}
	}


	return result;
	return result;
@@ -1707,6 +1714,8 @@ int acpi_sbs_remove(struct acpi_device *device, int type)


	acpi_ac_remove(sbs);
	acpi_ac_remove(sbs);


	acpi_driver_data(device) = NULL;

	kfree(sbs);
	kfree(sbs);


	return 0;
	return 0;