📄 w83781d.c
字号:
device_create_file_pwm(new_client, 3); device_create_file_pwm(new_client, 4); } if (kind != as99127f && kind != w83781d) { device_create_file_sensor(new_client, 1); device_create_file_sensor(new_client, 2); if (kind != w83783s && kind != w83697hf) device_create_file_sensor(new_client, 3); }#ifdef W83781D_RT if (kind == w83781d) { device_create_file_rt(new_client, 1); device_create_file_rt(new_client, 2); device_create_file_rt(new_client, 3); }#endif return 0;ERROR3: i2c_detach_client(new_client);ERROR2: kfree(data);ERROR1: if (is_isa) release_region(address, W83781D_EXTENT);ERROR0: return err;}static intw83781d_detach_client(struct i2c_client *client){ int err; if (i2c_is_isa_client(client)) release_region(client->addr, W83781D_EXTENT); if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); return err; } if (i2c_get_clientdata(client)==NULL) { /* subclients */ kfree(client); } else { /* main client */ kfree(i2c_get_clientdata(client)); } return 0;}/* The SMBus locks itself, usually, but nothing may access the Winbond between 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 news is - they should nowhere else be necessary! */static intw83781d_read_value(struct i2c_client *client, u16 reg){ struct w83781d_data *data = i2c_get_clientdata(client); int res, word_sized, bank; struct i2c_client *cl; down(&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); } outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); if (word_sized) { outb_p((reg & 0xff) + 1, client->addr + W83781D_ADDR_REG_OFFSET); res = (res << 8) + inb_p(client->addr + W83781D_DATA_REG_OFFSET); } if (reg & 0xff00) { outb_p(W83781D_REG_BANK, client->addr + W83781D_ADDR_REG_OFFSET); outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); } } else { 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 = data->lm75[bank - 1]; /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x50: /* TEMP */ res = swab16(i2c_smbus_read_word_data(cl, 0)); break; case 0x52: /* CONFIG */ res = i2c_smbus_read_byte_data(cl, 1); break; case 0x53: /* HYST */ res = swab16(i2c_smbus_read_word_data(cl, 2)); break; case 0x55: /* OVER */ default: res = swab16(i2c_smbus_read_word_data(cl, 3)); break; } } if (bank > 2) i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); } up(&data->lock); return res;}static intw83781d_write_value(struct i2c_client *client, u16 reg, u16 value){ struct w83781d_data *data = i2c_get_clientdata(client); int word_sized, bank; struct i2c_client *cl; down(&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); } outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); if (word_sized) { outb_p(value >> 8, client->addr + W83781D_DATA_REG_OFFSET); outb_p((reg & 0xff) + 1, client->addr + W83781D_ADDR_REG_OFFSET); } outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET); if (reg & 0xff00) { outb_p(W83781D_REG_BANK, client->addr + W83781D_ADDR_REG_OFFSET); outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); } } else { 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 = data->lm75[bank - 1]; /* convert from ISA to LM75 I2C addresses */ switch (reg & 0xff) { case 0x52: /* CONFIG */ i2c_smbus_write_byte_data(cl, 1, value & 0xff); break; case 0x53: /* HYST */ i2c_smbus_write_word_data(cl, 2, swab16(value)); break; case 0x55: /* OVER */ i2c_smbus_write_word_data(cl, 3, swab16(value)); break; } } if (bank > 2) i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); } up(&data->lock); return 0;}/* Called when we have found a new W83781D. It should set limits, etc. */static voidw83781d_init_client(struct i2c_client *client){ struct w83781d_data *data = i2c_get_clientdata(client); int i, p; int type = data->type; u8 tmp; if (init && type != as99127f) { /* this resets registers we don't have documentation for on the as99127f */ /* save these registers */ i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); p = w83781d_read_value(client, W83781D_REG_PWMCLK12); /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others */ w83781d_write_value(client, W83781D_REG_CONFIG, 0x80); /* Restore the registers and disable power-on abnormal beep. This saves FAN 1/2/3 input/output values set by BIOS. */ w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); w83781d_write_value(client, W83781D_REG_PWMCLK12, p); /* Disable master beep-enable (reset turns it on). Individual beep_mask should be reset to off but for some reason disabling this bit helps some people not get beeped */ w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); } data->vrm = 82; if ((type != w83781d) && (type != as99127f)) { tmp = w83781d_read_value(client, W83781D_REG_SCFG1); for (i = 1; i <= 3; i++) { if (!(tmp & BIT_SCFG1[i - 1])) { data->sens[i - 1] = W83781D_DEFAULT_BETA; } else { if (w83781d_read_value (client, W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) data->sens[i - 1] = 1; else data->sens[i - 1] = 2; } if ((type == w83783s || type == w83697hf) && (i == 2)) break; } }#ifdef W83781D_RT/* Fill up the RT Tables. We assume that they are 32 bytes long, in order for temp 1-3. Data sheet documentation is sparse. We also assume that it is only for the 781D although I suspect that the others support it as well....*/ if (init && type == w83781d) { u16 k = 0;/* Auto-indexing doesn't seem to work... w83781d_write_value(client,W83781D_REG_RT_IDX,0);*/ for (i = 0; i < 3; i++) { int j; for (j = 0; j < 32; j++) { w83781d_write_value(client, W83781D_REG_RT_IDX, k++); data->rt[i][j] = w83781d_read_value(client, W83781D_REG_RT_VAL); } } }#endif /* W83781D_RT */ if (init) { if (type != w83783s && type != w83697hf) { w83781d_write_value(client, W83781D_REG_TEMP3_CONFIG, 0x00); } 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 */ w83781d_write_value(client, W83781D_REG_CONFIG, (w83781d_read_value(client, W83781D_REG_CONFIG) & 0xf7) | 0x01);}static struct w83781d_data *w83781d_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct w83781d_data *data = i2c_get_clientdata(client); int i; down(&data->update_lock); if (time_after (jiffies - data->last_updated, (unsigned long) (HZ + HZ / 2)) || time_before(jiffies, data->last_updated) || !data->valid) { pr_debug("Starting device update\n"); for (i = 0; i <= 8; i++) { if ((data->type == w83783s || data->type == w83697hf) && (i == 1)) continue; /* 783S has no in1 */ data->in[i] = w83781d_read_value(client, W83781D_REG_IN(i)); data->in_min[i] = w83781d_read_value(client, W83781D_REG_IN_MIN(i)); data->in_max[i] = w83781d_read_value(client, W83781D_REG_IN_MAX(i)); if ((data->type != w83782d) && (data->type != w83697hf) && (data->type != w83627hf) && (i == 6)) break; } for (i = 1; i <= 3; i++) { data->fan[i - 1] = w83781d_read_value(client, W83781D_REG_FAN(i)); data->fan_min[i - 1] = w83781d_read_value(client, W83781D_REG_FAN_MIN(i)); } if (data->type != w83781d && data->type != as99127f) { for (i = 1; i <= 4; i++) { data->pwm[i - 1] = w83781d_read_value(client, W83781D_REG_PWM(i)); if ((data->type != w83782d || i2c_is_isa_client(client)) && i == 2) break; } /* Only PWM2 can be disabled */ data->pwmenable[1] = (w83781d_read_value(client, W83781D_REG_PWMCLK12) & 0x08) >> 3; } data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1)); data->temp_max = w83781d_read_value(client, W83781D_REG_TEMP_OVER(1)); data->temp_max_hyst = w83781d_read_value(client, W83781D_REG_TEMP_HYST(1)); data->temp_add[0] = w83781d_read_value(client, W83781D_REG_TEMP(2)); data->temp_max_add[0] = w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); data->temp_max_hyst_add[0] = w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); if (data->type != w83783s && data->type != w83697hf) { data->temp_add[1] = w83781d_read_value(client, W83781D_REG_TEMP(3)); data->temp_max_add[1] = w83781d_read_value(client, W83781D_REG_TEMP_OVER(3)); data->temp_max_hyst_add[1] = w83781d_read_value(client, W83781D_REG_TEMP_HYST(3)); } i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); if (data->type != w83697hf) { data->vid = i & 0x0f; data->vid |= (w83781d_read_value(client, W83781D_REG_CHIPID) & 0x01) << 4; } data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = (i >> 6) & 0x03; if (data->type != w83697hf) { data->fan_div[2] = (w83781d_read_value(client, W83781D_REG_PIN) >> 6) & 0x03; } if ((data->type != w83781d) && (data->type != as99127f)) { i = w83781d_read_value(client, W83781D_REG_VBAT); data->fan_div[0] |= (i >> 3) & 0x04; data->fan_div[1] |= (i >> 4) & 0x04; if (data->type != w83697hf) 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; } i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); data->beep_enable = i >> 7; data->beep_mask = ((i & 0x7f) << 8) + w83781d_read_value(client, W83781D_REG_BEEP_INTS1); if ((data->type != w83781d) && (data->type != as99127f)) { data->beep_mask |= w83781d_read_value(client, W83781D_REG_BEEP_INTS3) << 16; } data->last_updated = jiffies; data->valid = 1; } up(&data->update_lock); return data;}static int __initsensors_w83781d_init(void){ return i2c_add_driver(&w83781d_driver);}static void __exitsensors_w83781d_exit(void){ i2c_del_driver(&w83781d_driver);}MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, " "Philip Edelbrock <phil@netroedge.com>, " "and Mark Studebaker <mdsxyz123@yahoo.com>");MODULE_DESCRIPTION("W83781D driver");MODULE_LICENSE("GPL");module_init(sensors_w83781d_init);module_exit(sensors_w83781d_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -