⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 it87.c

📁 ite_8075 io source code temperature and fan speed control for linux
💻 C
📖 第 1 页 / 共 4 页
字号:
/*    it87.c - Part of lm_sensors, Linux kernel modules for hardware             monitoring.    The IT8705F is an LPC-based Super I/O part that contains UARTs, a    parallel port, an IR port, a MIDI port, a floppy controller, etc., in    addition to an Environment Controller (Enhanced Hardware Monitor and    Fan Controller)    This driver supports only the Environment Controller in the IT8705F and    similar parts.  The other devices are supported by different drivers.    Supports: IT8705F  Super I/O chip w/LPC interface              IT8712F  Super I/O chip w/LPC interface              IT8716F  Super I/O chip w/LPC interface              IT8718F  Super I/O chip w/LPC interface              IT8720F  Super I/O chip w/LPC interface              IT8726F  Super I/O chip w/LPC interface              IT8781F  Super I/O chip w/LPC interface              IT8782F  Super I/O chip w/LPC interface              Sis950   A clone of the IT8705F    Copyright (C) 2001 Chris Gauthron    Copyright (C) 2005-2007 Jean Delvare <khali@linux-fr.org>    Copyright (C) 2008 Cark Li <cark.li@ite.com.tw>    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.*/#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/sysfs.h>#include <asm/io.h>#define DRVNAME "it87"enum chips { it87, it8712, it8716, it8718 };static unsigned short force_id;module_param(force_id, ushort, 0);MODULE_PARM_DESC(force_id, "Override the detected device ID");static struct platform_device *pdev;#define	REG	0x2e	/* The register to read/write */#define	DEV	0x07	/* Register: Logical device select */#define	VAL	0x2f	/* The value to read/write */#define PME	0x04	/* The device with the fan registers in it */#define GPIO	0x07	/* The device with the IT8718F VID value in it */#define	DEVID	0x20	/* Register: Device ID */#define	DEVREV	0x22	/* Register: Device Revision */static inline intsuperio_inb(int reg){	outb(reg, REG);	return inb(VAL);}static int superio_inw(int reg){	int val;	outb(reg++, REG);	val = inb(VAL) << 8;	outb(reg, REG);	val |= inb(VAL);	return val;}static inline voidsuperio_select(int ldn){	outb(DEV, REG);	outb(ldn, VAL);}static inline voidsuperio_enter(void){	outb(0x87, REG);	outb(0x01, REG);	outb(0x55, REG);	outb(0x55, REG);}static inline voidsuperio_exit(void){	outb(0x02, REG);	outb(0x02, VAL);}/* Logical device 4 registers */#define IT8712F_DEVID 0x8712#define IT8705F_DEVID 0x8705#define IT8716F_DEVID 0x8716#define IT8718F_DEVID 0x8718#define IT8720F_DEVID 0x8720#define IT8726F_DEVID 0x8726#define IT8781F_DEVID 0x8781#define IT8782F_DEVID 0x8782#define IT87_ACT_REG  0x30#define IT87_BASE_REG 0x60/* Logical device 7 registers (IT8712F and later) */#define IT87_SIO_PINX2_REG	0x2c	/* Pin selection */#define IT87_SIO_VID_REG	0xfc	/* VID value *//* Update battery voltage after every reading if true */static int update_vbat;/* Not all BIOSes properly configure the PWM registers */static int fix_pwm_polarity;/* Many IT87 constants specified below *//* Length of ISA address segment */#define IT87_EXTENT 8/* Length of ISA address segment for Environmental Controller */#define IT87_EC_EXTENT 2/* Offset of EC registers from ISA base address */#define IT87_EC_OFFSET 5/* Where are the ISA address/data registers relative to the EC base address */#define IT87_ADDR_REG_OFFSET 0#define IT87_DATA_REG_OFFSET 1/*----- The IT87 registers -----*/#define IT87_REG_CONFIG        0x00#define IT87_REG_ALARM1        0x01#define IT87_REG_ALARM2        0x02#define IT87_REG_ALARM3        0x03/* The IT8718F has the VID value in a different register, in Super-I/O   configuration space. */#define IT87_REG_VID           0x0a/* Warning: register 0x0b is used for something completely different in   new chips/revisions. I suspect only 16-bit tachometer mode will work   for these. */#define IT87_REG_FAN_DIV       0x0b#define IT87_REG_FAN_16BIT     0x0c/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */static const u8 IT87_REG_FAN[]		= { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };static const u8 IT87_REG_FAN_MIN[]	= { 0x10, 0x11, 0x12, 0x84, 0x86 };static const u8 IT87_REG_FANX[]		= { 0x18, 0x19, 0x1a, 0x81, 0x83 };static const u8 IT87_REG_FANX_MIN[]	= { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };#define IT87_REG_FAN_MAIN_CTRL 0x13#define IT87_REG_FAN_CTL       0x14#define IT87_REG_PWM(nr)       (0x15 + (nr))#define IT87_REG_VIN(nr)       (0x20 + (nr))#define IT87_REG_TEMP(nr)      (0x29 + (nr))#define IT87_REG_VIN_MAX(nr)   (0x30 + (nr) * 2)#define IT87_REG_VIN_MIN(nr)   (0x31 + (nr) * 2)#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2)#define IT87_REG_TEMP_LOW(nr)  (0x41 + (nr) * 2)#define IT87_REG_VIN_ENABLE    0x50#define IT87_REG_TEMP_ENABLE   0x51#define IT87_REG_CHIPID        0x58#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);}static inline u16 FAN16_TO_REG(long rpm){	if (rpm == 0)		return 0xffff;	return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe);}#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))/* The divider is fixed to 2 in 16-bit mode */#define FAN16_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:1350000/((val)*2))#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\					((val)+500)/1000),-128,127))#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*1000)#define PWM_TO_REG(val)   ((val) >> 1)#define PWM_FROM_REG(val) (((val)&0x7f) << 1)static int DIV_TO_REG(int val){	int answer = 0;	while (answer < 7 && (val >>= 1))		answer++;	return answer;}#define DIV_FROM_REG(val) (1 << (val))static const unsigned int pwm_freq[8] = {	48000000 / 128,	24000000 / 128,	12000000 / 128,	8000000 / 128,	6000000 / 128,	3000000 / 128,	1500000 / 128,	750000 / 128,};struct it87_sio_data {	enum chips type;	/* Values read from Super-I/O config space */	u8 vid_value;};/* For each registered chip, we need to keep some data in memory.   The structure is dynamically allocated. */struct it87_data {	struct device *hwmon_dev;	enum chips type;	unsigned short addr;	const char *name;	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[8];		/* Register value */	u8 in_min[8];		/* Register value */	u8 has_fan;		/* Bitfield, fans enabled */	u16 fan[5];		/* Register values, possibly combined */	u16 fan_min[5];		/* Register values, possibly combined */	u8 temp[3];		/* Register value */	u8 temp_high[3];	/* Register value */	u8 temp_low[3];		/* Register value */	u8 sensor;		/* Register value */	u8 fan_div[3];		/* Register encoding, shifted right */	u8 vid;			/* Register encoding, combined */	u8 vrm;	u32 alarms;		/* Register encoding, combined */	u8 fan_main_ctrl;	/* Register value */	u8 fan_ctl;		/* Register value */	u8 manual_pwm_ctl[3];   /* manual PWM value set by user */};static int it87_probe(struct platform_device *pdev);static int __devexit it87_remove(struct platform_device *pdev);static int it87_read_value(struct it87_data *data, u8 reg);static void it87_write_value(struct it87_data *data, u8 reg, u8 value);static struct it87_data *it87_update_device(struct device *dev);static int it87_check_pwm(struct device *dev);static void it87_init_device(struct platform_device *pdev);static struct platform_driver it87_driver = {	.driver = {		.owner	= THIS_MODULE,		.name	= DRVNAME,	},	.probe	= it87_probe,	.remove	= __devexit_p(it87_remove),};static ssize_t show_in(struct device *dev, struct device_attribute *attr,		char *buf){	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);	int nr = sensor_attr->index;	struct it87_data *data = it87_update_device(dev);	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));}static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,		char *buf){	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);	int nr = sensor_attr->index;	struct it87_data *data = it87_update_device(dev);	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));}static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,		char *buf){	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);	int nr = sensor_attr->index;	struct it87_data *data = it87_update_device(dev);	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));}static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,		const char *buf, size_t count){	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);	int nr = sensor_attr->index;	struct it87_data *data = dev_get_drvdata(dev);	unsigned long val = simple_strtoul(buf, NULL, 10);	mutex_lock(&data->update_lock);	data->in_min[nr] = IN_TO_REG(val);	it87_write_value(data, IT87_REG_VIN_MIN(nr),			data->in_min[nr]);	mutex_unlock(&data->update_lock);	return count;}static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,		const char *buf, size_t count){	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);	int nr = sensor_attr->index;	struct it87_data *data = dev_get_drvdata(dev);	unsigned long val = simple_strtoul(buf, NULL, 10);	mutex_lock(&data->update_lock);	data->in_max[nr] = IN_TO_REG(val);	it87_write_value(data, IT87_REG_VIN_MAX(nr),			data->in_max[nr]);	mutex_unlock(&data->update_lock);	return count;}#define show_in_offset(offset)					\static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\		show_in, NULL, offset);#define limit_in_offset(offset)					\static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\		show_in_min, set_in_min, offset);		\static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\		show_in_max, set_in_max, offset);show_in_offset(0);limit_in_offset(0);show_in_offset(1);limit_in_offset(1);show_in_offset(2);limit_in_offset(2);show_in_offset(3);limit_in_offset(3);show_in_offset(4);limit_in_offset(4);show_in_offset(5);limit_in_offset(5);show_in_offset(6);limit_in_offset(6);show_in_offset(7);limit_in_offset(7);show_in_offset(8);/* 3 temperatures */static ssize_t show_temp(struct device *dev, struct device_attribute *attr,		char *buf){	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);	int nr = sensor_attr->index;	struct it87_data *data = it87_update_device(dev);	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -