mirror of
https://github.com/lm-sensors/lm-sensors.git
synced 2026-10-25 12:14:33 +00:00
(mds) Change accesses for LM75-compatible temp2/temp3
registers in I2C mode.
Instead of using bank 1 and 2, which was in violation of
the datasheets, use the separate I2C registers (usually
0x48 and 0x49). Register these addresses separately
using additional i2c_attach-client() calls.
Users will see new "subclient" registration messages
in the syslog.
/proc and libsensors interfaces are unchanged, i.e. the
chip still looks like a single device.
This should fix temp2 and temp3 for the as99127f, which
did not allow bank 1 and 2 accesses. Should not affect
operation for other chips as they worked before.
git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@686 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
1 parent
0ead31aaf1
commit
68c3de4b5e
1 file changed
+129
-29
+129
-29
@@ -134,6 +134,7 @@ static const u8 regpwm[] = {W83781D_REG_PWM1, W83781D_REG_PWM2,
|
||||
#define W83781D_REG_PWM(nr) (regpwm[(nr) - 1])
|
||||
|
||||
#define W83781D_REG_I2C_ADDR 0x48
|
||||
#define W83781D_REG_I2C_SUBADDR 0x4A
|
||||
|
||||
/* The following are undocumented in the data sheets however we
|
||||
received the information in an email from Winbond tech support */
|
||||
@@ -330,6 +331,9 @@ struct w83781d_data {
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
|
||||
struct i2c_client *lm75; /* for secondary I2C addresses */
|
||||
/* pointer to array of 2 subclients */
|
||||
|
||||
u8 in[9]; /* Register value - 8 & 9 for 782D only */
|
||||
u8 in_max[9]; /* Register value - 8 & 9 for 782D only */
|
||||
u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
|
||||
@@ -406,6 +410,7 @@ static void w83781d_sens(struct i2c_client *client, int operation,
|
||||
static void w83781d_rt(struct i2c_client *client, int operation,
|
||||
int ctl_name, int *nrels_mag, long *results);
|
||||
#endif
|
||||
static u16 swap_bytes(u16 val);
|
||||
|
||||
static int w83781d_id = 0;
|
||||
|
||||
@@ -801,6 +806,45 @@ int w83781d_detect(struct i2c_adapter *adapter, int address,
|
||||
if ((err = i2c_attach_client(new_client)))
|
||||
goto ERROR3;
|
||||
|
||||
/* attach secondary i2c lm75-like clients */
|
||||
if (!is_isa) {
|
||||
if (! (data->lm75 = kmalloc(2 * sizeof(struct i2c_client),
|
||||
GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
goto ERROR4;
|
||||
}
|
||||
val1 = w83781d_read_value(new_client,W83781D_REG_I2C_SUBADDR);
|
||||
data->lm75[0].addr = 0x48 + (val1 & 0x07);
|
||||
data->lm75[1].addr = 0x48 + ((val1 >> 4) & 0x07);
|
||||
if (kind == w83781d)
|
||||
client_name = "W83781D subclient";
|
||||
else if (kind == w83782d)
|
||||
client_name = "W83782D subclient";
|
||||
else if (kind == w83783s)
|
||||
client_name = "W83783S subclient";
|
||||
else if (kind == w83627hf)
|
||||
client_name = "W83627HF subclient";
|
||||
else if (kind == as99127f)
|
||||
client_name = "AS99127F subclient";
|
||||
|
||||
for(i = 0; i <= 1; i++) {
|
||||
data->lm75[i].data = NULL; /* store all data in w83781d */
|
||||
data->lm75[i].adapter = adapter;
|
||||
data->lm75[i].driver = &w83781d_driver;
|
||||
data->lm75[i].flags = 0;
|
||||
strcpy(data->lm75[i].name,client_name);
|
||||
data->lm75[i].id = w83781d_id++;
|
||||
if ((err = i2c_attach_client(&(data->lm75[i])))) {
|
||||
if(i == 1)
|
||||
goto ERROR6;
|
||||
else
|
||||
goto ERROR5;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data->lm75 = NULL;
|
||||
}
|
||||
|
||||
/* Register a new directory entry with module sensors */
|
||||
if ((i = sensors_register_entry(new_client,
|
||||
type_name,
|
||||
@@ -810,7 +854,7 @@ int w83781d_detect(struct i2c_adapter *adapter, int address,
|
||||
w83782d_isa_dir_table_template,
|
||||
THIS_MODULE)) < 0) {
|
||||
err = i;
|
||||
goto ERROR4;
|
||||
goto ERROR7;
|
||||
}
|
||||
data->sysctl_id = i;
|
||||
|
||||
@@ -821,6 +865,15 @@ int w83781d_detect(struct i2c_adapter *adapter, int address,
|
||||
/* OK, this is not exactly good programming practice, usually. But it is
|
||||
very code-efficient in this case. */
|
||||
|
||||
ERROR7:
|
||||
if (!is_isa)
|
||||
i2c_detach_client(&(((struct w83781d_data *) (new_client->data))->lm75[1]));
|
||||
ERROR6:
|
||||
if (!is_isa)
|
||||
i2c_detach_client(&(((struct w83781d_data *) (new_client->data))->lm75[0]));
|
||||
ERROR5:
|
||||
if (!is_isa)
|
||||
kfree(((struct w83781d_data *) (new_client->data))->lm75);
|
||||
ERROR4:
|
||||
i2c_detach_client(new_client);
|
||||
ERROR3:
|
||||
@@ -845,6 +898,11 @@ int w83781d_detach_client(struct i2c_client *client)
|
||||
|
||||
if i2c_is_isa_client(client)
|
||||
release_region(client->addr,W83781D_EXTENT);
|
||||
else {
|
||||
i2c_detach_client(&(((struct w83781d_data *) (client->data))->lm75[0]));
|
||||
i2c_detach_client(&(((struct w83781d_data *) (client->data))->lm75[1]));
|
||||
kfree(((struct w83781d_data *) (client->data))->lm75);
|
||||
}
|
||||
kfree(client);
|
||||
|
||||
return 0;
|
||||
@@ -870,22 +928,28 @@ void w83781d_dec_use (struct i2c_client *client)
|
||||
#endif
|
||||
}
|
||||
|
||||
u16 swap_bytes(u16 val)
|
||||
{
|
||||
return (val >> 8) | (val << 8);
|
||||
}
|
||||
|
||||
/* The SMBus locks itself, usually, but nothing may access the Winbond between
|
||||
bank switches. ISA access must always be locked explicitely!
|
||||
bank switches. ISA access must always be locked explicitly!
|
||||
We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
|
||||
would slow down the W83781D access and should not be necessary.
|
||||
There are some ugly typecasts here, but the good new is - they should
|
||||
There are some ugly typecasts here, but the good news is - they should
|
||||
nowhere else be necessary! */
|
||||
int w83781d_read_value(struct i2c_client *client, u16 reg)
|
||||
{
|
||||
int res,word_sized;
|
||||
int res,word_sized,bank;
|
||||
struct i2c_client *cl;
|
||||
|
||||
word_sized = (((reg & 0xff00) == 0x100) || ((reg & 0xff00) == 0x200)) &&
|
||||
(((reg & 0x00ff) == 0x50) ||
|
||||
((reg & 0x00ff) == 0x53) ||
|
||||
((reg & 0x00ff) == 0x55));
|
||||
down(& (((struct w83781d_data *) (client->data)) -> lock));
|
||||
if (i2c_is_isa_client(client)) {
|
||||
word_sized = (((reg & 0xff00) == 0x100) || ((reg & 0xff00) == 0x200)) &&
|
||||
(((reg & 0x00ff) == 0x50) ||
|
||||
((reg & 0x00ff) == 0x53) ||
|
||||
((reg & 0x00ff) == 0x55));
|
||||
if (reg & 0xff00) {
|
||||
outb_p(W83781D_REG_BANK,client->addr + W83781D_ADDR_REG_OFFSET);
|
||||
outb_p(reg >> 8,client->addr + W83781D_DATA_REG_OFFSET);
|
||||
@@ -901,12 +965,33 @@ int w83781d_read_value(struct i2c_client *client, u16 reg)
|
||||
outb_p(0,client->addr + W83781D_DATA_REG_OFFSET);
|
||||
}
|
||||
} else {
|
||||
if (reg & 0xff00)
|
||||
i2c_smbus_write_byte_data(client,W83781D_REG_BANK, reg >> 8);
|
||||
res = i2c_smbus_read_byte_data(client, reg);
|
||||
if (word_sized)
|
||||
res = (res << 8) + i2c_smbus_read_byte_data(client, reg);
|
||||
if (reg & 0xff00)
|
||||
bank = (reg >> 8) & 0x0f;
|
||||
if (bank > 2)
|
||||
/* switch banks */
|
||||
i2c_smbus_write_byte_data(client,W83781D_REG_BANK, bank);
|
||||
if(bank == 0 || bank > 2) {
|
||||
res = i2c_smbus_read_byte_data(client, reg & 0xff);
|
||||
} else {
|
||||
/* switch to subclient */
|
||||
cl = &(((struct w83781d_data *) (client->data))->lm75[bank - 1]);
|
||||
/* convert from ISA to LM75 I2C addresses */
|
||||
switch (reg & 0xff) {
|
||||
case 0x50:
|
||||
res = swap_bytes(i2c_smbus_read_word_data(cl, 0));
|
||||
break;
|
||||
case 0x52:
|
||||
res = i2c_smbus_read_byte_data(cl, 1);
|
||||
break;
|
||||
case 0x53:
|
||||
res = swap_bytes(i2c_smbus_read_word_data(cl, 2));
|
||||
break;
|
||||
case 0x55:
|
||||
default:
|
||||
res = swap_bytes(i2c_smbus_read_word_data(cl, 3));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bank > 2)
|
||||
i2c_smbus_write_byte_data(client,W83781D_REG_BANK,0);
|
||||
}
|
||||
up( & (((struct w83781d_data *) (client->data)) -> lock));
|
||||
@@ -914,21 +999,21 @@ int w83781d_read_value(struct i2c_client *client, u16 reg)
|
||||
}
|
||||
|
||||
/* The SMBus locks itself, usually, but nothing may access the Winbond between
|
||||
bank switches. ISA access must always be locked explicitely!
|
||||
bank switches. ISA access must always be locked explicitly!
|
||||
We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
|
||||
would slow down the W83781D access and should not be necessary.
|
||||
There are some ugly typecasts here, but the good new is - they should
|
||||
There are some ugly typecasts here, but the good news is - they should
|
||||
nowhere else be necessary! */
|
||||
int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value)
|
||||
{
|
||||
int word_sized;
|
||||
int word_sized,bank;
|
||||
struct i2c_client *cl;
|
||||
|
||||
word_sized = (((reg & 0xff00) == 0x100) || ((reg & 0xff00) == 0x200)) &&
|
||||
(((reg & 0x00ff) == 0x50) ||
|
||||
((reg & 0x00ff) == 0x53) ||
|
||||
((reg & 0x00ff) == 0x55));
|
||||
down( & (((struct w83781d_data *) (client->data)) -> lock));
|
||||
if (i2c_is_isa_client(client)) {
|
||||
word_sized = (((reg & 0xff00) == 0x100) || ((reg & 0xff00) == 0x200)) &&
|
||||
(((reg & 0x00ff) == 0x53) ||
|
||||
((reg & 0x00ff) == 0x55));
|
||||
if (reg & 0xff00) {
|
||||
outb_p(W83781D_REG_BANK,client->addr + W83781D_ADDR_REG_OFFSET);
|
||||
outb_p(reg >> 8,client->addr + W83781D_DATA_REG_OFFSET);
|
||||
@@ -944,14 +1029,29 @@ int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value)
|
||||
outb_p(0,client->addr + W83781D_DATA_REG_OFFSET);
|
||||
}
|
||||
} else {
|
||||
if (reg & 0xff00)
|
||||
i2c_smbus_write_byte_data(client,W83781D_REG_BANK, reg >> 8);
|
||||
if (word_sized) {
|
||||
i2c_smbus_write_byte_data(client, reg, value >> 8);
|
||||
i2c_smbus_write_byte_data(client, reg+1, value &0xff);
|
||||
} else
|
||||
i2c_smbus_write_byte_data(client, reg, value &0xff);
|
||||
if (reg & 0xff00)
|
||||
bank = (reg >> 8) & 0x0f;
|
||||
if (bank > 2)
|
||||
/* switch banks */
|
||||
i2c_smbus_write_byte_data(client,W83781D_REG_BANK, bank);
|
||||
if(bank == 0 || bank > 2) {
|
||||
i2c_smbus_write_byte_data(client, reg & 0xff, value & 0xff);
|
||||
} else {
|
||||
/* switch to subclient */
|
||||
cl = &(((struct w83781d_data *) (client->data))->lm75[bank - 1]);
|
||||
/* convert from ISA to LM75 I2C addresses */
|
||||
switch (reg & 0xff) {
|
||||
case 0x52:
|
||||
i2c_smbus_write_byte_data(cl, 1, value & 0xff);
|
||||
break;
|
||||
case 0x53:
|
||||
i2c_smbus_write_word_data(cl, 2, swap_bytes(value));
|
||||
break;
|
||||
case 0x55:
|
||||
i2c_smbus_write_word_data(cl, 3, swap_bytes(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bank > 2)
|
||||
i2c_smbus_write_byte_data(client,W83781D_REG_BANK,0);
|
||||
}
|
||||
up( & (((struct w83781d_data *) (client->data)) -> lock));
|
||||
|
||||
Reference in new issue
Block a user