w83627hf.c
来自「linux 内核源代码」· C语言 代码 · 共 1,707 行 · 第 1/4 页
C
1,707 行
/* 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> 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 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) w83687thf 7 3 3 3 0x90 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/jiffies.h>#include <linux/platform_device.h>#include <linux/hwmon.h>#include <linux/hwmon-sysfs.h>#include <linux/hwmon-vid.h>#include <linux/err.h>#include <linux/mutex.h>#include <linux/ioport.h>#include <asm/io.h>#include "lm75.h"static struct platform_device *pdev;#define DRVNAME "w83627hf"enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };static u16 force_addr;module_param(force_addr, ushort, 0);MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors");static u8 force_i2c = 0x1f;module_param(force_i2c, byte, 0);MODULE_PARM_DESC(force_i2c, "Initialize the i2c address of the sensors");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");/* modified from kernel/include/traps.c */static int REG; /* The register to read/write */#define DEV 0x07 /* Register: Logical device select */static int VAL; /* 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_EN 0x30 /* w83627thf only */#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */#define W83687THF_VID_EN 0x29 /* w83687thf only */#define W83687THF_VID_CFG 0xF0 /* w83687thf only */#define W83687THF_VID_DATA 0xF1 /* w83687thf 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 W687THF_DEVID 0x85#define WINB_ACT_REG 0x30#define WINB_BASE_REG 0x60/* Constants specified below *//* Alignment of the base address */#define WINB_ALIGNMENT ~7/* Offset & size of I/O region we are interested in */#define WINB_REGION_OFFSET 5#define WINB_REGION_SIZE 2/* Where are the sensors address/data registers relative to the region offset */#define W83781D_ADDR_REG_OFFSET 0#define W83781D_DATA_REG_OFFSET 1/* 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))/* nr:0-2 for fans:1-3 */#define W83627HF_REG_FAN_MIN(nr) (0x3b + (nr))#define W83627HF_REG_FAN(nr) (0x28 + (nr))#define W83627HF_REG_TEMP2_CONFIG 0x152#define W83627HF_REG_TEMP3_CONFIG 0x252/* these are zero-based, unlike config constants above */static const u16 w83627hf_reg_temp[] = { 0x27, 0x150, 0x250 };static const u16 w83627hf_reg_temp_hyst[] = { 0x3A, 0x153, 0x253 };static const u16 w83627hf_reg_temp_over[] = { 0x39, 0x155, 0x255 };#define W83781D_REG_BANK 0x4E#define W83781D_REG_CONFIG 0x40#define W83781D_REG_ALARM1 0x459#define W83781D_REG_ALARM2 0x45A#define W83781D_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#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 W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF/687THF 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] : regpwm[nr])#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */#define W83637HF_REG_PWM_FREQ1 0x00 /* 697HF/687THF too */#define W83637HF_REG_PWM_FREQ2 0x02 /* 697HF/687THF too */#define W83637HF_REG_PWM_FREQ3 0x10 /* 687THF too */static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1, W83637HF_REG_PWM_FREQ2, W83637HF_REG_PWM_FREQ3 };#define W83627HF_BASE_PWM_FREQ 46870#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(long 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))static inline unsigned long pwm_freq_from_reg_627hf(u8 reg){ unsigned long freq; freq = W83627HF_BASE_PWM_FREQ >> reg; return freq;}static inline u8 pwm_freq_to_reg_627hf(unsigned long val){ u8 i; /* Only 5 dividers (1 2 4 8 16) Search for the nearest available frequency */ for (i = 0; i < 4; i++) { if (val > (((W83627HF_BASE_PWM_FREQ >> i) + (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2)) break; } return i;}static inline unsigned long pwm_freq_from_reg(u8 reg){ /* Clock bit 8 -> 180 kHz or 24 MHz */ unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL; reg &= 0x7f; /* This should not happen but anyway... */ if (reg == 0) reg++; return (clock / (reg << 8));}static inline u8 pwm_freq_to_reg(unsigned long val){ /* Minimum divider value is 0x01 and maximum is 0x7F */ if (val >= 93750) /* The highest we can do */ return 0x01; if (val >= 720) /* Use 24 MHz clock */ return (24000000UL / (val << 8)); if (val < 6) /* The lowest we can do */ return 0xFF; else /* Use 180 kHz clock */ return (0x80 | (180000UL / (val << 8)));}#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 < 7; i++) { if (val == 0) break; val >>= 1; } return ((u8) i);}/* For each registered chip, we need to keep some data in memory. The structure is dynamically allocated. */struct w83627hf_data { unsigned short addr; const char *name; 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 */ 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 */ u16 temp[3]; /* Register value */ u16 temp_max[3]; /* Register value */ u16 temp_max_hyst[3]; /* 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 pwm_freq[3]; /* Register value */ u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode; 4 = thermistor */ u8 vrm; u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */};struct w83627hf_sio_data { enum chips type;};static int w83627hf_probe(struct platform_device *pdev);static int __devexit w83627hf_remove(struct platform_device *pdev);static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);static void w83627hf_update_fan_div(struct w83627hf_data *data);static struct w83627hf_data *w83627hf_update_device(struct device *dev);static void w83627hf_init_device(struct platform_device *pdev);static struct platform_driver w83627hf_driver = { .driver = { .owner = THIS_MODULE, .name = DRVNAME, }, .probe = w83627hf_probe, .remove = __devexit_p(w83627hf_remove),};static ssize_tshow_in_input(struct device *dev, struct device_attribute *devattr, char *buf){ int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr]));}static ssize_tshow_in_min(struct device *dev, struct device_attribute *devattr, char *buf){ int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr]));}static ssize_tshow_in_max(struct device *dev, struct device_attribute *devattr, char *buf){ int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr]));}static ssize_tstore_in_min(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count){ int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?