diff options
author | Jean Delvare <khali@linux-fr.org> | 2007-10-10 10:30:23 -0400 |
---|---|---|
committer | Mark M. Hoffman <mhoffman@lightlink.com> | 2007-10-13 20:37:19 -0400 |
commit | d58df9cd788e6fb4962e1c8d5ba7b8b95d639a44 (patch) | |
tree | 90a4d4b4ed5dc30f0e186a835f430bd8be4fb259 | |
parent | c09c5184a26158da32801e89d5849d774605f0dd (diff) |
hwmon: (w83627hf) don't assume bank 0
The bank switching code assumes that the bank selector is set to 0
when the driver is loaded. This might not be the case. This is exactly
the same bug as was fixed in the w83627ehf driver two months ago:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=0956895aa6f8dc6a33210967252fd7787652537d
In practice, this bug was causing the sensor thermal types to be
improperly reported for my W83627THF the first time I was loading the
w83627hf driver. From the driver history, I'd say that it has been
broken since September 2005 (when we stopped resetting the chip by
default at driver load.)
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Mark M. Hoffman <mhoffman@lightlink.com>
-rw-r--r-- | drivers/hwmon/w83627hf.c | 44 |
1 files changed, 22 insertions, 22 deletions
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 2169d8c8bbe4..20ae425a1980 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c | |||
@@ -1319,6 +1319,24 @@ static int __devexit w83627hf_remove(struct platform_device *pdev) | |||
1319 | } | 1319 | } |
1320 | 1320 | ||
1321 | 1321 | ||
1322 | /* Registers 0x50-0x5f are banked */ | ||
1323 | static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg) | ||
1324 | { | ||
1325 | if ((reg & 0x00f0) == 0x50) { | ||
1326 | outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); | ||
1327 | outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET); | ||
1328 | } | ||
1329 | } | ||
1330 | |||
1331 | /* Not strictly necessary, but play it safe for now */ | ||
1332 | static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg) | ||
1333 | { | ||
1334 | if (reg & 0xff00) { | ||
1335 | outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); | ||
1336 | outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); | ||
1337 | } | ||
1338 | } | ||
1339 | |||
1322 | static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) | 1340 | static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) |
1323 | { | 1341 | { |
1324 | int res, word_sized; | 1342 | int res, word_sized; |
@@ -1329,12 +1347,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) | |||
1329 | && (((reg & 0x00ff) == 0x50) | 1347 | && (((reg & 0x00ff) == 0x50) |
1330 | || ((reg & 0x00ff) == 0x53) | 1348 | || ((reg & 0x00ff) == 0x53) |
1331 | || ((reg & 0x00ff) == 0x55)); | 1349 | || ((reg & 0x00ff) == 0x55)); |
1332 | if (reg & 0xff00) { | 1350 | w83627hf_set_bank(data, reg); |
1333 | outb_p(W83781D_REG_BANK, | ||
1334 | data->addr + W83781D_ADDR_REG_OFFSET); | ||
1335 | outb_p(reg >> 8, | ||
1336 | data->addr + W83781D_DATA_REG_OFFSET); | ||
1337 | } | ||
1338 | outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); | 1351 | outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); |
1339 | res = inb_p(data->addr + W83781D_DATA_REG_OFFSET); | 1352 | res = inb_p(data->addr + W83781D_DATA_REG_OFFSET); |
1340 | if (word_sized) { | 1353 | if (word_sized) { |
@@ -1344,11 +1357,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) | |||
1344 | (res << 8) + inb_p(data->addr + | 1357 | (res << 8) + inb_p(data->addr + |
1345 | W83781D_DATA_REG_OFFSET); | 1358 | W83781D_DATA_REG_OFFSET); |
1346 | } | 1359 | } |
1347 | if (reg & 0xff00) { | 1360 | w83627hf_reset_bank(data, reg); |
1348 | outb_p(W83781D_REG_BANK, | ||
1349 | data->addr + W83781D_ADDR_REG_OFFSET); | ||
1350 | outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); | ||
1351 | } | ||
1352 | mutex_unlock(&data->lock); | 1361 | mutex_unlock(&data->lock); |
1353 | return res; | 1362 | return res; |
1354 | } | 1363 | } |
@@ -1419,12 +1428,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) | |||
1419 | || ((reg & 0xff00) == 0x200)) | 1428 | || ((reg & 0xff00) == 0x200)) |
1420 | && (((reg & 0x00ff) == 0x53) | 1429 | && (((reg & 0x00ff) == 0x53) |
1421 | || ((reg & 0x00ff) == 0x55)); | 1430 | || ((reg & 0x00ff) == 0x55)); |
1422 | if (reg & 0xff00) { | 1431 | w83627hf_set_bank(data, reg); |
1423 | outb_p(W83781D_REG_BANK, | ||
1424 | data->addr + W83781D_ADDR_REG_OFFSET); | ||
1425 | outb_p(reg >> 8, | ||
1426 | data->addr + W83781D_DATA_REG_OFFSET); | ||
1427 | } | ||
1428 | outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); | 1432 | outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); |
1429 | if (word_sized) { | 1433 | if (word_sized) { |
1430 | outb_p(value >> 8, | 1434 | outb_p(value >> 8, |
@@ -1434,11 +1438,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) | |||
1434 | } | 1438 | } |
1435 | outb_p(value & 0xff, | 1439 | outb_p(value & 0xff, |
1436 | data->addr + W83781D_DATA_REG_OFFSET); | 1440 | data->addr + W83781D_DATA_REG_OFFSET); |
1437 | if (reg & 0xff00) { | 1441 | w83627hf_reset_bank(data, reg); |
1438 | outb_p(W83781D_REG_BANK, | ||
1439 | data->addr + W83781D_ADDR_REG_OFFSET); | ||
1440 | outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); | ||
1441 | } | ||
1442 | mutex_unlock(&data->lock); | 1442 | mutex_unlock(&data->lock); |
1443 | return 0; | 1443 | return 0; |
1444 | } | 1444 | } |