#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
+#include <linux/mutex.h>
#include <asm/io.h>
#include "lm75.h"
I2C_CLIENT_MODULE_PARM(force_subclients, "List of subclient addresses: "
"{bus, clientaddr, subclientaddr1, subclientaddr2}");
+static int reset;
+module_param(reset, bool, 0);
+MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
+
static int init = 1;
module_param(init, bool, 0);
MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
(0x39)))
#define W83781D_REG_CONFIG 0x40
+
+/* Interrupt status (W83781D, AS99127F) */
#define W83781D_REG_ALARM1 0x41
#define W83781D_REG_ALARM2 0x42
-#define W83781D_REG_ALARM3 0x450 /* not on W83781D */
-#define W83781D_REG_IRQ 0x4C
+/* Real-time status (W83782D, W83783S, W83627HF) */
+#define W83782D_REG_ALARM1 0x459
+#define W83782D_REG_ALARM2 0x45A
+#define W83782D_REG_ALARM3 0x45B
+
#define W83781D_REG_BEEP_CONFIG 0x4D
#define W83781D_REG_BEEP_INTS1 0x56
#define W83781D_REG_BEEP_INTS2 0x57
struct w83781d_data {
struct i2c_client client;
struct class_device *class_dev;
- struct semaphore lock;
+ struct mutex lock;
enum chips type;
- struct semaphore update_lock;
+ struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
static int w83781d_detach_client(struct i2c_client *client);
-static int w83781d_read_value(struct i2c_client *client, u16 register);
-static int w83781d_write_value(struct i2c_client *client, u16 register,
- u16 value);
+static int w83781d_read_value(struct i2c_client *client, u16 reg);
+static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value);
static struct w83781d_data *w83781d_update_device(struct device *dev);
static void w83781d_init_client(struct i2c_client *client);
static struct i2c_driver w83781d_driver = {
- .owner = THIS_MODULE,
- .name = "w83781d",
+ .driver = {
+ .name = "w83781d",
+ },
.id = I2C_DRIVERID_W83781D,
.attach_adapter = w83781d_attach_adapter,
.detach_client = w83781d_detach_client,
};
static struct i2c_driver w83781d_isa_driver = {
- .owner = THIS_MODULE,
- .name = "w83781d-isa",
+ .driver = {
+ .name = "w83781d-isa",
+ },
.attach_adapter = w83781d_isa_attach_adapter,
.detach_client = w83781d_detach_client,
};
\
val = simple_strtoul(buf, NULL, 10) / 10; \
\
- down(&data->update_lock); \
+ mutex_lock(&data->update_lock); \
data->in_##reg[nr] = IN_TO_REG(val); \
w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
\
- up(&data->update_lock); \
+ mutex_unlock(&data->update_lock); \
return count; \
}
store_in_reg(MIN, min);
val = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->fan_min[nr - 1] =
FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
w83781d_write_value(client, W83781D_REG_FAN_MIN(nr),
data->fan_min[nr - 1]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
\
val = simple_strtol(buf, NULL, 10); \
\
- down(&data->update_lock); \
+ mutex_lock(&data->update_lock); \
\
if (nr >= 2) { /* TEMP2 and TEMP3 */ \
data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
data->temp_##reg); \
} \
\
- up(&data->update_lock); \
+ mutex_unlock(&data->update_lock); \
return count; \
}
store_temp_reg(OVER, max);
val = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
w83781d_write_value(client, W83781D_REG_BEEP_INTS2,
val2 | data->beep_enable << 7);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
- least suprise; the user doesn't expect the fan minimum to change just
+ least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t
store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
u8 reg;
unsigned long val = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
/* Save fan_min */
min = FAN_FROM_REG(data->fan_min[nr],
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
val = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->pwm[nr - 1] = PWM_TO_REG(val);
w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
val = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
switch (val) {
case 0:
break;
default:
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return -EINVAL;
}
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
val = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
switch (val) {
case 1: /* PII/Celeron diode */
break;
}
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
if (is_isa)
if (!request_region(address, W83781D_EXTENT,
- w83781d_isa_driver.name)) {
+ w83781d_isa_driver.driver.name)) {
dev_dbg(&adapter->dev, "Request of region "
"0x%x-0x%x for w83781d failed\n", address,
address + W83781D_EXTENT - 1);
new_client = &data->client;
i2c_set_clientdata(new_client, data);
new_client->addr = address;
- init_MUTEX(&data->lock);
+ mutex_init(&data->lock);
new_client->adapter = adapter;
new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
new_client->flags = 0;
data->type = kind;
data->valid = 0;
- init_MUTEX(&data->update_lock);
+ mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
int res, word_sized, bank;
struct i2c_client *cl;
- down(&data->lock);
+ mutex_lock(&data->lock);
if (i2c_is_isa_client(client)) {
word_sized = (((reg & 0xff00) == 0x100)
|| ((reg & 0xff00) == 0x200))
if (bank > 2)
i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
}
- up(&data->lock);
+ mutex_unlock(&data->lock);
return res;
}
int word_sized, bank;
struct i2c_client *cl;
- down(&data->lock);
+ mutex_lock(&data->lock);
if (i2c_is_isa_client(client)) {
word_sized = (((reg & 0xff00) == 0x100)
|| ((reg & 0xff00) == 0x200))
if (bank > 2)
i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);
}
- up(&data->lock);
+ mutex_unlock(&data->lock);
return 0;
}
int type = data->type;
u8 tmp;
- if (init && type != as99127f) { /* this resets registers we don't have
+ if (reset && type != as99127f) { /* this resets registers we don't have
documentation for on the as99127f */
+ /* Resetting the chip has been the default for a long time,
+ but it causes the BIOS initializations (fan clock dividers,
+ thermal sensor types...) to be lost, so it is now optional.
+ It might even go away if nobody reports it as being useful,
+ as I see very little reason why this would be needed at
+ all. */
+ dev_info(&client->dev, "If reset=1 solved a problem you were "
+ "having, please report!\n");
+
/* save these registers */
i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
p = w83781d_read_value(client, W83781D_REG_PWMCLK12);
w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
}
+ /* Disable power-on abnormal beep, as advised by the datasheet.
+ Already done if reset=1. */
+ if (init && !reset && type != as99127f) {
+ i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
+ w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
+ }
+
data->vrm = vid_which_vrm();
if ((type != w83781d) && (type != as99127f)) {
W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
}
}
-
- if (type != w83781d) {
- /* enable comparator mode for temp2 and temp3 so
- alarm indication will work correctly */
- i = w83781d_read_value(client, W83781D_REG_IRQ);
- if (!(i & 0x40))
- w83781d_write_value(client, W83781D_REG_IRQ,
- i | 0x40);
- }
}
/* Start monitoring */
struct w83781d_data *data = i2c_get_clientdata(client);
int i;
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
data->fan_div[1] |= (i >> 4) & 0x04;
data->fan_div[2] |= (i >> 5) & 0x04;
}
- data->alarms =
- w83781d_read_value(client,
- W83781D_REG_ALARM1) +
- (w83781d_read_value(client, W83781D_REG_ALARM2) << 8);
if ((data->type == w83782d) || (data->type == w83627hf)) {
- data->alarms |=
- w83781d_read_value(client,
- W83781D_REG_ALARM3) << 16;
+ data->alarms = w83781d_read_value(client,
+ W83782D_REG_ALARM1)
+ | (w83781d_read_value(client,
+ W83782D_REG_ALARM2) << 8)
+ | (w83781d_read_value(client,
+ W83782D_REG_ALARM3) << 16);
+ } else if (data->type == w83783s) {
+ data->alarms = w83781d_read_value(client,
+ W83782D_REG_ALARM1)
+ | (w83781d_read_value(client,
+ W83782D_REG_ALARM2) << 8);
+ } else {
+ /* No real-time status registers, fall back to
+ interrupt status registers */
+ data->alarms = w83781d_read_value(client,
+ W83781D_REG_ALARM1)
+ | (w83781d_read_value(client,
+ W83781D_REG_ALARM2) << 8);
}
i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2);
data->beep_enable = i >> 7;
data->valid = 1;
}
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return data;
}