w83781d.c
来自「linux 内核源代码」· C语言 代码 · 共 1,992 行 · 第 1/4 页
C
1,992 行
/* w83781d.c - Part of lm_sensors, Linux kernel modules for hardware monitoring Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark Studebaker <mdsxyz123@yahoo.com> Copyright (c) 2007 Jean Delvare <khali@linux-fr.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*//* Supports following chips: Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA as99127f 7 3 0 3 0x31 0x12c3 yes no as99127f rev.2 (type_name = as99127f) 0x31 0x5ca3 yes no w83781d 7 3 0 3 0x10-1 0x5ca3 yes yes w83627hf 9 3 2 3 0x21 0x5ca3 yes yes(LPC) w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no*/#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/jiffies.h>#include <linux/i2c.h>#include <linux/platform_device.h>#include <linux/ioport.h>#include <linux/hwmon.h>#include <linux/hwmon-vid.h>#include <linux/hwmon-sysfs.h>#include <linux/sysfs.h>#include <linux/err.h>#include <linux/mutex.h>#include <asm/io.h>#include "lm75.h"/* ISA device, if found */static struct platform_device *pdev;/* Addresses to scan */static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };static unsigned short isa_address = 0x290;/* Insmod parameters */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");/* Constants specified below *//* Length of ISA address segment */#define W83781D_EXTENT 8/* Where are the ISA address/data registers relative to the base address */#define W83781D_ADDR_REG_OFFSET 5#define W83781D_DATA_REG_OFFSET 6/* The device registers *//* in nr from 0 to 8 */#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ (0x554 + (((nr) - 7) * 2)))#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ (0x555 + (((nr) - 7) * 2)))#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ (0x550 + (nr) - 7))/* fan nr from 0 to 2 */#define W83781D_REG_FAN_MIN(nr) (0x3b + (nr))#define W83781D_REG_FAN(nr) (0x28 + (nr))#define W83781D_REG_BANK 0x4E#define W83781D_REG_TEMP2_CONFIG 0x152#define W83781D_REG_TEMP3_CONFIG 0x252/* temp nr from 1 to 3 */#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ ((nr == 2) ? (0x0150) : \ (0x27)))#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ ((nr == 2) ? (0x153) : \ (0x3A)))#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ ((nr == 2) ? (0x155) : \ (0x39)))#define W83781D_REG_CONFIG 0x40/* Interrupt status (W83781D, AS99127F) */#define W83781D_REG_ALARM1 0x41#define W83781D_REG_ALARM2 0x42/* 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#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */#define W83781D_REG_VID_FANDIV 0x47#define W83781D_REG_CHIPID 0x49#define W83781D_REG_WCHIPID 0x58#define W83781D_REG_CHIPMAN 0x4F#define W83781D_REG_PIN 0x4B/* 782D/783S only */#define W83781D_REG_VBAT 0x5D/* PWM 782D (1-4) and 783S (1-2) only */static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };#define W83781D_REG_PWMCLK12 0x5C#define W83781D_REG_PWMCLK34 0x45C#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 *//* Sensor selection - not on 781d */#define W83781D_REG_SCFG1 0x5Dstatic const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };#define W83781D_REG_SCFG2 0x59static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };#define W83781D_DEFAULT_BETA 3435/* RT Table registers */#define W83781D_REG_RT_IDX 0x50#define W83781D_REG_RT_VAL 0x51/* Conversions */#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)#define IN_FROM_REG(val) ((val) * 16)static inline u8FAN_TO_REG(long rpm, int div){ if (rpm == 0) return 255; rpm = SENSORS_LIMIT(rpm, 1, 1000000); return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);}static inline longFAN_FROM_REG(u8 val, int div){ if (val == 0) return -1; if (val == 255) return 0; return 1350000 / (val * div);}#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)#define TEMP_FROM_REG(val) ((val) * 1000)#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \ (val) ^ 0x7fff : (val))#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \ (~(val)) & 0x7fff : (val) & 0xffffff)#define DIV_FROM_REG(val) (1 << (val))static inline u8DIV_TO_REG(long val, enum chips type){ int i; val = SENSORS_LIMIT(val, 1, ((type == w83781d || type == as99127f) ? 8 : 128)) >> 1; for (i = 0; i < 7; i++) { if (val == 0) break; val >>= 1; } return i;}/* There are some complications in a module like this. First off, W83781D chips may be both present on the SMBus and the ISA bus, and we have to handle those cases separately at some places. Second, there might be several W83781D chips available (well, actually, that is probably never done; but it is a clean illustration of how to handle a case like that). Finally, a specific chip may be attached to *both* ISA and SMBus, and we would not like to detect it double. Fortunately, in the case of the W83781D at least, a register tells us what SMBus address we are on, so that helps a bit - except if there could be more than one SMBus. Groan. No solution for this yet. *//* For ISA chips, we abuse the i2c_client addr and name fields. We also use the driver field to differentiate between I2C and ISA chips. */struct w83781d_data { struct i2c_client client; struct device *hwmon_dev; struct mutex lock; enum chips type; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ struct i2c_client *lm75[2]; /* for secondary I2C addresses */ /* array of 2 pointers to 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 */ u8 fan[3]; /* Register value */ u8 fan_min[3]; /* Register value */ s8 temp; /* Register value */ s8 temp_max; /* Register value */ s8 temp_max_hyst; /* Register value */ u16 temp_add[2]; /* Register value */ u16 temp_max_add[2]; /* Register value */ u16 temp_max_hyst_add[2]; /* Register value */ u8 fan_div[3]; /* Register encoding, shifted right */ u8 vid; /* Register encoding, combined */ u32 alarms; /* Register encoding, combined */ u32 beep_mask; /* Register encoding, combined */ u8 beep_enable; /* Boolean */ u8 pwm[4]; /* Register value */ u8 pwm2_enable; /* Boolean */ u16 sens[3]; /* 782D/783S only. 1 = pentium diode; 2 = 3904 diode; 4 = thermistor */ u8 vrm;};static int w83781d_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 __devinit w83781d_isa_probe(struct platform_device *pdev);static int __devexit w83781d_isa_remove(struct platform_device *pdev);static int w83781d_read_value(struct w83781d_data *data, u16 reg);static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);static struct w83781d_data *w83781d_update_device(struct device *dev);static void w83781d_init_device(struct device *dev);static struct i2c_driver w83781d_driver = { .driver = { .name = "w83781d", }, .id = I2C_DRIVERID_W83781D, .attach_adapter = w83781d_attach_adapter, .detach_client = w83781d_detach_client,};static struct platform_driver w83781d_isa_driver = { .driver = { .owner = THIS_MODULE, .name = "w83781d", }, .probe = w83781d_isa_probe, .remove = w83781d_isa_remove,};/* following are the sysfs callback functions */#define show_in_reg(reg) \static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \ char *buf) \{ \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = w83781d_update_device(dev); \ return sprintf(buf, "%ld\n", \ (long)IN_FROM_REG(data->reg[attr->index])); \}show_in_reg(in);show_in_reg(in_min);show_in_reg(in_max);#define store_in_reg(REG, reg) \static ssize_t store_in_##reg (struct device *dev, struct device_attribute \ *da, const char *buf, size_t count) \{ \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = dev_get_drvdata(dev); \ int nr = attr->index; \ u32 val; \ \ val = simple_strtoul(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->in_##reg[nr] = IN_TO_REG(val); \ w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \ \ mutex_unlock(&data->update_lock); \ return count; \}store_in_reg(MIN, min);store_in_reg(MAX, max);#define sysfs_in_offsets(offset) \static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ show_in, NULL, offset); \static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ show_in_min, store_in_min, offset); \static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ show_in_max, store_in_max, offset)sysfs_in_offsets(0);sysfs_in_offsets(1);sysfs_in_offsets(2);sysfs_in_offsets(3);sysfs_in_offsets(4);sysfs_in_offsets(5);sysfs_in_offsets(6);sysfs_in_offsets(7);sysfs_in_offsets(8);#define show_fan_reg(reg) \static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \ char *buf) \{ \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = w83781d_update_device(dev); \ return sprintf(buf,"%ld\n", \ FAN_FROM_REG(data->reg[attr->index], \ DIV_FROM_REG(data->fan_div[attr->index]))); \}show_fan_reg(fan);show_fan_reg(fan_min);static ssize_tstore_fan_min(struct device *dev, struct device_attribute *da, const char *buf, size_t count){ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct w83781d_data *data = dev_get_drvdata(dev); int nr = attr->index; u32 val; val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]); mutex_unlock(&data->update_lock); return count;}static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, show_fan_min, store_fan_min, 0);static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR, show_fan_min, store_fan_min, 1);static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR, show_fan_min, store_fan_min, 2);#define show_temp_reg(reg) \static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \ char *buf) \{ \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = w83781d_update_device(dev); \ int nr = attr->index; \ if (nr >= 2) { /* TEMP2 and TEMP3 */ \ return sprintf(buf,"%d\n", \ LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ } else { /* TEMP1 */ \ return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ } \}show_temp_reg(temp);show_temp_reg(temp_max);show_temp_reg(temp_max_hyst);#define store_temp_reg(REG, reg) \static ssize_t store_temp_##reg (struct device *dev, \ struct device_attribute *da, const char *buf, size_t count) \{ \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = dev_get_drvdata(dev); \ int nr = attr->index; \ long val; \ \ val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ \ if (nr >= 2) { /* TEMP2 and TEMP3 */ \ data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \ data->temp_##reg##_add[nr-2]); \ } else { /* TEMP1 */ \ data->temp_##reg = TEMP_TO_REG(val); \ w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \ data->temp_##reg); \ } \ \ mutex_unlock(&data->update_lock); \ return count; \}store_temp_reg(OVER, max);store_temp_reg(HYST, max_hyst);#define sysfs_temp_offsets(offset) \static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ show_temp, NULL, offset); \static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ show_temp_max, store_temp_max, offset); \static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ show_temp_max_hyst, store_temp_max_hyst, offset);sysfs_temp_offsets(1);sysfs_temp_offsets(2);sysfs_temp_offsets(3);static ssize_tshow_vid_reg(struct device *dev, struct device_attribute *attr, char *buf){ struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));}static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);static ssize_tshow_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf){ struct w83781d_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm);}static ssize_tstore_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct w83781d_data *data = dev_get_drvdata(dev); u32 val; val = simple_strtoul(buf, NULL, 10); data->vrm = val; return count;}static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);static ssize_tshow_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf){ struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%u\n", data->alarms);}static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf){ struct w83781d_data *data = w83781d_update_device(dev); int bitnr = to_sensor_dev_attr(attr)->index; return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);}/* The W83781D has a single alarm bit for temp2 and temp3 */static ssize_t show_temp3_alarm(struct device *dev, struct device_attribute *attr, char *buf){ struct w83781d_data *data = w83781d_update_device(dev); int bitnr = (data->type == w83781d) ? 5 : 13; return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?