📄 fscher.c
字号:
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; fscher_init_client(new_client); /* Register sysfs hooks */ device_create_file_revision(new_client); device_create_file_alarms(new_client); device_create_file_control(new_client); device_create_file_watchdog(new_client); device_create_file_in(new_client, 0); device_create_file_in(new_client, 1); device_create_file_in(new_client, 2); device_create_file_fan(new_client, 1); device_create_file_fan(new_client, 2); device_create_file_fan(new_client, 3); device_create_file_temp(new_client, 1); device_create_file_temp(new_client, 2); device_create_file_temp(new_client, 3); return 0;exit_free: kfree(data);exit: return err;}static int fscher_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 fscher_read_value(struct i2c_client *client, u8 reg){ dev_dbg(&client->dev, "read reg 0x%02x\n", reg); return i2c_smbus_read_byte_data(client, reg);}static int fscher_write_value(struct i2c_client *client, u8 reg, u8 value){ dev_dbg(&client->dev, "write reg 0x%02x, val 0x%02x\n", reg, value); return i2c_smbus_write_byte_data(client, reg, value);}/* Called when we have found a new FSC Hermes. */static void fscher_init_client(struct i2c_client *client){ struct fscher_data *data = i2c_get_clientdata(client); /* Read revision from chip */ data->revision = fscher_read_value(client, FSCHER_REG_REVISION);}static struct fscher_data *fscher_update_device(struct device *dev){ struct i2c_client *client = to_i2c_client(dev); struct fscher_data *data = i2c_get_clientdata(client); down(&data->update_lock); if ((jiffies - data->last_updated > 2 * HZ) || (jiffies < data->last_updated) || !data->valid) { dev_dbg(&client->dev, "Starting fscher update\n"); data->temp_act[0] = fscher_read_value(client, FSCHER_REG_TEMP0_ACT); data->temp_act[1] = fscher_read_value(client, FSCHER_REG_TEMP1_ACT); data->temp_act[2] = fscher_read_value(client, FSCHER_REG_TEMP2_ACT); data->temp_status[0] = fscher_read_value(client, FSCHER_REG_TEMP0_STATE); data->temp_status[1] = fscher_read_value(client, FSCHER_REG_TEMP1_STATE); data->temp_status[2] = fscher_read_value(client, FSCHER_REG_TEMP2_STATE); data->volt[0] = fscher_read_value(client, FSCHER_REG_VOLT_12); data->volt[1] = fscher_read_value(client, FSCHER_REG_VOLT_5); data->volt[2] = fscher_read_value(client, FSCHER_REG_VOLT_BATT); data->fan_act[0] = fscher_read_value(client, FSCHER_REG_FAN0_ACT); data->fan_act[1] = fscher_read_value(client, FSCHER_REG_FAN1_ACT); data->fan_act[2] = fscher_read_value(client, FSCHER_REG_FAN2_ACT); data->fan_status[0] = fscher_read_value(client, FSCHER_REG_FAN0_STATE); data->fan_status[1] = fscher_read_value(client, FSCHER_REG_FAN1_STATE); data->fan_status[2] = fscher_read_value(client, FSCHER_REG_FAN2_STATE); data->fan_min[0] = fscher_read_value(client, FSCHER_REG_FAN0_MIN); data->fan_min[1] = fscher_read_value(client, FSCHER_REG_FAN1_MIN); data->fan_min[2] = fscher_read_value(client, FSCHER_REG_FAN2_MIN); data->fan_ripple[0] = fscher_read_value(client, FSCHER_REG_FAN0_RIPPLE); data->fan_ripple[1] = fscher_read_value(client, FSCHER_REG_FAN1_RIPPLE); data->fan_ripple[2] = fscher_read_value(client, FSCHER_REG_FAN2_RIPPLE); data->watchdog[0] = fscher_read_value(client, FSCHER_REG_WDOG_PRESET); data->watchdog[1] = fscher_read_value(client, FSCHER_REG_WDOG_STATE); data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL); data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE); data->last_updated = jiffies; data->valid = 1; } up(&data->update_lock); return data;}#define FAN_INDEX_FROM_NUM(nr) ((nr) - 1)static ssize_t set_fan_status(struct i2c_client *client, struct fscher_data *data, const char *buf, size_t count, int nr, int reg){ /* bits 0..1, 3..7 reserved => mask with 0x04 */ unsigned long v = simple_strtoul(buf, NULL, 10) & 0x04; data->fan_status[FAN_INDEX_FROM_NUM(nr)] &= ~v; fscher_write_value(client, reg, v); return count;}static ssize_t show_fan_status(struct fscher_data *data, char *buf, int nr){ /* bits 0..1, 3..7 reserved => mask with 0x04 */ return sprintf(buf, "%u\n", data->fan_status[FAN_INDEX_FROM_NUM(nr)] & 0x04);}static ssize_t set_fan_pwm(struct i2c_client *client, struct fscher_data *data, const char *buf, size_t count, int nr, int reg){ data->fan_min[FAN_INDEX_FROM_NUM(nr)] = simple_strtoul(buf, NULL, 10) & 0xff; fscher_write_value(client, reg, data->fan_min[FAN_INDEX_FROM_NUM(nr)]); return count;}static ssize_t show_fan_pwm (struct fscher_data *data, char *buf, int nr){ return sprintf(buf, "%u\n", data->fan_min[FAN_INDEX_FROM_NUM(nr)]);}static ssize_t set_fan_div(struct i2c_client *client, struct fscher_data *data, const char *buf, size_t count, int nr, int reg){ /* supported values: 2, 4, 8 */ unsigned long v = simple_strtoul(buf, NULL, 10); switch (v) { case 2: v = 1; break; case 4: v = 2; break; case 8: v = 3; break; default: dev_err(&client->dev, "fan_div value %ld not " "supported. Choose one of 2, 4 or 8!\n", v); return -EINVAL; } /* bits 2..7 reserved => mask with 0x03 */ data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] &= ~0x03; data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] |= v; fscher_write_value(client, reg, data->fan_ripple[FAN_INDEX_FROM_NUM(nr)]); return count;}static ssize_t show_fan_div(struct fscher_data *data, char *buf, int nr){ /* bits 2..7 reserved => mask with 0x03 */ return sprintf(buf, "%u\n", 1 << (data->fan_ripple[FAN_INDEX_FROM_NUM(nr)] & 0x03));}#define RPM_FROM_REG(val) (val*60)static ssize_t show_fan_input (struct fscher_data *data, char *buf, int nr){ return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[FAN_INDEX_FROM_NUM(nr)]));}#define TEMP_INDEX_FROM_NUM(nr) ((nr) - 1)static ssize_t set_temp_status(struct i2c_client *client, struct fscher_data *data, const char *buf, size_t count, int nr, int reg){ /* bits 2..7 reserved, 0 read only => mask with 0x02 */ unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; data->temp_status[TEMP_INDEX_FROM_NUM(nr)] &= ~v; fscher_write_value(client, reg, v); return count;}static ssize_t show_temp_status(struct fscher_data *data, char *buf, int nr){ /* bits 2..7 reserved => mask with 0x03 */ return sprintf(buf, "%u\n", data->temp_status[TEMP_INDEX_FROM_NUM(nr)] & 0x03);}#define TEMP_FROM_REG(val) (((val) - 128) * 1000)static ssize_t show_temp_input(struct fscher_data *data, char *buf, int nr){ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[TEMP_INDEX_FROM_NUM(nr)]));}/* * The final conversion is specified in sensors.conf, as it depends on * mainboard specific values. We export the registers contents as * pseudo-hundredths-of-Volts (range 0V - 2.55V). Not that it makes much * sense per se, but it minimizes the conversions count and keeps the * values within a usual range. */#define VOLT_FROM_REG(val) ((val) * 10)static ssize_t show_in_input(struct fscher_data *data, char *buf, int nr){ return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[nr]));}static ssize_t show_revision(struct fscher_data *data, char *buf, int nr){ return sprintf(buf, "%u\n", data->revision);}static ssize_t show_alarms(struct fscher_data *data, char *buf, int nr){ /* bits 2, 5..6 reserved => mask with 0x9b */ return sprintf(buf, "%u\n", data->global_event & 0x9b);}static ssize_t set_control(struct i2c_client *client, struct fscher_data *data, const char *buf, size_t count, int nr, int reg){ /* bits 1..7 reserved => mask with 0x01 */ unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01; data->global_control &= ~v; fscher_write_value(client, reg, v); return count;}static ssize_t show_control(struct fscher_data *data, char *buf, int nr){ /* bits 1..7 reserved => mask with 0x01 */ return sprintf(buf, "%u\n", data->global_control & 0x01);}static ssize_t set_watchdog_control(struct i2c_client *client, struct fscher_data *data, const char *buf, size_t count, int nr, int reg){ /* bits 0..3 reserved => mask with 0xf0 */ unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0; data->watchdog[2] &= ~0xf0; data->watchdog[2] |= v; fscher_write_value(client, reg, data->watchdog[2]); return count;}static ssize_t show_watchdog_control(struct fscher_data *data, char *buf, int nr){ /* bits 0..3 reserved, bit 5 write only => mask with 0xd0 */ return sprintf(buf, "%u\n", data->watchdog[2] & 0xd0);}static ssize_t set_watchdog_status(struct i2c_client *client, struct fscher_data *data, const char *buf, size_t count, int nr, int reg){ /* bits 0, 2..7 reserved => mask with 0x02 */ unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02; data->watchdog[1] &= ~v; fscher_write_value(client, reg, v); return count;}static ssize_t show_watchdog_status(struct fscher_data *data, char *buf, int nr){ /* bits 0, 2..7 reserved => mask with 0x02 */ return sprintf(buf, "%u\n", data->watchdog[1] & 0x02);}static ssize_t set_watchdog_preset(struct i2c_client *client, struct fscher_data *data, const char *buf, size_t count, int nr, int reg){ data->watchdog[0] = simple_strtoul(buf, NULL, 10) & 0xff; fscher_write_value(client, reg, data->watchdog[0]); return count;}static ssize_t show_watchdog_preset(struct fscher_data *data, char *buf, int nr){ return sprintf(buf, "%u\n", data->watchdog[0]);}static int __init sensors_fscher_init(void){ return i2c_add_driver(&fscher_driver);}static void __exit sensors_fscher_exit(void){ i2c_del_driver(&fscher_driver);}MODULE_AUTHOR("Reinhard Nissl <rnissl@gmx.de>");MODULE_DESCRIPTION("FSC Hermes driver");MODULE_LICENSE("GPL");module_init(sensors_fscher_init);module_exit(sensors_fscher_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -