X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fhwmon%2Fw83781d.c;h=7be469ed0f8f4a41cc30c6ecd48eaf09210fafa8;hb=467c432a4d63349025d92f5dbdd0b9ba8ff40fd5;hp=fd1a59c536302e0d893669e0e7809d9167f2fdff;hpb=cdaf79349c7d24e1d33acb6497849c9e956a33ea;p=linux-2.6 diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index fd1a59c536..7be469ed0f 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include "lm75.h" @@ -56,6 +57,10 @@ I2C_CLIENT_INSMOD_5(w83781d, w83782d, w83783s, w83627hf, as99127f); 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"); @@ -95,11 +100,16 @@ 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 @@ -221,10 +231,10 @@ DIV_TO_REG(long val, enum chips type) 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 */ @@ -262,15 +272,13 @@ static int w83781d_isa_attach_adapter(struct i2c_adapter *adapter); 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 = { .driver = { - .owner = THIS_MODULE, .name = "w83781d", }, .id = I2C_DRIVERID_W83781D, @@ -280,7 +288,6 @@ static struct i2c_driver w83781d_driver = { static struct i2c_driver w83781d_isa_driver = { .driver = { - .owner = THIS_MODULE, .name = "w83781d-isa", }, .attach_adapter = w83781d_isa_attach_adapter, @@ -308,11 +315,11 @@ static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count \ 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); @@ -378,13 +385,13 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr) 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; } @@ -443,7 +450,7 @@ static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t cou \ 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); \ @@ -455,7 +462,7 @@ static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t cou data->temp_##reg); \ } \ \ - up(&data->update_lock); \ + mutex_unlock(&data->update_lock); \ return count; \ } store_temp_reg(OVER, max); @@ -568,7 +575,7 @@ store_beep_reg(struct device *dev, const char *buf, size_t count, 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); @@ -589,7 +596,7 @@ store_beep_reg(struct device *dev, const char *buf, size_t count, w83781d_write_value(client, W83781D_REG_BEEP_INTS2, val2 | data->beep_enable << 7); - up(&data->update_lock); + mutex_unlock(&data->update_lock); return count; } @@ -623,7 +630,7 @@ show_fan_div_reg(struct device *dev, char *buf, int nr) /* 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) @@ -634,7 +641,7 @@ 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], @@ -659,7 +666,7 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int 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; } @@ -706,10 +713,10 @@ store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) 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; } @@ -722,7 +729,7 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) val = simple_strtoul(buf, NULL, 10); - down(&data->update_lock); + mutex_lock(&data->update_lock); switch (val) { case 0: @@ -739,11 +746,11 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) break; default: - up(&data->update_lock); + mutex_unlock(&data->update_lock); return -EINVAL; } - up(&data->update_lock); + mutex_unlock(&data->update_lock); return count; } @@ -805,7 +812,7 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) val = simple_strtoul(buf, NULL, 10); - down(&data->update_lock); + mutex_lock(&data->update_lock); switch (val) { case 1: /* PII/Celeron diode */ @@ -838,7 +845,7 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) break; } - up(&data->update_lock); + mutex_unlock(&data->update_lock); return count; } @@ -1070,7 +1077,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) 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; @@ -1175,7 +1182,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) 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))) @@ -1322,7 +1329,7 @@ w83781d_read_value(struct i2c_client *client, u16 reg) 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)) @@ -1380,7 +1387,7 @@ w83781d_read_value(struct i2c_client *client, u16 reg) if (bank > 2) i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); } - up(&data->lock); + mutex_unlock(&data->lock); return res; } @@ -1391,7 +1398,7 @@ w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) 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)) @@ -1444,7 +1451,7 @@ w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) if (bank > 2) i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); } - up(&data->lock); + mutex_unlock(&data->lock); return 0; } @@ -1456,8 +1463,17 @@ w83781d_init_client(struct i2c_client *client) 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); @@ -1474,6 +1490,13 @@ w83781d_init_client(struct i2c_client *client) 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)) { @@ -1515,15 +1538,6 @@ w83781d_init_client(struct i2c_client *client) 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 */ @@ -1539,7 +1553,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) 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) { @@ -1614,14 +1628,25 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) 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; @@ -1636,7 +1661,7 @@ static struct w83781d_data *w83781d_update_device(struct device *dev) data->valid = 1; } - up(&data->update_lock); + mutex_unlock(&data->update_lock); return data; }