Commit 683d88c8 authored by Aurelien Jarno's avatar Aurelien Jarno Committed by Greg Kroah-Hartman

[PATCH] I2C: lm78 driver improvement

The following patch against kernel 2.6.11-rc2-mm1 improves the lm78
driver. I used it as a model to port the sis5595 driver to the 2.6
kernel, and I then applied the changes suggested by Jean Delvare on
the sis5595 driver to this one.
Signed-off-by: default avatarAurelien Jarno <aurelien@aurel32.net>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent a8e3efd1
...@@ -81,9 +81,8 @@ static inline u8 IN_TO_REG(unsigned long val) ...@@ -81,9 +81,8 @@ static inline u8 IN_TO_REG(unsigned long val)
static inline u8 FAN_TO_REG(long rpm, int div) static inline u8 FAN_TO_REG(long rpm, int div)
{ {
if (rpm == 0) if (rpm <= 0)
return 255; return 255;
rpm = SENSORS_LIMIT(rpm, 1, 1000000);
return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
} }
...@@ -94,15 +93,15 @@ static inline int FAN_FROM_REG(u8 val, int div) ...@@ -94,15 +93,15 @@ static inline int FAN_FROM_REG(u8 val, int div)
/* TEMP: mC (-128C to +127C) /* TEMP: mC (-128C to +127C)
REG: 1C/bit, two's complement */ REG: 1C/bit, two's complement */
static inline u8 TEMP_TO_REG(int val) static inline s8 TEMP_TO_REG(int val)
{ {
int nval = SENSORS_LIMIT(val, -128000, 127000) ; int nval = SENSORS_LIMIT(val, -128000, 127000) ;
return nval<0 ? (nval-500)/1000+0x100 : (nval+500)/1000; return nval<0 ? (nval-500)/1000 : (nval+500)/1000;
} }
static inline int TEMP_FROM_REG(u8 val) static inline int TEMP_FROM_REG(s8 val)
{ {
return (val>=0x80 ? val-0x100 : val) * 1000; return val * 1000;
} }
/* VID: mV /* VID: mV
...@@ -112,16 +111,6 @@ static inline int VID_FROM_REG(u8 val) ...@@ -112,16 +111,6 @@ static inline int VID_FROM_REG(u8 val)
return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50; return val==0x1f ? 0 : val>=0x10 ? 5100-val*100 : 2050-val*50;
} }
/* ALARMS: chip-specific bitmask
REG: (same) */
#define ALARMS_FROM_REG(val) (val)
/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
REG: 0, 1, 2, or 3 (respectively) (defaults to 1) */
static inline u8 DIV_TO_REG(int val)
{
return val==8 ? 3 : val==4 ? 2 : val==1 ? 0 : 1;
}
#define DIV_FROM_REG(val) (1 << (val)) #define DIV_FROM_REG(val) (1 << (val))
/* There are some complications in a module like this. First off, LM78 chips /* There are some complications in a module like this. First off, LM78 chips
...@@ -157,9 +146,9 @@ struct lm78_data { ...@@ -157,9 +146,9 @@ struct lm78_data {
u8 in_min[7]; /* Register value */ u8 in_min[7]; /* Register value */
u8 fan[3]; /* Register value */ u8 fan[3]; /* Register value */
u8 fan_min[3]; /* Register value */ u8 fan_min[3]; /* Register value */
u8 temp; /* Register value */ s8 temp; /* Register value */
u8 temp_over; /* Register value */ s8 temp_over; /* Register value */
u8 temp_hyst; /* Register value */ s8 temp_hyst; /* Register value */
u8 fan_div[3]; /* Register encoding, shifted right */ u8 fan_div[3]; /* Register encoding, shifted right */
u8 vid; /* Register encoding, combined */ u8 vid; /* Register encoding, combined */
u16 alarms; /* Register encoding, combined */ u16 alarms; /* Register encoding, combined */
...@@ -357,7 +346,17 @@ static ssize_t set_fan_div(struct device *dev, const char *buf, ...@@ -357,7 +346,17 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
DIV_FROM_REG(data->fan_div[nr])); DIV_FROM_REG(data->fan_div[nr]));
unsigned long val = simple_strtoul(buf, NULL, 10); unsigned long val = simple_strtoul(buf, NULL, 10);
int reg = lm78_read_value(client, LM78_REG_VID_FANDIV); int reg = lm78_read_value(client, LM78_REG_VID_FANDIV);
data->fan_div[nr] = DIV_TO_REG(val); switch (val) {
case 1: data->fan_div[nr] = 0; break;
case 2: data->fan_div[nr] = 1; break;
case 4: data->fan_div[nr] = 2; break;
case 8: data->fan_div[nr] = 3; break;
default:
dev_err(&client->dev, "fan_div value %ld not "
"supported. Choose one of 1, 2, 4 or 8!\n", val);
return -EINVAL;
}
switch (nr) { switch (nr) {
case 0: case 0:
reg = (reg & 0xcf) | (data->fan_div[nr] << 4); reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
...@@ -430,7 +429,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); ...@@ -430,7 +429,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
static ssize_t show_alarms(struct device *dev, char *buf) static ssize_t show_alarms(struct device *dev, char *buf)
{ {
struct lm78_data *data = lm78_update_device(dev); struct lm78_data *data = lm78_update_device(dev);
return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms)); return sprintf(buf, "%u\n", data->alarms);
} }
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
...@@ -633,17 +632,15 @@ static int lm78_detach_client(struct i2c_client *client) ...@@ -633,17 +632,15 @@ static int lm78_detach_client(struct i2c_client *client)
{ {
int err; int err;
/* release ISA region first */
if(i2c_is_isa_client(client))
release_region(client->addr, LM78_EXTENT);
/* now it's safe to scrap the rest */
if ((err = i2c_detach_client(client))) { if ((err = i2c_detach_client(client))) {
dev_err(&client->dev, dev_err(&client->dev,
"Client deregistration failed, client not detached.\n"); "Client deregistration failed, client not detached.\n");
return err; return err;
} }
if(i2c_is_isa_client(client))
release_region(client->addr, LM78_EXTENT);
kfree(i2c_get_clientdata(client)); kfree(i2c_get_clientdata(client));
return 0; return 0;
...@@ -653,9 +650,7 @@ static int lm78_detach_client(struct i2c_client *client) ...@@ -653,9 +650,7 @@ static int lm78_detach_client(struct i2c_client *client)
We don't want to lock the whole ISA bus, so we lock each client We don't want to lock the whole ISA bus, so we lock each client
separately. separately.
We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
would slow down the LM78 access and should not be necessary. would slow down the LM78 access and should not be necessary. */
There are some ugly typecasts here, but the good new is - they should
nowhere else be necessary! */
static int lm78_read_value(struct i2c_client *client, u8 reg) static int lm78_read_value(struct i2c_client *client, u8 reg)
{ {
int res; int res;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment