📄 lm87.c
字号:
lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]);}/* Note: we save and restore the fan minimum here, because its value is determined in part by the fan clock divider. This follows the principle of least suprise; the user doesn't expect the fan minimum to change just because the divider changed. */static ssize_t set_fan_div(struct device *dev, const char *buf, size_t count, int nr){ struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); unsigned long min = FAN_FROM_REG(data->fan_min[nr], FAN_DIV_FROM_REG(data->fan_div[nr])); u8 reg; switch (val) { case 1: data->fan_div[nr] = 0; break; case 2: data->fan_div[nr] = 1; break; case 4: data->fan_div[nr] = 2; break; case 8: data->fan_div[nr] = 3; break; default: return -EINVAL; } reg = lm87_read_value(client, LM87_REG_VID_FAN_DIV); switch (nr) { case 0: reg = (reg & 0xCF) | (data->fan_div[0] << 4); break; case 1: reg = (reg & 0x3F) | (data->fan_div[1] << 6); break; } lm87_write_value(client, LM87_REG_VID_FAN_DIV, reg); data->fan_min[nr] = FAN_TO_REG(min, val); lm87_write_value(client, LM87_REG_FAN_MIN(nr), data->fan_min[nr]); return count;}#define set_fan(offset) \static ssize_t set_fan##offset##_min(struct device *dev, const char *buf, \ size_t count) \{ \ set_fan_min(dev, buf, offset-1); \ return count; \} \static ssize_t set_fan##offset##_div(struct device *dev, const char *buf, \ size_t count) \{ \ return set_fan_div(dev, buf, count, offset-1); \} \static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ show_fan##offset##_min, set_fan##offset##_min); \static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ show_fan##offset##_div, set_fan##offset##_div);set_fan(1);set_fan(2);static ssize_t show_alarms(struct device *dev, char *buf){ struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", data->alarms);}static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);static ssize_t show_vid(struct device *dev, char *buf){ struct lm87_data *data = lm87_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, char *buf){ struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", data->vrm);}static ssize_t set_vrm(struct device *dev, const char *buf, size_t count){ struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); data->vrm = simple_strtoul(buf, NULL, 10); return count;}static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);static ssize_t show_aout(struct device *dev, char *buf){ struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout));}static ssize_t set_aout(struct device *dev, const char *buf, size_t count){ struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); data->aout = AOUT_TO_REG(val); lm87_write_value(client, LM87_REG_AOUT, data->aout); return count;}static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout);/* * Real code */static int lm87_attach_adapter(struct i2c_adapter *adapter){ if (!(adapter->class & I2C_CLASS_HWMON)) return 0; return i2c_detect(adapter, &addr_data, lm87_detect);}/* * The following function does more than just detection. If detection * succeeds, it also registers the new chip. */static int lm87_detect(struct i2c_adapter *adapter, int address, int kind){ struct i2c_client *new_client; struct lm87_data *data; int err = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; if (!(data = kmalloc(sizeof(struct lm87_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } memset(data, 0, sizeof(struct lm87_data)); /* The common I2C client data is placed right before the LM87-specific data. */ new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; new_client->driver = &lm87_driver; new_client->flags = 0; /* Default to an LM87 if forced */ if (kind == 0) kind = lm87; /* Now, we do the remaining detection. */ if (kind < 0) { u8 rev = lm87_read_value(new_client, LM87_REG_REVISION); if (rev < 0x01 || rev > 0x08 || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) || lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02) { dev_dbg(&adapter->dev, "LM87 detection failed at 0x%02x.\n", address); goto exit_free; } } /* We can fill in the remaining client fields */ strlcpy(new_client->name, "lm87", I2C_NAME_SIZE); new_client->id = lm87_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 exit_free; /* Initialize the LM87 chip */ lm87_init_client(new_client); data->in_scale[0] = 2500; data->in_scale[1] = 2700; data->in_scale[2] = (data->channel & CHAN_VCC_5V) ? 5000 : 3300; data->in_scale[3] = 5000; data->in_scale[4] = 12000; data->in_scale[5] = 2700; data->in_scale[6] = 1875; data->in_scale[7] = 1875; /* Register sysfs hooks */ device_create_file(&new_client->dev, &dev_attr_in1_input); device_create_file(&new_client->dev, &dev_attr_in1_min); device_create_file(&new_client->dev, &dev_attr_in1_max); device_create_file(&new_client->dev, &dev_attr_in2_input); device_create_file(&new_client->dev, &dev_attr_in2_min); device_create_file(&new_client->dev, &dev_attr_in2_max); device_create_file(&new_client->dev, &dev_attr_in3_input); device_create_file(&new_client->dev, &dev_attr_in3_min); device_create_file(&new_client->dev, &dev_attr_in3_max); device_create_file(&new_client->dev, &dev_attr_in4_input); device_create_file(&new_client->dev, &dev_attr_in4_min); device_create_file(&new_client->dev, &dev_attr_in4_max); if (data->channel & CHAN_NO_FAN(0)) { device_create_file(&new_client->dev, &dev_attr_in6_input); device_create_file(&new_client->dev, &dev_attr_in6_min); device_create_file(&new_client->dev, &dev_attr_in6_max); } else { device_create_file(&new_client->dev, &dev_attr_fan1_input); device_create_file(&new_client->dev, &dev_attr_fan1_min); device_create_file(&new_client->dev, &dev_attr_fan1_div); } if (data->channel & CHAN_NO_FAN(1)) { device_create_file(&new_client->dev, &dev_attr_in7_input); device_create_file(&new_client->dev, &dev_attr_in7_min); device_create_file(&new_client->dev, &dev_attr_in7_max); } else { device_create_file(&new_client->dev, &dev_attr_fan2_input); device_create_file(&new_client->dev, &dev_attr_fan2_min); 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_min); device_create_file(&new_client->dev, &dev_attr_temp1_crit); device_create_file(&new_client->dev, &dev_attr_temp2_input); device_create_file(&new_client->dev, &dev_attr_temp2_max); device_create_file(&new_client->dev, &dev_attr_temp2_min); device_create_file(&new_client->dev, &dev_attr_temp2_crit); if (data->channel & CHAN_TEMP3) { device_create_file(&new_client->dev, &dev_attr_temp3_input); device_create_file(&new_client->dev, &dev_attr_temp3_max); device_create_file(&new_client->dev, &dev_attr_temp3_min); device_create_file(&new_client->dev, &dev_attr_temp3_crit); } else { device_create_file(&new_client->dev, &dev_attr_in0_input); device_create_file(&new_client->dev, &dev_attr_in0_min); device_create_file(&new_client->dev, &dev_attr_in0_max); device_create_file(&new_client->dev, &dev_attr_in5_input); device_create_file(&new_client->dev, &dev_attr_in5_min); device_create_file(&new_client->dev, &dev_attr_in5_max); } if (!(data->channel & CHAN_NO_VID)) { device_create_file(&new_client->dev, &dev_attr_cpu0_vid); device_create_file(&new_client->dev, &dev_attr_vrm); } device_create_file(&new_client->dev, &dev_attr_alarms); device_create_file(&new_client->dev, &dev_attr_aout_output); return 0;exit_free: kfree(data);exit: return err;}static void lm87_init_client(struct i2c_client *client){ struct lm87_data *data = i2c_get_clientdata(client); u8 config; data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE); data->vrm = i2c_which_vrm(); config = lm87_read_value(client, LM87_REG_CONFIG); if (!(config & 0x01)) { int i; /* Limits are left uninitialized after power-up */ for (i = 1; i < 6; i++) { lm87_write_value(client, LM87_REG_IN_MIN(i), 0x00); lm87_write_value(client, LM87_REG_IN_MAX(i), 0xFF); } for (i = 0; i < 2; i++) { lm87_write_value(client, LM87_REG_TEMP_HIGH[i], 0x7F); lm87_write_value(client, LM87_REG_TEMP_LOW[i], 0x00); lm87_write_value(client, LM87_REG_AIN_MIN(i), 0x00); lm87_write_value(client, LM87_REG_AIN_MAX(i), 0xFF); } if (data->channel & CHAN_TEMP3) { lm87_write_value(client, LM87_REG_TEMP_HIGH[2], 0x7F); lm87_write_value(client, LM87_REG_TEMP_LOW[2], 0x00); } else { lm87_write_value(client, LM87_REG_IN_MIN(0), 0x00); lm87_write_value(client, LM87_REG_IN_MAX(0), 0xFF); } } if ((config & 0x81) != 0x01) { /* Start monitoring */ lm87_write_value(client, LM87_REG_CONFIG, (config & 0xF7) | 0x01); }}static int lm87_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 struct lm87_data *lm87_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct lm87_data *data = i2c_get_clientdata(client); down(&data->update_lock); if (jiffies - data->last_updated > HZ || jiffies < data->last_updated || !data->valid) { int i, j; dev_dbg(&client->dev, "Updating data.\n"); i = (data->channel & CHAN_TEMP3) ? 1 : 0; j = (data->channel & CHAN_TEMP3) ? 5 : 6; for (; i < j; i++) { data->in[i] = lm87_read_value(client, LM87_REG_IN(i)); data->in_min[i] = lm87_read_value(client, LM87_REG_IN_MIN(i)); data->in_max[i] = lm87_read_value(client, LM87_REG_IN_MAX(i)); } for (i = 0; i < 2; i++) { if (data->channel & CHAN_NO_FAN(i)) { data->in[6+i] = lm87_read_value(client, LM87_REG_AIN(i)); data->in_max[6+i] = lm87_read_value(client, LM87_REG_AIN_MAX(i)); data->in_min[6+i] = lm87_read_value(client, LM87_REG_AIN_MIN(i)); } else { data->fan[i] = lm87_read_value(client, LM87_REG_FAN(i)); data->fan_min[i] = lm87_read_value(client, LM87_REG_FAN_MIN(i)); } } j = (data->channel & CHAN_TEMP3) ? 3 : 2; for (i = 0 ; i < j; i++) { data->temp[i] = lm87_read_value(client, LM87_REG_TEMP[i]); data->temp_high[i] = lm87_read_value(client, LM87_REG_TEMP_HIGH[i]); data->temp_low[i] = lm87_read_value(client, LM87_REG_TEMP_LOW[i]); } i = lm87_read_value(client, LM87_REG_TEMP_HW_INT_LOCK); j = lm87_read_value(client, LM87_REG_TEMP_HW_INT); data->temp_crit_int = min(i, j); i = lm87_read_value(client, LM87_REG_TEMP_HW_EXT_LOCK); j = lm87_read_value(client, LM87_REG_TEMP_HW_EXT); data->temp_crit_ext = min(i, j); i = lm87_read_value(client, LM87_REG_VID_FAN_DIV); data->fan_div[0] = (i >> 4) & 0x03; data->fan_div[1] = (i >> 6) & 0x03; data->vid = (i & 0x0F) | (lm87_read_value(client, LM87_REG_VID4) & 0x01) << 4; data->alarms = lm87_read_value(client, LM87_REG_ALARMS1) | (lm87_read_value(client, LM87_REG_ALARMS2) << 8); data->aout = lm87_read_value(client, LM87_REG_AOUT); data->last_updated = jiffies; data->valid = 1; } up(&data->update_lock); return data;}static int __init sensors_lm87_init(void){ return i2c_add_driver(&lm87_driver);}static void __exit sensors_lm87_exit(void){ i2c_del_driver(&lm87_driver);}MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org> and others");MODULE_DESCRIPTION("LM87 driver");MODULE_LICENSE("GPL");module_init(sensors_lm87_init);module_exit(sensors_lm87_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -