📄 w83627hf.c
字号:
/* w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware monitoring Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark Studebaker <mdsxyz123@yahoo.com> Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.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 w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) For other winbond chips, and for i2c support in the above chips, use w83781d.c. Note: automatic ("cruise") fan control for 697, 637 & 627thf not supported yet.*/#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/i2c.h>#include <linux/i2c-sensor.h>#include <linux/i2c-vid.h>#include <asm/io.h>#include "lm75.h"static int force_addr;MODULE_PARM(force_addr, "i");MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors");static int force_i2c = 0x1f;MODULE_PARM(force_i2c, "i");MODULE_PARM_DESC(force_i2c, "Initialize the i2c address of the sensors");/* Addresses to scan */static unsigned short normal_i2c[] = { I2C_CLIENT_END };static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };/* Insmod parameters */SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf);static int init = 1;MODULE_PARM(init, "i");MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");/* modified from kernel/include/traps.c */#define REG 0x2e /* The register to read/write */#define DEV 0x07 /* Register: Logical device select */#define VAL 0x2f /* The value to read/write *//* logical device numbers for superio_select (below) */#define W83627HF_LD_FDC 0x00#define W83627HF_LD_PRT 0x01#define W83627HF_LD_UART1 0x02#define W83627HF_LD_UART2 0x03#define W83627HF_LD_KBC 0x05#define W83627HF_LD_CIR 0x06 /* w83627hf only */#define W83627HF_LD_GAME 0x07#define W83627HF_LD_MIDI 0x07#define W83627HF_LD_GPIO1 0x07#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */#define W83627HF_LD_GPIO2 0x08#define W83627HF_LD_GPIO3 0x09#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */#define W83627HF_LD_ACPI 0x0a#define W83627HF_LD_HWM 0x0b#define DEVID 0x20 /* Register: Device ID */#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */#define W83627THF_GPIO5_INVR 0xf5 /* w83627thf only */static inline voidsuperio_outb(int reg, int val){ outb(reg, REG); outb(val, VAL);}static inline intsuperio_inb(int reg){ outb(reg, REG); return inb(VAL);}static inline voidsuperio_select(int ld){ outb(DEV, REG); outb(ld, VAL);}static inline voidsuperio_enter(void){ outb(0x87, REG); outb(0x87, REG);}static inline voidsuperio_exit(void){ outb(0xAA, REG);}#define W627_DEVID 0x52#define W627THF_DEVID 0x82#define W697_DEVID 0x60#define W637_DEVID 0x70#define WINB_ACT_REG 0x30#define WINB_BASE_REG 0x60/* Constants specified below *//* Length of ISA address segment */#define WINB_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 W83781D registers *//* The W83782D registers for nr=7,8 are in bank 5 */#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))#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))#define W83781D_REG_FAN(nr) (0x27 + (nr))#define W83781D_REG_TEMP2_CONFIG 0x152#define W83781D_REG_TEMP3_CONFIG 0x252#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_BANK 0x4E#define W83781D_REG_CONFIG 0x40#define W83781D_REG_ALARM1 0x41#define W83781D_REG_ALARM2 0x42#define W83781D_REG_ALARM3 0x450#define W83781D_REG_IRQ 0x4C#define W83781D_REG_BEEP_CONFIG 0x4D#define W83781D_REG_BEEP_INTS1 0x56#define W83781D_REG_BEEP_INTS2 0x57#define W83781D_REG_BEEP_INTS3 0x453#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#define W83781D_REG_VBAT 0x5D#define W83627HF_REG_PWM1 0x5A#define W83627HF_REG_PWM2 0x5B#define W83627HF_REG_PWMCLK12 0x5C#define W83627THF_REG_PWM1 0x01 /* 697HF and 637HF too */#define W83627THF_REG_PWM2 0x03 /* 697HF and 637HF too */#define W83627THF_REG_PWM3 0x11 /* 637HF too */#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF too */static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, W83627THF_REG_PWM3 };#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])#define W83781D_REG_I2C_ADDR 0x48#define W83781D_REG_I2C_SUBADDR 0x4A/* Sensor selection */#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/* Conversions. Limit checking is only done on the TO_REG variants. Note that you should be a bit careful with which arguments these macros are called: arguments may be evaluated more than once. Fixing this is just not worth it. */#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255))#define IN_FROM_REG(val) ((val) * 16)static inline u8 FAN_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);}#define TEMP_MIN (-128000)#define TEMP_MAX ( 127000)/* TEMP: 0.001C/bit (-128C to +127C) REG: 1C/bit, two's complement */static u8 TEMP_TO_REG(int temp){ int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); ntemp += (ntemp<0 ? -500 : 500); return (u8)(ntemp / 1000);}static int TEMP_FROM_REG(u8 reg){ return (s8)reg * 1000;}#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))#define BEEP_MASK_FROM_REG(val) (val)#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0)#define DIV_FROM_REG(val) (1 << (val))static inline u8 DIV_TO_REG(long val){ int i; val = SENSORS_LIMIT(val, 1, 128) >> 1; for (i = 0; i < 6; i++) { if (val == 0) break; val >>= 1; } return ((u8) i);}/* For each registered chip, we need to keep some data in memory. That data is pointed to by w83627hf_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new client is allocated. */struct w83627hf_data { struct i2c_client client; struct semaphore lock; enum chips type; struct semaphore update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ struct i2c_client *lm75; /* for secondary I2C addresses */ /* pointer to array of 2 subclients */ u8 in[9]; /* Register value */ u8 in_max[9]; /* Register value */ u8 in_min[9]; /* Register value */ u8 fan[3]; /* Register value */ u8 fan_min[3]; /* Register value */ u8 temp; u8 temp_max; /* Register value */ u8 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[3]; /* Register value */ u8 pwmenable[3]; /* bool */ u16 sens[3]; /* 782D/783S only. 1 = pentium diode; 2 = 3904 diode; 3000-5000 = thermistor beta. Default = 3435. Other Betas unimplemented */ u8 vrm; u8 vrm_ovt; /* Register value, 627thf & 637hf only */};static int w83627hf_attach_adapter(struct i2c_adapter *adapter);static int w83627hf_detect(struct i2c_adapter *adapter, int address, int kind);static int w83627hf_detach_client(struct i2c_client *client);static int w83627hf_read_value(struct i2c_client *client, u16 register);static int w83627hf_write_value(struct i2c_client *client, u16 register, u16 value);static struct w83627hf_data *w83627hf_update_device(struct device *dev);static void w83627hf_init_client(struct i2c_client *client);static struct i2c_driver w83627hf_driver = { .owner = THIS_MODULE, .name = "w83627hf", .id = I2C_DRIVERID_W83627HF, .flags = I2C_DF_NOTIFY, .attach_adapter = w83627hf_attach_adapter, .detach_client = w83627hf_detach_client,};/* following are the sysfs callback functions */#define show_in_reg(reg) \static ssize_t show_##reg (struct device *dev, char *buf, int nr) \{ \ struct w83627hf_data *data = w83627hf_update_device(dev); \ return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \}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, const char *buf, size_t count, int nr) \{ \ struct i2c_client *client = to_i2c_client(dev); \ struct w83627hf_data *data = i2c_get_clientdata(client); \ u32 val; \ \ val = simple_strtoul(buf, NULL, 10); \ data->in_##reg[nr] = IN_TO_REG(val); \ w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \ data->in_##reg[nr]); \ \ return count; \}store_in_reg(MIN, min)store_in_reg(MAX, max)#define sysfs_in_offset(offset) \static ssize_t \show_regs_in_##offset (struct device *dev, char *buf) \{ \ return show_in(dev, buf, 0x##offset); \} \static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);#define sysfs_in_reg_offset(reg, offset) \static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \{ \ return show_in_##reg (dev, buf, 0x##offset); \} \static ssize_t \store_regs_in_##reg##offset (struct device *dev, \ const char *buf, size_t count) \{ \ return store_in_##reg (dev, buf, count, 0x##offset); \} \static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \ show_regs_in_##reg##offset, store_regs_in_##reg##offset);#define sysfs_in_offsets(offset) \sysfs_in_offset(offset) \sysfs_in_reg_offset(min, offset) \sysfs_in_reg_offset(max, offset)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);/* use a different set of functions for in0 */static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg){ long in0; if ((data->vrm_ovt & 0x01) && (w83627thf == data->type || w83637hf == data->type)) /* use VRM9 calculation */ in0 = (long)((reg * 488 + 70000 + 50) / 100); else /* use VRM8 (standard) calculation */ in0 = (long)IN_FROM_REG(reg); return sprintf(buf,"%ld\n", in0);}static ssize_t show_regs_in_0(struct device *dev, char *buf){ struct w83627hf_data *data = w83627hf_update_device(dev); return show_in_0(data, buf, data->in[0]);}static ssize_t show_regs_in_min0(struct device *dev, char *buf){ struct w83627hf_data *data = w83627hf_update_device(dev); return show_in_0(data, buf, data->in_min[0]);}static ssize_t show_regs_in_max0(struct device *dev, char *buf){ struct w83627hf_data *data = w83627hf_update_device(dev); return show_in_0(data, buf, data->in_max[0]);}static ssize_t store_regs_in_min0(struct device *dev, const char *buf, size_t count){ struct i2c_client *client = to_i2c_client(dev); struct w83627hf_data *data = i2c_get_clientdata(client); u32 val; val = simple_strtoul(buf, NULL, 10); if ((data->vrm_ovt & 0x01) && (w83627thf == data->type || w83637hf == data->type)) /* use VRM9 calculation */ data->in_min[0] = (u8)(((val * 100) - 70000 + 244) / 488); else /* use VRM8 (standard) calculation */ data->in_min[0] = IN_TO_REG(val); w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]); return count;}static ssize_t store_regs_in_max0(struct device *dev, const char *buf, size_t count){ struct i2c_client *client = to_i2c_client(dev); struct w83627hf_data *data = i2c_get_clientdata(client); u32 val; val = simple_strtoul(buf, NULL, 10); if ((data->vrm_ovt & 0x01) && (w83627thf == data->type || w83637hf == data->type)) /* use VRM9 calculation */ data->in_max[0] = (u8)(((val * 100) - 70000 + 244) / 488); else /* use VRM8 (standard) calculation */ data->in_max[0] = IN_TO_REG(val); w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]); return count;}static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, show_regs_in_min0, store_regs_in_min0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -