📄 lm80.c
字号:
#define show_temp(suffix, value) \static ssize_t show_temp_##suffix(struct device *dev, char *buf) \{ \ struct lm80_data *data = lm80_update_device(dev); \ return sprintf(buf, "%d\n", TEMP_LIMIT_FROM_REG(data->value)); \}show_temp(hot_max, temp_hot_max);show_temp(hot_hyst, temp_hot_hyst);show_temp(os_max, temp_os_max);show_temp(os_hyst, temp_os_hyst);#define set_temp(suffix, value, reg) \static ssize_t set_temp_##suffix(struct device *dev, const char *buf, \ size_t count) \{ \ struct i2c_client *client = to_i2c_client(dev); \ struct lm80_data *data = i2c_get_clientdata(client); \ long val = simple_strtoul(buf, NULL, 10); \ data->value = TEMP_LIMIT_TO_REG(val); \ lm80_write_value(client, reg, data->value); \ return count; \}set_temp(hot_max, temp_hot_max, LM80_REG_TEMP_HOT_MAX);set_temp(hot_hyst, temp_hot_hyst, LM80_REG_TEMP_HOT_HYST);set_temp(os_max, temp_os_max, LM80_REG_TEMP_OS_MAX);set_temp(os_hyst, temp_os_hyst, LM80_REG_TEMP_OS_HYST);static ssize_t show_alarms(struct device *dev, char *buf){ struct lm80_data *data = lm80_update_device(dev); return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->alarms));}static DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min0, set_in_min0);static DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min1, set_in_min1);static DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min2, set_in_min2);static DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min3, set_in_min3);static DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min4, set_in_min4);static DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min5, set_in_min5);static DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min6, set_in_min6);static DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max0, set_in_max0);static DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max1, set_in_max1);static DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max2, set_in_max2);static DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max3, set_in_max3);static DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max4, set_in_max4);static DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max5, set_in_max5);static DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max6, set_in_max6);static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL);static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL);static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL);static DEVICE_ATTR(in3_input, S_IRUGO, show_in_input3, NULL);static DEVICE_ATTR(in4_input, S_IRUGO, show_in_input4, NULL);static DEVICE_ATTR(in5_input, S_IRUGO, show_in_input5, NULL);static DEVICE_ATTR(in6_input, S_IRUGO, show_in_input6, NULL);static DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min1, set_fan_min1);static DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min2, set_fan_min2);static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL);static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL);static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div1, set_fan_div1);static DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div2, set_fan_div2);static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input1, NULL);static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_hot_max, set_temp_hot_max);static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hot_hyst, set_temp_hot_hyst);static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp_os_max, set_temp_os_max);static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_os_hyst, set_temp_os_hyst);static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);/* * Real code */static int lm80_attach_adapter(struct i2c_adapter *adapter){ if (!(adapter->class & I2C_CLASS_HWMON)) return 0; return i2c_detect(adapter, &addr_data, lm80_detect);}int lm80_detect(struct i2c_adapter *adapter, int address, int kind){ int i, cur; struct i2c_client *new_client; struct lm80_data *data; int err = 0; const char *name; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access lm80_{read,write}_value. */ if (!(data = kmalloc(sizeof(struct lm80_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } memset(data, 0, sizeof(struct lm80_data)); new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; new_client->driver = &lm80_driver; new_client->flags = 0; /* Now, we do the remaining detection. It is lousy. */ if (lm80_read_value(new_client, LM80_REG_ALARM2) & 0xc0) goto error_free; for (i = 0x2a; i <= 0x3d; i++) { cur = i2c_smbus_read_byte_data(new_client, i); if ((i2c_smbus_read_byte_data(new_client, i + 0x40) != cur) || (i2c_smbus_read_byte_data(new_client, i + 0x80) != cur) || (i2c_smbus_read_byte_data(new_client, i + 0xc0) != cur)) goto error_free; } /* Determine the chip type - only one kind supported! */ kind = lm80; name = "lm80"; /* Fill in the remaining client fields and put it into the global list */ strlcpy(new_client->name, name, I2C_NAME_SIZE); new_client->id = lm80_id++; data->valid = 0; init_MUTEX(&data->update_lock); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto error_free; /* Initialize the LM80 chip */ lm80_init_client(new_client); /* A few vars need to be filled upon startup */ data->fan_min[0] = lm80_read_value(new_client, LM80_REG_FAN_MIN(1)); data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2)); /* Register sysfs hooks */ device_create_file(&new_client->dev, &dev_attr_in0_min); device_create_file(&new_client->dev, &dev_attr_in1_min); device_create_file(&new_client->dev, &dev_attr_in2_min); device_create_file(&new_client->dev, &dev_attr_in3_min); device_create_file(&new_client->dev, &dev_attr_in4_min); device_create_file(&new_client->dev, &dev_attr_in5_min); device_create_file(&new_client->dev, &dev_attr_in6_min); device_create_file(&new_client->dev, &dev_attr_in0_max); device_create_file(&new_client->dev, &dev_attr_in1_max); device_create_file(&new_client->dev, &dev_attr_in2_max); device_create_file(&new_client->dev, &dev_attr_in3_max); device_create_file(&new_client->dev, &dev_attr_in4_max); device_create_file(&new_client->dev, &dev_attr_in5_max); device_create_file(&new_client->dev, &dev_attr_in6_max); device_create_file(&new_client->dev, &dev_attr_in0_input); device_create_file(&new_client->dev, &dev_attr_in1_input); device_create_file(&new_client->dev, &dev_attr_in2_input); device_create_file(&new_client->dev, &dev_attr_in3_input); device_create_file(&new_client->dev, &dev_attr_in4_input); device_create_file(&new_client->dev, &dev_attr_in5_input); device_create_file(&new_client->dev, &dev_attr_in6_input); device_create_file(&new_client->dev, &dev_attr_fan1_min); device_create_file(&new_client->dev, &dev_attr_fan2_min); device_create_file(&new_client->dev, &dev_attr_fan1_input); device_create_file(&new_client->dev, &dev_attr_fan2_input); device_create_file(&new_client->dev, &dev_attr_fan1_div); device_create_file(&new_client->dev, &dev_attr_fan2_div); device_create_file(&new_client->dev, &dev_attr_temp1_input); device_create_file(&new_client->dev, &dev_attr_temp1_max); device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst); device_create_file(&new_client->dev, &dev_attr_temp1_crit); device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst); device_create_file(&new_client->dev, &dev_attr_alarms); return 0;error_free: kfree(data);exit: return err;}static int lm80_detach_client(struct i2c_client *client){ int err; if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached.\n"); return err; } kfree(i2c_get_clientdata(client)); return 0;}static int lm80_read_value(struct i2c_client *client, u8 reg){ return i2c_smbus_read_byte_data(client, reg);}static int lm80_write_value(struct i2c_client *client, u8 reg, u8 value){ return i2c_smbus_write_byte_data(client, reg, value);}/* Called when we have found a new LM80. */static void lm80_init_client(struct i2c_client *client){ /* Reset all except Watchdog values and last conversion values This sets fan-divs to 2, among others. This makes most other initializations unnecessary */ lm80_write_value(client, LM80_REG_CONFIG, 0x80); /* Set 11-bit temperature resolution */ lm80_write_value(client, LM80_REG_RES, 0x08); /* Start monitoring */ lm80_write_value(client, LM80_REG_CONFIG, 0x01);}static struct lm80_data *lm80_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct lm80_data *data = i2c_get_clientdata(client); int i; down(&data->update_lock); if ((jiffies - data->last_updated > 2 * HZ) || (jiffies < data->last_updated) || !data->valid) { dev_dbg(&client->dev, "Starting lm80 update\n"); for (i = 0; i <= 6; i++) { data->in[i] = lm80_read_value(client, LM80_REG_IN(i)); data->in_min[i] = lm80_read_value(client, LM80_REG_IN_MIN(i)); data->in_max[i] = lm80_read_value(client, LM80_REG_IN_MAX(i)); } data->fan[0] = lm80_read_value(client, LM80_REG_FAN1); data->fan_min[0] = lm80_read_value(client, LM80_REG_FAN_MIN(1)); data->fan[1] = lm80_read_value(client, LM80_REG_FAN2); data->fan_min[1] = lm80_read_value(client, LM80_REG_FAN_MIN(2)); data->temp = (lm80_read_value(client, LM80_REG_TEMP) << 8) | (lm80_read_value(client, LM80_REG_RES) & 0xf0); data->temp_os_max = lm80_read_value(client, LM80_REG_TEMP_OS_MAX); data->temp_os_hyst = lm80_read_value(client, LM80_REG_TEMP_OS_HYST); data->temp_hot_max = lm80_read_value(client, LM80_REG_TEMP_HOT_MAX); data->temp_hot_hyst = lm80_read_value(client, LM80_REG_TEMP_HOT_HYST); i = lm80_read_value(client, LM80_REG_FANDIV); data->fan_div[0] = (i >> 2) & 0x03; data->fan_div[1] = (i >> 4) & 0x03; data->alarms = lm80_read_value(client, LM80_REG_ALARM1) + (lm80_read_value(client, LM80_REG_ALARM2) << 8); data->last_updated = jiffies; data->valid = 1; } up(&data->update_lock); return data;}static int __init sensors_lm80_init(void){ return i2c_add_driver(&lm80_driver);}static void __exit sensors_lm80_exit(void){ i2c_del_driver(&lm80_driver);}MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and " "Philip Edelbrock <phil@netroedge.com>");MODULE_DESCRIPTION("LM80 driver");MODULE_LICENSE("GPL");module_init(sensors_lm80_init);module_exit(sensors_lm80_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -