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 + -
显示快捷键?