2 fscpos.c - Kernel module for hardware monitoring with FSC Poseidon chips
3 Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 fujitsu siemens poseidon chip,
22 module based on the old fscpos module by Hermann Jung <hej@odn.de> and
23 the fscher module by Reinhard Nissl <rnissl@gmx.de>
25 original module based on lm80.c
26 Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
27 and Philip Edelbrock <phil@netroedge.com>
29 Thanks to Jean Delvare for reviewing my code and suggesting a lot of
33 #include <linux/module.h>
34 #include <linux/slab.h>
35 #include <linux/jiffies.h>
36 #include <linux/i2c.h>
37 #include <linux/init.h>
38 #include <linux/hwmon.h>
39 #include <linux/err.h>
40 #include <linux/mutex.h>
41 #include <linux/sysfs.h>
46 static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
51 I2C_CLIENT_INSMOD_1(fscpos);
54 * The FSCPOS registers
57 /* chip identification */
58 #define FSCPOS_REG_IDENT_0 0x00
59 #define FSCPOS_REG_IDENT_1 0x01
60 #define FSCPOS_REG_IDENT_2 0x02
61 #define FSCPOS_REG_REVISION 0x03
63 /* global control and status */
64 #define FSCPOS_REG_EVENT_STATE 0x04
65 #define FSCPOS_REG_CONTROL 0x05
68 #define FSCPOS_REG_WDOG_PRESET 0x28
69 #define FSCPOS_REG_WDOG_STATE 0x23
70 #define FSCPOS_REG_WDOG_CONTROL 0x21
73 #define FSCPOS_REG_VOLT_12 0x45
74 #define FSCPOS_REG_VOLT_5 0x42
75 #define FSCPOS_REG_VOLT_BATT 0x48
77 /* fans - the chip does not support minimum speed for fan2 */
78 static u8 FSCPOS_REG_PWM[] = { 0x55, 0x65 };
79 static u8 FSCPOS_REG_FAN_ACT[] = { 0x0e, 0x6b, 0xab };
80 static u8 FSCPOS_REG_FAN_STATE[] = { 0x0d, 0x62, 0xa2 };
81 static u8 FSCPOS_REG_FAN_RIPPLE[] = { 0x0f, 0x6f, 0xaf };
84 static u8 FSCPOS_REG_TEMP_ACT[] = { 0x64, 0x32, 0x35 };
85 static u8 FSCPOS_REG_TEMP_STATE[] = { 0x71, 0x81, 0x91 };
88 * Functions declaration
90 static int fscpos_probe(struct i2c_client *client,
91 const struct i2c_device_id *id);
92 static int fscpos_detect(struct i2c_client *client, int kind,
93 struct i2c_board_info *info);
94 static int fscpos_remove(struct i2c_client *client);
96 static int fscpos_read_value(struct i2c_client *client, u8 reg);
97 static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value);
98 static struct fscpos_data *fscpos_update_device(struct device *dev);
99 static void fscpos_init_client(struct i2c_client *client);
101 static void reset_fan_alarm(struct i2c_client *client, int nr);
104 * Driver data (common to all clients)
106 static const struct i2c_device_id fscpos_id[] = {
107 { "fscpos", fscpos },
111 static struct i2c_driver fscpos_driver = {
112 .class = I2C_CLASS_HWMON,
116 .probe = fscpos_probe,
117 .remove = fscpos_remove,
118 .id_table = fscpos_id,
119 .detect = fscpos_detect,
120 .address_data = &addr_data,
124 * Client data (each client gets its own)
127 struct device *hwmon_dev;
128 struct mutex update_lock;
129 char valid; /* 0 until following fields are valid */
130 unsigned long last_updated; /* In jiffies */
132 /* register values */
133 u8 revision; /* revision of chip */
134 u8 global_event; /* global event status */
135 u8 global_control; /* global control register */
136 u8 wdog_control; /* watchdog control */
137 u8 wdog_state; /* watchdog status */
138 u8 wdog_preset; /* watchdog preset */
139 u8 volt[3]; /* 12, 5, battery current */
140 u8 temp_act[3]; /* temperature */
141 u8 temp_status[3]; /* status of sensor */
142 u8 fan_act[3]; /* fans revolutions per second */
143 u8 fan_status[3]; /* fan status */
144 u8 pwm[2]; /* fan min value for rps */
145 u8 fan_ripple[3]; /* divider for rps */
149 #define TEMP_FROM_REG(val) (((val) - 128) * 1000)
151 static ssize_t show_temp_input(struct fscpos_data *data, char *buf, int nr)
153 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[nr - 1]));
156 static ssize_t show_temp_status(struct fscpos_data *data, char *buf, int nr)
158 /* bits 2..7 reserved => mask with 0x03 */
159 return sprintf(buf, "%u\n", data->temp_status[nr - 1] & 0x03);
162 static ssize_t show_temp_reset(struct fscpos_data *data, char *buf, int nr)
164 return sprintf(buf, "1\n");
167 static ssize_t set_temp_reset(struct i2c_client *client, struct fscpos_data
168 *data, const char *buf, size_t count, int nr, int reg)
170 unsigned long v = simple_strtoul(buf, NULL, 10);
172 dev_err(&client->dev, "temp_reset value %ld not supported. "
173 "Use 1 to reset the alarm!\n", v);
177 dev_info(&client->dev, "You used the temp_reset feature which has not "
178 "been proplerly tested. Please report your "
179 "experience to the module author.\n");
181 /* Supported value: 2 (clears the status) */
182 fscpos_write_value(client, FSCPOS_REG_TEMP_STATE[nr - 1], 2);
187 #define RPM_FROM_REG(val) ((val) * 60)
189 static ssize_t show_fan_status(struct fscpos_data *data, char *buf, int nr)
191 /* bits 0..1, 3..7 reserved => mask with 0x04 */
192 return sprintf(buf, "%u\n", data->fan_status[nr - 1] & 0x04);
195 static ssize_t show_fan_input(struct fscpos_data *data, char *buf, int nr)
197 return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[nr - 1]));
200 static ssize_t show_fan_ripple(struct fscpos_data *data, char *buf, int nr)
202 /* bits 2..7 reserved => mask with 0x03 */
203 return sprintf(buf, "%u\n", data->fan_ripple[nr - 1] & 0x03);
206 static ssize_t set_fan_ripple(struct i2c_client *client, struct fscpos_data
207 *data, const char *buf, size_t count, int nr, int reg)
209 /* supported values: 2, 4, 8 */
210 unsigned long v = simple_strtoul(buf, NULL, 10);
213 case 2: v = 1; break;
214 case 4: v = 2; break;
215 case 8: v = 3; break;
217 dev_err(&client->dev, "fan_ripple value %ld not supported. "
218 "Must be one of 2, 4 or 8!\n", v);
222 mutex_lock(&data->update_lock);
223 /* bits 2..7 reserved => mask with 0x03 */
224 data->fan_ripple[nr - 1] &= ~0x03;
225 data->fan_ripple[nr - 1] |= v;
227 fscpos_write_value(client, reg, data->fan_ripple[nr - 1]);
228 mutex_unlock(&data->update_lock);
232 static ssize_t show_pwm(struct fscpos_data *data, char *buf, int nr)
234 return sprintf(buf, "%u\n", data->pwm[nr - 1]);
237 static ssize_t set_pwm(struct i2c_client *client, struct fscpos_data *data,
238 const char *buf, size_t count, int nr, int reg)
240 unsigned long v = simple_strtoul(buf, NULL, 10);
244 if (v > 255) v = 255;
246 mutex_lock(&data->update_lock);
247 data->pwm[nr - 1] = v;
248 fscpos_write_value(client, reg, data->pwm[nr - 1]);
249 mutex_unlock(&data->update_lock);
253 static void reset_fan_alarm(struct i2c_client *client, int nr)
255 fscpos_write_value(client, FSCPOS_REG_FAN_STATE[nr], 4);
259 #define VOLT_FROM_REG(val, mult) ((val) * (mult) / 255)
261 static ssize_t show_volt_12(struct device *dev, struct device_attribute *attr, char *buf)
263 struct fscpos_data *data = fscpos_update_device(dev);
264 return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[0], 14200));
267 static ssize_t show_volt_5(struct device *dev, struct device_attribute *attr, char *buf)
269 struct fscpos_data *data = fscpos_update_device(dev);
270 return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[1], 6600));
273 static ssize_t show_volt_batt(struct device *dev, struct device_attribute *attr, char *buf)
275 struct fscpos_data *data = fscpos_update_device(dev);
276 return sprintf(buf, "%u\n", VOLT_FROM_REG(data->volt[2], 3300));
280 static ssize_t show_wdog_control(struct fscpos_data *data, char *buf)
282 /* bits 0..3 reserved, bit 6 write only => mask with 0xb0 */
283 return sprintf(buf, "%u\n", data->wdog_control & 0xb0);
286 static ssize_t set_wdog_control(struct i2c_client *client, struct fscpos_data
287 *data, const char *buf, size_t count, int reg)
289 /* bits 0..3 reserved => mask with 0xf0 */
290 unsigned long v = simple_strtoul(buf, NULL, 10) & 0xf0;
292 mutex_lock(&data->update_lock);
293 data->wdog_control &= ~0xf0;
294 data->wdog_control |= v;
295 fscpos_write_value(client, reg, data->wdog_control);
296 mutex_unlock(&data->update_lock);
300 static ssize_t show_wdog_state(struct fscpos_data *data, char *buf)
302 /* bits 0, 2..7 reserved => mask with 0x02 */
303 return sprintf(buf, "%u\n", data->wdog_state & 0x02);
306 static ssize_t set_wdog_state(struct i2c_client *client, struct fscpos_data
307 *data, const char *buf, size_t count, int reg)
309 unsigned long v = simple_strtoul(buf, NULL, 10) & 0x02;
311 /* Valid values: 2 (clear) */
313 dev_err(&client->dev, "wdog_state value %ld not supported. "
314 "Must be 2 to clear the state!\n", v);
318 mutex_lock(&data->update_lock);
319 data->wdog_state &= ~v;
320 fscpos_write_value(client, reg, v);
321 mutex_unlock(&data->update_lock);
325 static ssize_t show_wdog_preset(struct fscpos_data *data, char *buf)
327 return sprintf(buf, "%u\n", data->wdog_preset);
330 static ssize_t set_wdog_preset(struct i2c_client *client, struct fscpos_data
331 *data, const char *buf, size_t count, int reg)
333 unsigned long v = simple_strtoul(buf, NULL, 10) & 0xff;
335 mutex_lock(&data->update_lock);
336 data->wdog_preset = v;
337 fscpos_write_value(client, reg, data->wdog_preset);
338 mutex_unlock(&data->update_lock);
343 static ssize_t show_event(struct device *dev, struct device_attribute *attr, char *buf)
345 /* bits 5..7 reserved => mask with 0x1f */
346 struct fscpos_data *data = fscpos_update_device(dev);
347 return sprintf(buf, "%u\n", data->global_event & 0x9b);
353 #define create_getter(kind, sub) \
354 static ssize_t sysfs_show_##kind##sub(struct device *dev, struct device_attribute *attr, char *buf) \
356 struct fscpos_data *data = fscpos_update_device(dev); \
357 return show_##kind##sub(data, buf); \
360 #define create_getter_n(kind, offset, sub) \
361 static ssize_t sysfs_show_##kind##offset##sub(struct device *dev, struct device_attribute *attr, char\
364 struct fscpos_data *data = fscpos_update_device(dev); \
365 return show_##kind##sub(data, buf, offset); \
368 #define create_setter(kind, sub, reg) \
369 static ssize_t sysfs_set_##kind##sub (struct device *dev, struct device_attribute *attr, const char \
370 *buf, size_t count) \
372 struct i2c_client *client = to_i2c_client(dev); \
373 struct fscpos_data *data = i2c_get_clientdata(client); \
374 return set_##kind##sub(client, data, buf, count, reg); \
377 #define create_setter_n(kind, offset, sub, reg) \
378 static ssize_t sysfs_set_##kind##offset##sub (struct device *dev, struct device_attribute *attr, \
379 const char *buf, size_t count) \
381 struct i2c_client *client = to_i2c_client(dev); \
382 struct fscpos_data *data = i2c_get_clientdata(client); \
383 return set_##kind##sub(client, data, buf, count, offset, reg);\
386 #define create_sysfs_device_ro(kind, sub, offset) \
387 static DEVICE_ATTR(kind##offset##sub, S_IRUGO, \
388 sysfs_show_##kind##offset##sub, NULL);
390 #define create_sysfs_device_rw(kind, sub, offset) \
391 static DEVICE_ATTR(kind##offset##sub, S_IRUGO | S_IWUSR, \
392 sysfs_show_##kind##offset##sub, sysfs_set_##kind##offset##sub);
394 #define sysfs_ro_n(kind, sub, offset) \
395 create_getter_n(kind, offset, sub); \
396 create_sysfs_device_ro(kind, sub, offset);
398 #define sysfs_rw_n(kind, sub, offset, reg) \
399 create_getter_n(kind, offset, sub); \
400 create_setter_n(kind, offset, sub, reg); \
401 create_sysfs_device_rw(kind, sub, offset);
403 #define sysfs_rw(kind, sub, reg) \
404 create_getter(kind, sub); \
405 create_setter(kind, sub, reg); \
406 create_sysfs_device_rw(kind, sub,);
408 #define sysfs_fan_with_min(offset, reg_status, reg_ripple, reg_min) \
409 sysfs_fan(offset, reg_status, reg_ripple); \
410 sysfs_rw_n(pwm,, offset, reg_min);
412 #define sysfs_fan(offset, reg_status, reg_ripple) \
413 sysfs_ro_n(fan, _input, offset); \
414 sysfs_ro_n(fan, _status, offset); \
415 sysfs_rw_n(fan, _ripple, offset, reg_ripple);
417 #define sysfs_temp(offset, reg_status) \
418 sysfs_ro_n(temp, _input, offset); \
419 sysfs_ro_n(temp, _status, offset); \
420 sysfs_rw_n(temp, _reset, offset, reg_status);
422 #define sysfs_watchdog(reg_wdog_preset, reg_wdog_state, reg_wdog_control) \
423 sysfs_rw(wdog, _control, reg_wdog_control); \
424 sysfs_rw(wdog, _preset, reg_wdog_preset); \
425 sysfs_rw(wdog, _state, reg_wdog_state);
427 sysfs_fan_with_min(1, FSCPOS_REG_FAN_STATE[0], FSCPOS_REG_FAN_RIPPLE[0],
429 sysfs_fan_with_min(2, FSCPOS_REG_FAN_STATE[1], FSCPOS_REG_FAN_RIPPLE[1],
431 sysfs_fan(3, FSCPOS_REG_FAN_STATE[2], FSCPOS_REG_FAN_RIPPLE[2]);
433 sysfs_temp(1, FSCPOS_REG_TEMP_STATE[0]);
434 sysfs_temp(2, FSCPOS_REG_TEMP_STATE[1]);
435 sysfs_temp(3, FSCPOS_REG_TEMP_STATE[2]);
437 sysfs_watchdog(FSCPOS_REG_WDOG_PRESET, FSCPOS_REG_WDOG_STATE,
438 FSCPOS_REG_WDOG_CONTROL);
440 static DEVICE_ATTR(event, S_IRUGO, show_event, NULL);
441 static DEVICE_ATTR(in0_input, S_IRUGO, show_volt_12, NULL);
442 static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL);
443 static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL);
445 static struct attribute *fscpos_attributes[] = {
446 &dev_attr_event.attr,
447 &dev_attr_in0_input.attr,
448 &dev_attr_in1_input.attr,
449 &dev_attr_in2_input.attr,
451 &dev_attr_wdog_control.attr,
452 &dev_attr_wdog_preset.attr,
453 &dev_attr_wdog_state.attr,
455 &dev_attr_temp1_input.attr,
456 &dev_attr_temp1_status.attr,
457 &dev_attr_temp1_reset.attr,
458 &dev_attr_temp2_input.attr,
459 &dev_attr_temp2_status.attr,
460 &dev_attr_temp2_reset.attr,
461 &dev_attr_temp3_input.attr,
462 &dev_attr_temp3_status.attr,
463 &dev_attr_temp3_reset.attr,
465 &dev_attr_fan1_input.attr,
466 &dev_attr_fan1_status.attr,
467 &dev_attr_fan1_ripple.attr,
469 &dev_attr_fan2_input.attr,
470 &dev_attr_fan2_status.attr,
471 &dev_attr_fan2_ripple.attr,
473 &dev_attr_fan3_input.attr,
474 &dev_attr_fan3_status.attr,
475 &dev_attr_fan3_ripple.attr,
479 static const struct attribute_group fscpos_group = {
480 .attrs = fscpos_attributes,
483 /* Return 0 if detection is successful, -ENODEV otherwise */
484 static int fscpos_detect(struct i2c_client *new_client, int kind,
485 struct i2c_board_info *info)
487 struct i2c_adapter *adapter = new_client->adapter;
489 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
492 /* Do the remaining detection unless force or force_fscpos parameter */
494 if ((fscpos_read_value(new_client, FSCPOS_REG_IDENT_0)
496 || (fscpos_read_value(new_client, FSCPOS_REG_IDENT_1)
498 || (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2)
503 strlcpy(info->type, "fscpos", I2C_NAME_SIZE);
508 static int fscpos_probe(struct i2c_client *new_client,
509 const struct i2c_device_id *id)
511 struct fscpos_data *data;
514 data = kzalloc(sizeof(struct fscpos_data), GFP_KERNEL);
520 i2c_set_clientdata(new_client, data);
522 mutex_init(&data->update_lock);
524 /* Inizialize the fscpos chip */
525 fscpos_init_client(new_client);
527 /* Announce that the chip was found */
528 dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision);
530 /* Register sysfs hooks */
531 if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
534 data->hwmon_dev = hwmon_device_register(&new_client->dev);
535 if (IS_ERR(data->hwmon_dev)) {
536 err = PTR_ERR(data->hwmon_dev);
537 goto exit_remove_files;
543 sysfs_remove_group(&new_client->dev.kobj, &fscpos_group);
550 static int fscpos_remove(struct i2c_client *client)
552 struct fscpos_data *data = i2c_get_clientdata(client);
554 hwmon_device_unregister(data->hwmon_dev);
555 sysfs_remove_group(&client->dev.kobj, &fscpos_group);
561 static int fscpos_read_value(struct i2c_client *client, u8 reg)
563 dev_dbg(&client->dev, "Read reg 0x%02x\n", reg);
564 return i2c_smbus_read_byte_data(client, reg);
567 static int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value)
569 dev_dbg(&client->dev, "Write reg 0x%02x, val 0x%02x\n", reg, value);
570 return i2c_smbus_write_byte_data(client, reg, value);
573 /* Called when we have found a new FSCPOS chip */
574 static void fscpos_init_client(struct i2c_client *client)
576 struct fscpos_data *data = i2c_get_clientdata(client);
578 /* read revision from chip */
579 data->revision = fscpos_read_value(client, FSCPOS_REG_REVISION);
582 static struct fscpos_data *fscpos_update_device(struct device *dev)
584 struct i2c_client *client = to_i2c_client(dev);
585 struct fscpos_data *data = i2c_get_clientdata(client);
587 mutex_lock(&data->update_lock);
589 if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
592 dev_dbg(&client->dev, "Starting fscpos update\n");
594 for (i = 0; i < 3; i++) {
595 data->temp_act[i] = fscpos_read_value(client,
596 FSCPOS_REG_TEMP_ACT[i]);
597 data->temp_status[i] = fscpos_read_value(client,
598 FSCPOS_REG_TEMP_STATE[i]);
599 data->fan_act[i] = fscpos_read_value(client,
600 FSCPOS_REG_FAN_ACT[i]);
601 data->fan_status[i] = fscpos_read_value(client,
602 FSCPOS_REG_FAN_STATE[i]);
603 data->fan_ripple[i] = fscpos_read_value(client,
604 FSCPOS_REG_FAN_RIPPLE[i]);
606 /* fan2_min is not supported by the chip */
607 data->pwm[i] = fscpos_read_value(client,
610 /* reset fan status if speed is back to > 0 */
611 if (data->fan_status[i] != 0 && data->fan_act[i] > 0) {
612 reset_fan_alarm(client, i);
616 data->volt[0] = fscpos_read_value(client, FSCPOS_REG_VOLT_12);
617 data->volt[1] = fscpos_read_value(client, FSCPOS_REG_VOLT_5);
618 data->volt[2] = fscpos_read_value(client, FSCPOS_REG_VOLT_BATT);
620 data->wdog_preset = fscpos_read_value(client,
621 FSCPOS_REG_WDOG_PRESET);
622 data->wdog_state = fscpos_read_value(client,
623 FSCPOS_REG_WDOG_STATE);
624 data->wdog_control = fscpos_read_value(client,
625 FSCPOS_REG_WDOG_CONTROL);
627 data->global_event = fscpos_read_value(client,
628 FSCPOS_REG_EVENT_STATE);
630 data->last_updated = jiffies;
633 mutex_unlock(&data->update_lock);
637 static int __init sm_fscpos_init(void)
639 return i2c_add_driver(&fscpos_driver);
642 static void __exit sm_fscpos_exit(void)
644 i2c_del_driver(&fscpos_driver);
647 MODULE_AUTHOR("Stefan Ott <stefan@desire.ch> based on work from Hermann Jung "
648 "<hej@odn.de>, Frodo Looijaard <frodol@dds.nl>"
649 " and Philip Edelbrock <phil@netroedge.com>");
650 MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver");
651 MODULE_LICENSE("GPL");
653 module_init(sm_fscpos_init);
654 module_exit(sm_fscpos_exit);