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