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