smsc47m192.c

来自「linux 内核源代码」· C语言 代码 · 共 670 行 · 第 1/2 页

C
670
字号
/*    smsc47m192.c - Support for hardware monitoring block of                   SMSC LPC47M192 and compatible Super I/O chips    Copyright (C) 2006  Hartmut Rick <linux@rick.claranet.de>    Derived from lm78.c and other chip drivers.    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/i2c.h>#include <linux/hwmon.h>#include <linux/hwmon-sysfs.h>#include <linux/hwmon-vid.h>#include <linux/err.h>#include <linux/sysfs.h>#include <linux/mutex.h>/* Addresses to scan */static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };/* Insmod parameters */I2C_CLIENT_INSMOD_1(smsc47m192);/* SMSC47M192 registers */#define SMSC47M192_REG_IN(nr)		((nr)<6 ? (0x20 + (nr)) : \					(0x50 + (nr) - 6))#define SMSC47M192_REG_IN_MAX(nr)	((nr)<6 ? (0x2b + (nr) * 2) : \					(0x54 + (((nr) - 6) * 2)))#define SMSC47M192_REG_IN_MIN(nr)	((nr)<6 ? (0x2c + (nr) * 2) : \					(0x55 + (((nr) - 6) * 2)))static u8 SMSC47M192_REG_TEMP[3] =	{ 0x27, 0x26, 0x52 };static u8 SMSC47M192_REG_TEMP_MAX[3] =	{ 0x39, 0x37, 0x58 };static u8 SMSC47M192_REG_TEMP_MIN[3] =	{ 0x3A, 0x38, 0x59 };#define SMSC47M192_REG_TEMP_OFFSET(nr)	((nr)==2 ? 0x1e : 0x1f)#define SMSC47M192_REG_ALARM1		0x41#define SMSC47M192_REG_ALARM2		0x42#define SMSC47M192_REG_VID		0x47#define SMSC47M192_REG_VID4		0x49#define SMSC47M192_REG_CONFIG		0x40#define SMSC47M192_REG_SFR		0x4f#define SMSC47M192_REG_COMPANY_ID	0x3e#define SMSC47M192_REG_VERSION		0x3f/* generalised scaling with integer rounding */static inline int SCALE(long val, int mul, int div){	if (val < 0)		return (val * mul - div / 2) / div;	else		return (val * mul + div / 2) / div;}/* Conversions *//* smsc47m192 internally scales voltage measurements */static const u16 nom_mv[] = { 2500, 2250, 3300, 5000, 12000, 3300, 1500, 1800 };static inline unsigned int IN_FROM_REG(u8 reg, int n){	return SCALE(reg, nom_mv[n], 192);}static inline u8 IN_TO_REG(unsigned long val, int n){	return SENSORS_LIMIT(SCALE(val, 192, nom_mv[n]), 0, 255);}/* TEMP: 0.001 degC units (-128C to +127C)   REG: 1C/bit, two's complement */static inline s8 TEMP_TO_REG(int val){	return SENSORS_LIMIT(SCALE(val, 1, 1000), -128000, 127000);}static inline int TEMP_FROM_REG(s8 val){	return val * 1000;}struct smsc47m192_data {	struct i2c_client client;	struct device *hwmon_dev;	struct mutex update_lock;	char valid;		/* !=0 if following fields are valid */	unsigned long last_updated;	/* In jiffies */	u8 in[8];		/* Register value */	u8 in_max[8];		/* Register value */	u8 in_min[8];		/* Register value */	s8 temp[3];		/* Register value */	s8 temp_max[3];		/* Register value */	s8 temp_min[3];		/* Register value */	s8 temp_offset[3];	/* Register value */	u16 alarms;		/* Register encoding, combined */	u8 vid;			/* Register encoding, combined */	u8 vrm;};static int smsc47m192_attach_adapter(struct i2c_adapter *adapter);static int smsc47m192_detect(struct i2c_adapter *adapter, int address,		int kind);static int smsc47m192_detach_client(struct i2c_client *client);static struct smsc47m192_data *smsc47m192_update_device(struct device *dev);static struct i2c_driver smsc47m192_driver = {	.driver = {		.name	= "smsc47m192",	},	.attach_adapter	= smsc47m192_attach_adapter,	.detach_client	= smsc47m192_detach_client,};/* Voltages */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 smsc47m192_data *data = smsc47m192_update_device(dev);	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr], 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 smsc47m192_data *data = smsc47m192_update_device(dev);	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr], 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 smsc47m192_data *data = smsc47m192_update_device(dev);	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr], 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 i2c_client *client = to_i2c_client(dev);	struct smsc47m192_data *data = i2c_get_clientdata(client);	unsigned long val = simple_strtoul(buf, NULL, 10);	mutex_lock(&data->update_lock);	data->in_min[nr] = IN_TO_REG(val, nr);	i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_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 i2c_client *client = to_i2c_client(dev);	struct smsc47m192_data *data = i2c_get_clientdata(client);	unsigned long val = simple_strtoul(buf, NULL, 10);	mutex_lock(&data->update_lock);	data->in_max[nr] = IN_TO_REG(val, nr);	i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_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);				\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)show_in_offset(1)show_in_offset(2)show_in_offset(3)show_in_offset(4)show_in_offset(5)show_in_offset(6)show_in_offset(7)/* 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 smsc47m192_data *data = smsc47m192_update_device(dev);	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));}static ssize_t show_temp_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 smsc47m192_data *data = smsc47m192_update_device(dev);	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));}static ssize_t show_temp_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 smsc47m192_data *data = smsc47m192_update_device(dev);	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));}static ssize_t set_temp_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 i2c_client *client = to_i2c_client(dev);	struct smsc47m192_data *data = i2c_get_clientdata(client);	long val = simple_strtol(buf, NULL, 10);	mutex_lock(&data->update_lock);	data->temp_min[nr] = TEMP_TO_REG(val);	i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],						data->temp_min[nr]);	mutex_unlock(&data->update_lock);	return count;}static ssize_t set_temp_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 i2c_client *client = to_i2c_client(dev);	struct smsc47m192_data *data = i2c_get_clientdata(client);	long val = simple_strtol(buf, NULL, 10);	mutex_lock(&data->update_lock);	data->temp_max[nr] = TEMP_TO_REG(val);	i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],						data->temp_max[nr]);	mutex_unlock(&data->update_lock);	return count;}static ssize_t show_temp_offset(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 smsc47m192_data *data = smsc47m192_update_device(dev);	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_offset[nr]));}static ssize_t set_temp_offset(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 i2c_client *client = to_i2c_client(dev);	struct smsc47m192_data *data = i2c_get_clientdata(client);	u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);	long val = simple_strtol(buf, NULL, 10);	mutex_lock(&data->update_lock);	data->temp_offset[nr] = TEMP_TO_REG(val);	if (nr>1)		i2c_smbus_write_byte_data(client,			SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);	else if (data->temp_offset[nr] != 0) {		/* offset[0] and offset[1] share the same register,			SFR bit 4 activates offset[0] */		i2c_smbus_write_byte_data(client, SMSC47M192_REG_SFR,					(sfr & 0xef) | (nr==0 ? 0x10 : 0));		data->temp_offset[1-nr] = 0;		i2c_smbus_write_byte_data(client,			SMSC47M192_REG_TEMP_OFFSET(nr), data->temp_offset[nr]);	} else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0))		i2c_smbus_write_byte_data(client,					SMSC47M192_REG_TEMP_OFFSET(nr), 0);	mutex_unlock(&data->update_lock);	return count;}#define show_temp_index(index)						\static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO,			\		show_temp, NULL, index-1);				\static SENSOR_DEVICE_ATTR(temp##index##_min, S_IRUGO | S_IWUSR,		\		show_temp_min, set_temp_min, index-1);			\static SENSOR_DEVICE_ATTR(temp##index##_max, S_IRUGO | S_IWUSR,		\		show_temp_max, set_temp_max, index-1);			\static SENSOR_DEVICE_ATTR(temp##index##_offset, S_IRUGO | S_IWUSR,	\		show_temp_offset, set_temp_offset, index-1);show_temp_index(1)show_temp_index(2)show_temp_index(3)/* VID */static ssize_t show_vid(struct device *dev, struct device_attribute *attr,		char *buf){	struct smsc47m192_data *data = smsc47m192_update_device(dev);	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));}static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,		char *buf)

⌨️ 快捷键说明

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