w83793.c
来自「linux 内核源代码」· C语言 代码 · 共 1,703 行 · 第 1/4 页
C
1,703 行
/* w83793.c - Linux kernel driver for hardware monitoring Copyright (C) 2006 Winbond Electronics Corp. Yuan Mu Rudolf Marek <r.marek@assembler.cz> 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 - version 2. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.*//* Supports following chips: Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA w83793 10 12 8 6 0x7b 0x5ca3 yes no*/#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/i2c.h>#include <linux/hwmon.h>#include <linux/hwmon-vid.h>#include <linux/hwmon-sysfs.h>#include <linux/err.h>#include <linux/mutex.h>/* Addresses to scan */static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };/* Insmod parameters */I2C_CLIENT_INSMOD_1(w83793);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 1 to reset chip, not recommended");/* Address 0x00, 0x0d, 0x0e, 0x0f in all three banks are reserved as ID, Bank Select registers*/#define W83793_REG_BANKSEL 0x00#define W83793_REG_VENDORID 0x0d#define W83793_REG_CHIPID 0x0e#define W83793_REG_DEVICEID 0x0f#define W83793_REG_CONFIG 0x40#define W83793_REG_MFC 0x58#define W83793_REG_FANIN_CTRL 0x5c#define W83793_REG_FANIN_SEL 0x5d#define W83793_REG_I2C_ADDR 0x0b#define W83793_REG_I2C_SUBADDR 0x0c#define W83793_REG_VID_INA 0x05#define W83793_REG_VID_INB 0x06#define W83793_REG_VID_LATCHA 0x07#define W83793_REG_VID_LATCHB 0x08#define W83793_REG_VID_CTRL 0x59static u16 W83793_REG_TEMP_MODE[2] = { 0x5e, 0x5f };#define TEMP_READ 0#define TEMP_CRIT 1#define TEMP_CRIT_HYST 2#define TEMP_WARN 3#define TEMP_WARN_HYST 4/* only crit and crit_hyst affect real-time alarm status current crit crit_hyst warn warn_hyst */static u16 W83793_REG_TEMP[][5] = { {0x1c, 0x78, 0x79, 0x7a, 0x7b}, {0x1d, 0x7c, 0x7d, 0x7e, 0x7f}, {0x1e, 0x80, 0x81, 0x82, 0x83}, {0x1f, 0x84, 0x85, 0x86, 0x87}, {0x20, 0x88, 0x89, 0x8a, 0x8b}, {0x21, 0x8c, 0x8d, 0x8e, 0x8f},};#define W83793_REG_TEMP_LOW_BITS 0x22#define W83793_REG_BEEP(index) (0x53 + (index))#define W83793_REG_ALARM(index) (0x4b + (index))#define W83793_REG_CLR_CHASSIS 0x4a /* SMI MASK4 */#define W83793_REG_IRQ_CTRL 0x50#define W83793_REG_OVT_CTRL 0x51#define W83793_REG_OVT_BEEP 0x52#define IN_READ 0#define IN_MAX 1#define IN_LOW 2static const u16 W83793_REG_IN[][3] = { /* Current, High, Low */ {0x10, 0x60, 0x61}, /* Vcore A */ {0x11, 0x62, 0x63}, /* Vcore B */ {0x12, 0x64, 0x65}, /* Vtt */ {0x14, 0x6a, 0x6b}, /* VSEN1 */ {0x15, 0x6c, 0x6d}, /* VSEN2 */ {0x16, 0x6e, 0x6f}, /* +3VSEN */ {0x17, 0x70, 0x71}, /* +12VSEN */ {0x18, 0x72, 0x73}, /* 5VDD */ {0x19, 0x74, 0x75}, /* 5VSB */ {0x1a, 0x76, 0x77}, /* VBAT */};/* Low Bits of Vcore A/B Vtt Read/High/Low */static const u16 W83793_REG_IN_LOW_BITS[] = { 0x1b, 0x68, 0x69 };static u8 scale_in[] = { 2, 2, 2, 16, 16, 16, 8, 24, 24, 16 };static u8 scale_in_add[] = { 0, 0, 0, 0, 0, 0, 0, 150, 150, 0 };#define W83793_REG_FAN(index) (0x23 + 2 * (index)) /* High byte */#define W83793_REG_FAN_MIN(index) (0x90 + 2 * (index)) /* High byte */#define W83793_REG_PWM_DEFAULT 0xb2#define W83793_REG_PWM_ENABLE 0x207#define W83793_REG_PWM_UPTIME 0xc3 /* Unit in 0.1 second */#define W83793_REG_PWM_DOWNTIME 0xc4 /* Unit in 0.1 second */#define W83793_REG_TEMP_CRITICAL 0xc5#define PWM_DUTY 0#define PWM_START 1#define PWM_NONSTOP 2#define W83793_REG_PWM(index, nr) (((nr) == 0 ? 0xb3 : \ (nr) == 1 ? 0x220 : 0x218) + (index))/* bit field, fan1 is bit0, fan2 is bit1 ... */#define W83793_REG_TEMP_FAN_MAP(index) (0x201 + (index))#define W83793_REG_TEMP_TOL(index) (0x208 + (index))#define W83793_REG_TEMP_CRUISE(index) (0x210 + (index))#define W83793_REG_PWM_STOP_TIME(index) (0x228 + (index))#define W83793_REG_SF2_TEMP(index, nr) (0x230 + ((index) << 4) + (nr))#define W83793_REG_SF2_PWM(index, nr) (0x238 + ((index) << 4) + (nr))static inline unsigned long FAN_FROM_REG(u16 val){ if ((val >= 0xfff) || (val == 0)) return 0; return (1350000UL / val);}static inline u16 FAN_TO_REG(long rpm){ if (rpm <= 0) return 0x0fff; return SENSORS_LIMIT((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);}static inline unsigned long TIME_FROM_REG(u8 reg){ return (reg * 100);}static inline u8 TIME_TO_REG(unsigned long val){ return SENSORS_LIMIT((val + 50) / 100, 0, 0xff);}static inline long TEMP_FROM_REG(s8 reg){ return (reg * 1000);}static inline s8 TEMP_TO_REG(long val, s8 min, s8 max){ return SENSORS_LIMIT((val + (val < 0 ? -500 : 500)) / 1000, min, max);}struct w83793_data { struct i2c_client client; struct i2c_client *lm75[2]; struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ unsigned long last_nonvolatile; /* In jiffies, last time we update the nonvolatile registers */ u8 bank; u8 vrm; u8 vid[2]; u8 in[10][3]; /* Register value, read/high/low */ u8 in_low_bits[3]; /* Additional resolution for VCore A/B Vtt */ u16 has_fan; /* Only fan1- fan5 has own pins */ u16 fan[12]; /* Register value combine */ u16 fan_min[12]; /* Register value combine */ s8 temp[6][5]; /* current, crit, crit_hyst,warn, warn_hyst */ u8 temp_low_bits; /* Additional resolution TD1-TD4 */ u8 temp_mode[2]; /* byte 0: Temp D1-D4 mode each has 2 bits byte 1: Temp R1,R2 mode, each has 1 bit */ u8 temp_critical; /* If reached all fan will be at full speed */ u8 temp_fan_map[6]; /* Temp controls which pwm fan, bit field */ u8 has_pwm; u8 has_temp; u8 has_vid; u8 pwm_enable; /* Register value, each Temp has 1 bit */ u8 pwm_uptime; /* Register value */ u8 pwm_downtime; /* Register value */ u8 pwm_default; /* All fan default pwm, next poweron valid */ u8 pwm[8][3]; /* Register value */ u8 pwm_stop_time[8]; u8 temp_cruise[6]; u8 alarms[5]; /* realtime status registers */ u8 beeps[5]; u8 beep_enable; u8 tolerance[3]; /* Temp tolerance(Smart Fan I/II) */ u8 sf2_pwm[6][7]; /* Smart FanII: Fan duty cycle */ u8 sf2_temp[6][7]; /* Smart FanII: Temp level point */};static u8 w83793_read_value(struct i2c_client *client, u16 reg);static int w83793_write_value(struct i2c_client *client, u16 reg, u8 value);static int w83793_attach_adapter(struct i2c_adapter *adapter);static int w83793_detect(struct i2c_adapter *adapter, int address, int kind);static int w83793_detach_client(struct i2c_client *client);static void w83793_init_client(struct i2c_client *client);static void w83793_update_nonvolatile(struct device *dev);static struct w83793_data *w83793_update_device(struct device *dev);static struct i2c_driver w83793_driver = { .driver = { .name = "w83793", }, .attach_adapter = w83793_attach_adapter, .detach_client = w83793_detach_client,};static ssize_tshow_vrm(struct device *dev, struct device_attribute *attr, char *buf){ struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); return sprintf(buf, "%d\n", data->vrm);}static ssize_tshow_vid(struct device *dev, struct device_attribute *attr, char *buf){ struct w83793_data *data = w83793_update_device(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int index = sensor_attr->index; return sprintf(buf, "%d\n", vid_from_reg(data->vid[index], data->vrm));}static ssize_tstore_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); data->vrm = simple_strtoul(buf, NULL, 10); return count;}#define ALARM_STATUS 0#define BEEP_ENABLE 1static ssize_tshow_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf){ struct w83793_data *data = w83793_update_device(dev); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index >> 3; int bit = sensor_attr->index & 0x07; u8 val; if (ALARM_STATUS == nr) { val = (data->alarms[index] >> (bit)) & 1; } else { /* BEEP_ENABLE */ val = (data->beeps[index] >> (bit)) & 1; } return sprintf(buf, "%u\n", val);}static ssize_tstore_beep(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int index = sensor_attr->index >> 3; int shift = sensor_attr->index & 0x07; u8 beep_bit = 1 << shift; u8 val; val = simple_strtoul(buf, NULL, 10); if (val != 0 && val != 1) return -EINVAL; mutex_lock(&data->update_lock); data->beeps[index] = w83793_read_value(client, W83793_REG_BEEP(index)); data->beeps[index] &= ~beep_bit; data->beeps[index] |= val << shift; w83793_write_value(client, W83793_REG_BEEP(index), data->beeps[index]); mutex_unlock(&data->update_lock); return count;}static ssize_tshow_beep_enable(struct device *dev, struct device_attribute *attr, char *buf){ struct w83793_data *data = w83793_update_device(dev); return sprintf(buf, "%u\n", (data->beep_enable >> 1) & 0x01);}static ssize_tstore_beep_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); u8 val = simple_strtoul(buf, NULL, 10); if (val != 0 && val != 1) return -EINVAL; mutex_lock(&data->update_lock); data->beep_enable = w83793_read_value(client, W83793_REG_OVT_BEEP) & 0xfd; data->beep_enable |= val << 1; w83793_write_value(client, W83793_REG_OVT_BEEP, data->beep_enable); mutex_unlock(&data->update_lock); return count;}/* Write any value to clear chassis alarm */static ssize_tstore_chassis_clear(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); u8 val; mutex_lock(&data->update_lock); val = w83793_read_value(client, W83793_REG_CLR_CHASSIS); val |= 0x80; w83793_write_value(client, W83793_REG_CLR_CHASSIS, val); mutex_unlock(&data->update_lock); return count;}#define FAN_INPUT 0#define FAN_MIN 1static ssize_tshow_fan(struct device *dev, struct device_attribute *attr, char *buf){ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int nr = sensor_attr->nr; int index = sensor_attr->index; struct w83793_data *data = w83793_update_device(dev); u16 val; if (FAN_INPUT == nr) { val = data->fan[index] & 0x0fff; } else { val = data->fan_min[index] & 0x0fff; } return sprintf(buf, "%lu\n", FAN_FROM_REG(val));}static ssize_tstore_fan_min(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); int index = sensor_attr->index; struct i2c_client *client = to_i2c_client(dev); struct w83793_data *data = i2c_get_clientdata(client); u16 val = FAN_TO_REG(simple_strtoul(buf, NULL, 10)); mutex_lock(&data->update_lock); data->fan_min[index] = val; w83793_write_value(client, W83793_REG_FAN_MIN(index), (val >> 8) & 0xff); w83793_write_value(client, W83793_REG_FAN_MIN(index) + 1, val & 0xff); mutex_unlock(&data->update_lock); return count;}#define PWM_DUTY 0#define PWM_START 1#define PWM_NONSTOP 2#define PWM_STOP_TIME 3static ssize_tshow_pwm(struct device *dev, struct device_attribute *attr, char *buf){ struct sensor_device_attribute_2 *sensor_attr = to_sensor_dev_attr_2(attr); struct w83793_data *data = w83793_update_device(dev); u16 val; int nr = sensor_attr->nr; int index = sensor_attr->index; if (PWM_STOP_TIME == nr) val = TIME_FROM_REG(data->pwm_stop_time[index]); else
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?