From e9d296adf3c90eaae01f0d84f9d9db28470e4bdd Mon Sep 17 00:00:00 2001 From: "Mark D. Studebaker" Date: Sun, 11 Jan 2004 23:54:27 +0000 Subject: [PATCH] fix detection git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@2214 7894878c-1315-0410-8ee3-d5d059ff63e0 --- CHANGES | 1 + kernel/chips/smartbatt.c | 226 +++++++++++++++++++++++++++------------ 2 files changed, 161 insertions(+), 66 deletions(-) diff --git a/CHANGES b/CHANGES index bf073c46..57d7979e 100644 --- a/CHANGES +++ b/CHANGES @@ -30,6 +30,7 @@ ask CVS about it: remove initialization of temp_type and fan_ctl; remove init and temp_type module parameters Module lm90: Handle hysteresis differently + Module smartbatt: Fix detection Module w83781d: Fix negative voltages Module w83l785ts: New Program eeprog: Make 8 bit mode the default diff --git a/kernel/chips/smartbatt.c b/kernel/chips/smartbatt.c index 47e6a2df..f272237d 100644 --- a/kernel/chips/smartbatt.c +++ b/kernel/chips/smartbatt.c @@ -33,17 +33,14 @@ /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x0b, SENSORS_I2C_END }; -static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { 0x0b, SENSORS_I2C_END }; static unsigned int normal_isa[] = { SENSORS_ISA_END }; static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; /* Insmod parameters */ SENSORS_INSMOD_1(smartbatt); -/* Conversions */ -#define TEMP_FROM_REG(r) (r - 2732) /* tenths of degree kelvin to celsius */ - /* The SMARTBATT registers */ #define SMARTBATT_REG_MODE 0x03 #define SMARTBATT_REG_TEMP 0x08 @@ -52,10 +49,16 @@ SENSORS_INSMOD_1(smartbatt); #define SMARTBATT_REG_AVGI 0x0b #define SMARTBATT_REG_RELCHG 0x0d #define SMARTBATT_REG_ABSCHG 0x0e +#define SMARTBATT_REG_REMCAP 0x0f +#define SMARTBATT_REG_CHGCAP 0x10 #define SMARTBATT_REG_RUNTIME_E 0x11 #define SMARTBATT_REG_AVGTIME_E 0x12 #define SMARTBATT_REG_AVGTIME_F 0x13 +#define SMARTBATT_REG_CHGI 0x14 +#define SMARTBATT_REG_CHGV 0x15 #define SMARTBATT_REG_STATUS 0x16 +#define SMARTBATT_REG_CYCLECT 0x17 +#define SMARTBATT_REG_DESCAP 0x18 #define SMARTBATT_REG_DESV 0x19 #define SMARTBATT_REG_DATE 0x1b #define SMARTBATT_REG_SERIAL 0x1c @@ -63,8 +66,9 @@ SENSORS_INSMOD_1(smartbatt); #define SMARTBATT_REG_NAME 0x21 #define SMARTBATT_REG_CHEM 0x22 +#define BATTERY_STRING_MAX 64 #define COMM_TIMEOUT 16 -#define BATTERY_STRING_MAX 33 + /* Each client has this additional data */ struct smartbatt_data { @@ -77,16 +81,17 @@ struct smartbatt_data { char manufacturer[BATTERY_STRING_MAX]; char device[BATTERY_STRING_MAX]; char chemistry[BATTERY_STRING_MAX]; +#endif int serial; struct { unsigned int day:5; /* Day (1-31) */ unsigned int month:4; /* Month (1-12) */ unsigned int year:7; /* Year (1980 + 0-127) */ } manufacture_date; -#endif - u16 temp, v, desv, i, avgi; /* Register values */ - u16 rte, ate, atf, alarms; /* Register values */ - u16 relchg, abschg; /* Register values */ + u16 mode, temp, v, i, avgi; /* Register values */ + u16 relchg, abschg, remcap, chgcap; /* Register values */ + u16 rte, ate, atf, chgi, chgv; /* Register values */ + u16 status, cyclect, descap, desv; /* Register values */ }; static int smartbatt_attach_adapter(struct i2c_adapter *adapter); @@ -95,9 +100,9 @@ static int smartbatt_detect(struct i2c_adapter *adapter, int address, static void smartbatt_init_client(struct i2c_client *client); static int smartbatt_detach_client(struct i2c_client *client); -static u16 swap_bytes(u16 val); -static int sb_read(struct i2c_client *client, u8 reg); +static int smartbatt_read(struct i2c_client *client, u8 reg); #if 0 +static u16 swap_bytes(u16 val); static int smartbatt_write_value(struct i2c_client *client, u8 reg, u16 value); #endif static void smartbatt_temp(struct i2c_client *client, int operation, @@ -112,6 +117,10 @@ static void smartbatt_alarms(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); static void smartbatt_charge(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results); +static void smartbatt_status(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void smartbatt_error(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); static void smartbatt_update_client(struct i2c_client *client); @@ -127,12 +136,53 @@ static struct i2c_driver smartbatt_driver = { /* -- SENSORS SYSCTL START -- */ + +/* Status Register Bits */ +/* * * * * * Alarm Bits * * * * */ +#define SMARTBATT_OVER_CHARGED_ALARM 0x8000 +#define SMARTBATT_TERMINATE_CHARGE_ALARM 0x4000 +#define SMARTBATT_OVER_TEMP_ALARM 0x1000 +#define SMARTBATT_TERMINATE_DISCHARGE_ALARM 0x0800 +#define SMARTBATT_REMAINING_CAPACITY_ALARM 0x0200 +#define SMARTBATT_REMAINING_TIME_ALARM 0x0100 +/* * * * * * Status Bits * * * * */ +#define SMARTBATT_INITIALIZED 0x0080 +#define SMARTBATT_DISCHARGING 0x0040 +#define SMARTBATT_FULLY_CHARGED 0x0020 +#define SMARTBATT_FULLY_DISCHARGED 0x0010 +/* * * * * * Error Bits * * * * */ +#define SMARTBATT_OK 0x0000 +#define SMARTBATT_BUSY 0x0001 +#define SMARTBATT_RESERVED_COMMAND 0x0002 +#define SMARTBATT_UNSUPPORTED_COMMAND 0x0003 +#define SMARTBATT_ACCESS_DENIED 0x0004 +#define SMARTBATT_OVER_UNDERFLOW 0x0005 +#define SMARTBATT_BAD_SIZE 0x0006 +#define SMARTBATT_UNKNOWN_ERROR 0x0007 + +#define SMARTBATT_ALARM (SMARTBATT_OVER_CHARGED_ALARM \ + | SMARTBATT_TERMINATE_CHARGE_ALARM | SMARTBATT_OVER_TEMP_ALARM \ + | SMARTBATT_TERMINATE_DISCHARGE_ALARM \ + | SMARTBATT_REMAINING_CAPACITY_ALARM \ + | SMARTBATT_REMAINING_TIME_ALARM) + +#define SMARTBATT_STATUS (SMARTBATT_INITIALIZED | SMARTBATT_DISCHARGING \ + | SMARTBATT_FULLY_CHARGED | SMARTBATT_FULLY_DISCHARGED ) + +#define SMARTBATT_ERROR (SMARTBATT_BUSY | SMARTBATT_RESERVED_COMMAND \ + | SMARTBATT_UNSUPPORTED_COMMAND | SMARTBATT_ACCESS_DENIED \ + | SMARTBATT_OVER_UNDERFLOW | SMARTBATT_BAD_SIZE\ + | SMARTBATT_UNKNOWN_ERROR) + + #define SMARTBATT_SYSCTL_I 1001 #define SMARTBATT_SYSCTL_V 1002 #define SMARTBATT_SYSCTL_TEMP 1003 #define SMARTBATT_SYSCTL_TIME 1004 #define SMARTBATT_SYSCTL_ALARMS 1005 -#define SMARTBATT_SYSCTL_CHARGE 1006 +#define SMARTBATT_SYSCTL_STATUS 1006 +#define SMARTBATT_SYSCTL_ERROR 1007 +#define SMARTBATT_SYSCTL_CHARGE 1008 /* -- SENSORS SYSCTL END -- */ @@ -152,6 +202,10 @@ static ctl_table smartbatt_dir_table_template[] = { &i2c_sysctl_real, NULL, &smartbatt_time}, {SMARTBATT_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &smartbatt_alarms}, + {SMARTBATT_SYSCTL_STATUS, "status", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &smartbatt_status}, + {SMARTBATT_SYSCTL_ERROR, "error", NULL, 0, 0444, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &smartbatt_error}, {SMARTBATT_SYSCTL_CHARGE, "charge", NULL, 0, 0444, NULL, &i2c_proc_real, &i2c_sysctl_real, NULL, &smartbatt_charge}, {0} @@ -204,10 +258,10 @@ int smartbatt_detect(struct i2c_adapter *adapter, int address, new_client->driver = &smartbatt_driver; new_client->flags = 0; - /* Now, we do the remaining detection. It is lousy. */ + /* Lousy detection. Check the temp, voltage, and current registers */ if (kind < 0) { for (i = 0x08; i <= 0x0a; i++) - if (i2c_smbus_read_word_data(new_client, i) != 0xff) + if (i2c_smbus_read_word_data(new_client, i) == 0xffff) goto ERROR1; } @@ -267,15 +321,22 @@ static int smartbatt_detach_client(struct i2c_client *client) return 0; } - +#if 0 +/* Why swap bytes? */ static u16 swap_bytes(u16 val) { return (val >> 8) | (val << 8); } +#endif -static int sb_read(struct i2c_client *client, u8 reg) -{ - return swap_bytes(i2c_smbus_read_word_data(client, reg)); +static int smartbatt_read(struct i2c_client *client, u8 reg) +{ + int n = COMM_TIMEOUT; + int val; + do { + val = i2c_smbus_read_word_data(client, reg); + } while ((val == -1) && (n-- > 0)); + return val; } #if 0 @@ -285,53 +346,53 @@ static int smartbatt_write_value(struct i2c_client *client, u8 reg, u16 value) } #endif -#if 0 -/* this is code from battery.c. No strings support yet in i2c-proc.c so - all we could do is print this out at startup if we wanted. -*/ -int -static battery_info(int fd, struct battery_info *info) +#define COMM_TIMEOUT 16 +static void get_battery_info(struct i2c_client *client) { - int n; + struct smartbatt_data *data = client->data; int val; + down(&data->update_lock); + data->chgcap = smartbatt_read(client, SMARTBATT_REG_CHGCAP); + data->descap = smartbatt_read(client, SMARTBATT_REG_DESCAP); + data->desv = smartbatt_read(client, SMARTBATT_REG_DESV); /* ManufactureDate */ - val = sb_read(SMARTBATT_REG_DATE); - info->manufacture_date.day=val & 0x1F; - info->manufacture_date.month=(val >> 5) & 0x0F; - info->manufacture_date.year=(val >> 9) & 0x7F; + val = smartbatt_read(client, SMARTBATT_REG_DATE); + data->manufacture_date.day=val & 0x1F; + data->manufacture_date.month=(val >> 5) & 0x0F; + data->manufacture_date.year=(val >> 9) & 0x7F; /* SerialNumber */ - info->serial = sb_read(SMARTBATT_REG_SERIAL - + data->serial = smartbatt_read(client, SMARTBATT_REG_SERIAL); +#if 0 /* ManufacturerName */ - n = COMM_TIMEOUT; + n=COMM_TIMEOUT; do { - val = i2c_smbus_read_block_data(fd, 0x20, info->manufacturer); + val = i2c_smbus_read_block_data(client, 0x20, data->manufacturer); } while ((val == -1) && (n-- > 0)); - info->manufacturer[val]=0; + data->manufacturer[val]=0; /* DeviceName */ - n = COMM_TIMEOUT; + n=COMM_TIMEOUT; do { - val = i2c_smbus_read_block_data(fd, 0x21, info->device); + val = i2c_smbus_read_block_data(client, 0x21, data->device); } while ((val == -1) && (n-- > 0)); - info->device[val]=0; + data->device[val]=0; /* DeviceChemistry */ - n = COMM_TIMEOUT; + n=COMM_TIMEOUT; do { - val = i2c_smbus_read_block_data(fd, 0x22, info->chemistry); + val = i2c_smbus_read_block_data(client, 0x22, data->chemistry); } while ((val == -1) && (n-- > 0)); - info->chemistry[val]=0; - - return 0; -} + data->chemistry[val]=0; #endif + up(&data->update_lock); + +} static void smartbatt_init_client(struct i2c_client *client) { - + get_battery_info( client ); } static void smartbatt_update_client(struct i2c_client *client) @@ -342,17 +403,21 @@ static void smartbatt_update_client(struct i2c_client *client) if ((jiffies - data->last_updated > HZ + HZ / 2) || (jiffies < data->last_updated) || !data->valid) { - data->temp = sb_read(client, SMARTBATT_REG_TEMP); - data->i = sb_read(client, SMARTBATT_REG_I); - data->avgi = sb_read(client, SMARTBATT_REG_AVGI); - data->v = sb_read(client, SMARTBATT_REG_V); - data->desv = sb_read(client, SMARTBATT_REG_DESV); - data->ate = sb_read(client, SMARTBATT_REG_AVGTIME_E); - data->atf = sb_read(client, SMARTBATT_REG_AVGTIME_F); - data->rte = sb_read(client, SMARTBATT_REG_RUNTIME_E); - data->alarms = sb_read(client, SMARTBATT_REG_STATUS); - data->relchg = sb_read(client, SMARTBATT_REG_RELCHG); - data->abschg = sb_read(client, SMARTBATT_REG_ABSCHG); + data->mode = smartbatt_read(client, SMARTBATT_REG_MODE); + data->temp = smartbatt_read(client, SMARTBATT_REG_TEMP); + data->i = smartbatt_read(client, SMARTBATT_REG_I); + data->avgi = smartbatt_read(client, SMARTBATT_REG_AVGI); + data->v = smartbatt_read(client, SMARTBATT_REG_V); + data->chgi = smartbatt_read(client, SMARTBATT_REG_CHGI); + data->chgv = smartbatt_read(client, SMARTBATT_REG_CHGV); + data->ate = smartbatt_read(client, SMARTBATT_REG_AVGTIME_E); + data->atf = smartbatt_read(client, SMARTBATT_REG_AVGTIME_F); + data->rte = smartbatt_read(client, SMARTBATT_REG_RUNTIME_E); + data->status = smartbatt_read(client, SMARTBATT_REG_STATUS); + data->cyclect = smartbatt_read(client, SMARTBATT_REG_CYCLECT); + data->relchg = smartbatt_read(client, SMARTBATT_REG_RELCHG); + data->abschg = smartbatt_read(client, SMARTBATT_REG_ABSCHG); + data->remcap = smartbatt_read(client, SMARTBATT_REG_REMCAP); data->last_updated = jiffies; data->valid = 1; } @@ -366,10 +431,10 @@ void smartbatt_temp(struct i2c_client *client, int operation, int ctl_name, { struct smartbatt_data *data = client->data; if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; + *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { smartbatt_update_client(client); - results[0] = TEMP_FROM_REG(data->temp); + results[0] = data->temp; *nrels_mag = 1; } } @@ -379,12 +444,13 @@ void smartbatt_i(struct i2c_client *client, int operation, int ctl_name, { struct smartbatt_data *data = client->data; if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; + *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { smartbatt_update_client(client); - results[0] = data->avgi; - results[1] = data->i; - *nrels_mag = 2; + results[0] = data->chgi; + results[1] = data->avgi; + results[2] = data->i; + *nrels_mag = 3; } } @@ -393,10 +459,10 @@ void smartbatt_v(struct i2c_client *client, int operation, int ctl_name, { struct smartbatt_data *data = client->data; if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 3; + *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { smartbatt_update_client(client); - results[0] = data->desv; + results[0] = data->chgv; results[1] = data->v; *nrels_mag = 2; } @@ -425,7 +491,33 @@ void smartbatt_alarms(struct i2c_client *client, int operation, int ctl_name, *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { smartbatt_update_client(client); - results[0] = data->alarms; + results[0] = data->status & SMARTBATT_ALARM; + *nrels_mag = 1; + } +} + +void smartbatt_status(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct smartbatt_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + smartbatt_update_client(client); + results[0] = data->status & SMARTBATT_STATUS; + *nrels_mag = 1; + } +} + +void smartbatt_error(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct smartbatt_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + smartbatt_update_client(client); + results[0] = data->status & SMARTBATT_ERROR; *nrels_mag = 1; } } @@ -440,7 +532,9 @@ void smartbatt_charge(struct i2c_client *client, int operation, int ctl_name, smartbatt_update_client(client); results[0] = data->relchg; results[1] = data->abschg; - *nrels_mag = 2; + results[2] = data->chgi; + results[3] = data->chgv; + *nrels_mag = 4; } }