📄 pc87360.c
字号:
} if (data->innr == 14) { device_create_file(&new_client->dev, &dev_attr_temp4_input); device_create_file(&new_client->dev, &dev_attr_temp5_input); device_create_file(&new_client->dev, &dev_attr_temp6_input); device_create_file(&new_client->dev, &dev_attr_temp4_min); device_create_file(&new_client->dev, &dev_attr_temp5_min); device_create_file(&new_client->dev, &dev_attr_temp6_min); device_create_file(&new_client->dev, &dev_attr_temp4_max); device_create_file(&new_client->dev, &dev_attr_temp5_max); device_create_file(&new_client->dev, &dev_attr_temp6_max); device_create_file(&new_client->dev, &dev_attr_temp4_crit); device_create_file(&new_client->dev, &dev_attr_temp5_crit); device_create_file(&new_client->dev, &dev_attr_temp6_crit); device_create_file(&new_client->dev, &dev_attr_temp4_status); device_create_file(&new_client->dev, &dev_attr_temp5_status); device_create_file(&new_client->dev, &dev_attr_temp6_status); } if (data->fannr) { if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) { 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); device_create_file(&new_client->dev, &dev_attr_fan1_status); } if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) { 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_fan2_status); } if (FAN_CONFIG_CONTROL(data->fan_conf, 0)) device_create_file(&new_client->dev, &dev_attr_pwm1); if (FAN_CONFIG_CONTROL(data->fan_conf, 1)) device_create_file(&new_client->dev, &dev_attr_pwm2); } if (data->fannr == 3) { if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) { device_create_file(&new_client->dev, &dev_attr_fan3_input); device_create_file(&new_client->dev, &dev_attr_fan3_min); device_create_file(&new_client->dev, &dev_attr_fan3_div); device_create_file(&new_client->dev, &dev_attr_fan3_status); } if (FAN_CONFIG_CONTROL(data->fan_conf, 2)) device_create_file(&new_client->dev, &dev_attr_pwm3); } return 0;ERROR2: for (i = 0; i < 3; i++) { if (data->address[i]) { release_region(data->address[i], PC87360_EXTENT); } }ERROR1: kfree(data); return err;}static int pc87360_detach_client(struct i2c_client *client){ struct pc87360_data *data = i2c_get_clientdata(client); int i; if ((i = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached.\n"); return i; } for (i = 0; i < 3; i++) { if (data->address[i]) { release_region(data->address[i], PC87360_EXTENT); } } kfree(data); return 0;}/* ldi is the logical device index bank is for voltages and temperatures only */static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, u8 reg){ int res; down(&(data->lock)); if (bank != NO_BANK) outb_p(bank, data->address[ldi] + PC87365_REG_BANK); res = inb_p(data->address[ldi] + reg); up(&(data->lock)); return res;}static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, u8 reg, u8 value){ down(&(data->lock)); if (bank != NO_BANK) outb_p(bank, data->address[ldi] + PC87365_REG_BANK); outb_p(value, data->address[ldi] + reg); up(&(data->lock));}static void pc87360_init_client(struct i2c_client *client, int use_thermistors){ struct pc87360_data *data = i2c_get_clientdata(client); int i, nr; const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; const u8 init_temp[3] = { 2, 2, 1 }; u8 reg; if (init >= 2 && data->innr) { reg = pc87360_read_value(data, LD_IN, NO_BANK, PC87365_REG_IN_CONVRATE); dev_info(&client->dev, "VLM conversion set to" "1s period, 160us delay\n"); pc87360_write_value(data, LD_IN, NO_BANK, PC87365_REG_IN_CONVRATE, (reg & 0xC0) | 0x11); } nr = data->innr < 11 ? data->innr : 11; for (i=0; i<nr; i++) { if (init >= init_in[i]) { /* Forcibly enable voltage channel */ reg = pc87360_read_value(data, LD_IN, i, PC87365_REG_IN_STATUS); if (!(reg & 0x01)) { dev_dbg(&client->dev, "Forcibly " "enabling in%d\n", i); pc87360_write_value(data, LD_IN, i, PC87365_REG_IN_STATUS, (reg & 0x68) | 0x87); } } } /* We can't blindly trust the Super-I/O space configuration bit, most BIOS won't set it properly */ for (i=11; i<data->innr; i++) { reg = pc87360_read_value(data, LD_IN, i, PC87365_REG_TEMP_STATUS); use_thermistors = use_thermistors || (reg & 0x01); } i = use_thermistors ? 2 : 0; for (; i<data->tempnr; i++) { if (init >= init_temp[i]) { /* Forcibly enable temperature channel */ reg = pc87360_read_value(data, LD_TEMP, i, PC87365_REG_TEMP_STATUS); if (!(reg & 0x01)) { dev_dbg(&client->dev, "Forcibly " "enabling temp%d\n", i+1); pc87360_write_value(data, LD_TEMP, i, PC87365_REG_TEMP_STATUS, 0xCF); } } } if (use_thermistors) { for (i=11; i<data->innr; i++) { if (init >= init_in[i]) { /* The pin may already be used by thermal diodes */ reg = pc87360_read_value(data, LD_TEMP, (i-11)/2, PC87365_REG_TEMP_STATUS); if (reg & 0x01) { dev_dbg(&client->dev, "Skipping " "temp%d, pin already in use " "by temp%d\n", i-7, (i-11)/2); continue; } /* Forcibly enable thermistor channel */ reg = pc87360_read_value(data, LD_IN, i, PC87365_REG_IN_STATUS); if (!(reg & 0x01)) { dev_dbg(&client->dev, "Forcibly " "enabling temp%d\n", i-7); pc87360_write_value(data, LD_IN, i, PC87365_REG_TEMP_STATUS, (reg & 0x60) | 0x8F); } } } } if (data->innr) { reg = pc87360_read_value(data, LD_IN, NO_BANK, PC87365_REG_IN_CONFIG); if (reg & 0x01) { dev_dbg(&client->dev, "Forcibly " "enabling monitoring (VLM)\n"); pc87360_write_value(data, LD_IN, NO_BANK, PC87365_REG_IN_CONFIG, reg & 0xFE); } } if (data->tempnr) { reg = pc87360_read_value(data, LD_TEMP, NO_BANK, PC87365_REG_TEMP_CONFIG); if (reg & 0x01) { dev_dbg(&client->dev, "Forcibly enabling " "monitoring (TMS)\n"); pc87360_write_value(data, LD_TEMP, NO_BANK, PC87365_REG_TEMP_CONFIG, reg & 0xFE); } if (init >= 2) { /* Chip config as documented by National Semi. */ pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); /* We voluntarily omit the bank here, in case the sequence itself matters. It shouldn't be a problem, since nobody else is supposed to access the device at that point. */ pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05); } }}static void pc87360_autodiv(struct i2c_client *client, int nr){ struct pc87360_data *data = i2c_get_clientdata(client); u8 old_min = data->fan_min[nr]; /* Increase clock divider if needed and possible */ if ((data->fan_status[nr] & 0x04) /* overflow flag */ || (data->fan[nr] >= 224)) { /* next to overflow */ if ((data->fan_status[nr] & 0x60) != 0x60) { data->fan_status[nr] += 0x20; data->fan_min[nr] >>= 1; data->fan[nr] >>= 1; dev_dbg(&client->dev, "Increasing " "clock divider to %d for fan %d\n", FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1); } } else { /* Decrease clock divider if possible */ while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */ && data->fan[nr] < 85 /* bad accuracy */ && (data->fan_status[nr] & 0x60) != 0x00) { data->fan_status[nr] -= 0x20; data->fan_min[nr] <<= 1; data->fan[nr] <<= 1; dev_dbg(&client->dev, "Decreasing " "clock divider to %d for fan %d\n", FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1); } } /* Write new fan min if it changed */ if (old_min != data->fan_min[nr]) { pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(nr), data->fan_min[nr]); }}static struct pc87360_data *pc87360_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct pc87360_data *data = i2c_get_clientdata(client); u8 i; down(&data->update_lock); if ((jiffies - data->last_updated > HZ * 2) || (jiffies < data->last_updated) || !data->valid) { dev_dbg(&client->dev, "Data update\n"); /* Fans */ for (i = 0; i < data->fannr; i++) { if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { data->fan_status[i] = pc87360_read_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(i)); data->fan[i] = pc87360_read_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN(i)); data->fan_min[i] = pc87360_read_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_MIN(i)); /* Change clock divider if needed */ pc87360_autodiv(client, i); /* Clear bits and write new divider */ pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(i), data->fan_status[i]); } if (FAN_CONFIG_CONTROL(data->fan_conf, i)) data->pwm[i] = pc87360_read_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(i)); } /* Voltages */ for (i = 0; i < data->innr; i++) { data->in_status[i] = pc87360_read_value(data, LD_IN, i, PC87365_REG_IN_STATUS); /* Clear bits */ pc87360_write_value(data, LD_IN, i, PC87365_REG_IN_STATUS, data->in_status[i]); if ((data->in_status[i] & 0x81) == 0x81) { data->in[i] = pc87360_read_value(data, LD_IN, i, PC87365_REG_IN); } if (data->in_status[i] & 0x01) { data->in_min[i] = pc87360_read_value(data, LD_IN, i, PC87365_REG_IN_MIN); data->in_max[i] = pc87360_read_value(data, LD_IN, i, PC87365_REG_IN_MAX); if (i >= 11) data->in_crit[i-11] = pc87360_read_value(data, LD_IN, i, PC87365_REG_TEMP_CRIT); } } if (data->innr) { data->in_alarms = pc87360_read_value(data, LD_IN, NO_BANK, PC87365_REG_IN_ALARMS1) | ((pc87360_read_value(data, LD_IN, NO_BANK, PC87365_REG_IN_ALARMS2) & 0x07) << 8); data->vid = (data->vid_conf & 0xE0) ? pc87360_read_value(data, LD_IN, NO_BANK, PC87365_REG_VID) : 0x1F; } /* Temperatures */ for (i = 0; i < data->tempnr; i++) { data->temp_status[i] = pc87360_read_value(data, LD_TEMP, i, PC87365_REG_TEMP_STATUS); /* Clear bits */ pc87360_write_value(data, LD_TEMP, i, PC87365_REG_TEMP_STATUS, data->temp_status[i]); if ((data->temp_status[i] & 0x81) == 0x81) { data->temp[i] = pc87360_read_value(data, LD_TEMP, i, PC87365_REG_TEMP); } if (data->temp_status[i] & 0x01) { data->temp_min[i] = pc87360_read_value(data, LD_TEMP, i, PC87365_REG_TEMP_MIN); data->temp_max[i] = pc87360_read_value(data, LD_TEMP, i, PC87365_REG_TEMP_MAX); data->temp_crit[i] = pc87360_read_value(data, LD_TEMP, i, PC87365_REG_TEMP_CRIT); } } if (data->tempnr) { data->temp_alarms = pc87360_read_value(data, LD_TEMP, NO_BANK, PC87365_REG_TEMP_ALARMS) & 0x3F; } data->last_updated = jiffies; data->valid = 1; } up(&data->update_lock); return data;}static int __init pc87360_init(void){ int i; if (pc87360_find(0x2e, &devid, extra_isa) && pc87360_find(0x4e, &devid, extra_isa)) { printk(KERN_WARNING "pc87360: PC8736x not detected, " "module not inserted.\n"); return -ENODEV; } /* Arbitrarily pick one of the addresses */ for (i = 0; i < 3; i++) { if (extra_isa[i] != 0x0000) { normal_isa[0] = extra_isa[i]; break; } } if (normal_isa[0] == 0x0000) { printk(KERN_WARNING "pc87360: No active logical device, " "module not inserted.\n"); return -ENODEV; } return i2c_add_driver(&pc87360_driver);}static void __exit pc87360_exit(void){ i2c_del_driver(&pc87360_driver);}MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");MODULE_DESCRIPTION("PC8736x hardware monitor");MODULE_LICENSE("GPL");module_init(pc87360_init);module_exit(pc87360_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -