aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/fschmd.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-01-07 14:59:51 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-07 14:59:51 -0500
commit2f2408a88cf8fa43febfd7fb5783e61b2937b0f9 (patch)
tree4f49e5113ec8fe0554e1a8766b25d21f6fbc5a69 /drivers/hwmon/fschmd.c
parentfa7b906e7fef53b6c9eb3ecb8164b0a69e9e1a68 (diff)
parent77fa49d94a75b5f9702c70b4fbe27b08b21317b9 (diff)
Merge branch 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
* 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6: (29 commits) hwmon: Fix various typos hwmon: Check for ACPI resource conflicts hwmon: (lm70) Add TI TMP121 support hwmon: (lm70) Code streamlining and cleanup hwmon: Deprecate the fscher and fscpos drivers hwmon: (fschmd) Add watchdog support hwmon: (fschmd) Cleanups for watchdog support hwmon: (i5k_amb) Load automatically on all 5000/5400 chipsets hwmon: (it87) Add support for the ITE IT8720F hwmon: Don't overuse I2C_CLIENT_MODULE_PARM hwmon: Add LTC4245 driver hwmon: (f71882fg) Fix fan_to/from_reg prototypes hwmon: (f71882fg) Printout fan modes hwmon: (f71882fg) Add documentation hwmon: (f71882fg) Fix auto_channels_temp temp numbering with f8000 hwmon: (f71882fg) Add missing pwm3 attr for f71862fg hwmon: (f71882fg) Add F8000 support hwmon: (f71882fg) Remove the fan_mode module option hwmon: (f71882fg) Separate max and crit alarm and beep hwmon: (f71882fg) Check for hwmon powerdown state ...
Diffstat (limited to 'drivers/hwmon/fschmd.c')
-rw-r--r--drivers/hwmon/fschmd.c448
1 files changed, 405 insertions, 43 deletions
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c
index 8b2d756595d9..d07f4ef75092 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -1,6 +1,6 @@
1/* fschmd.c 1/* fschmd.c
2 * 2 *
3 * Copyright (C) 2007 Hans de Goede <j.w.r.degoede@hhs.nl> 3 * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com>
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License as published by
@@ -42,11 +42,20 @@
42#include <linux/mutex.h> 42#include <linux/mutex.h>
43#include <linux/sysfs.h> 43#include <linux/sysfs.h>
44#include <linux/dmi.h> 44#include <linux/dmi.h>
45#include <linux/fs.h>
46#include <linux/watchdog.h>
47#include <linux/miscdevice.h>
48#include <linux/uaccess.h>
49#include <linux/kref.h>
45 50
46/* Addresses to scan */ 51/* Addresses to scan */
47static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; 52static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
48 53
49/* Insmod parameters */ 54/* Insmod parameters */
55static int nowayout = WATCHDOG_NOWAYOUT;
56module_param(nowayout, int, 0);
57MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
58 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
50I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); 59I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
51 60
52/* 61/*
@@ -63,13 +72,20 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd);
63#define FSCHMD_REG_EVENT_STATE 0x04 72#define FSCHMD_REG_EVENT_STATE 0x04
64#define FSCHMD_REG_CONTROL 0x05 73#define FSCHMD_REG_CONTROL 0x05
65 74
66#define FSCHMD_CONTROL_ALERT_LED_MASK 0x01 75#define FSCHMD_CONTROL_ALERT_LED 0x01
67 76
68/* watchdog (support to be implemented) */ 77/* watchdog */
69#define FSCHMD_REG_WDOG_PRESET 0x28 78#define FSCHMD_REG_WDOG_PRESET 0x28
70#define FSCHMD_REG_WDOG_STATE 0x23 79#define FSCHMD_REG_WDOG_STATE 0x23
71#define FSCHMD_REG_WDOG_CONTROL 0x21 80#define FSCHMD_REG_WDOG_CONTROL 0x21
72 81
82#define FSCHMD_WDOG_CONTROL_TRIGGER 0x10
83#define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */
84#define FSCHMD_WDOG_CONTROL_STOP 0x20
85#define FSCHMD_WDOG_CONTROL_RESOLUTION 0x40
86
87#define FSCHMD_WDOG_STATE_CARDRESET 0x02
88
73/* voltages, weird order is to keep the same order as the old drivers */ 89/* voltages, weird order is to keep the same order as the old drivers */
74static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 }; 90static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 };
75 91
@@ -115,8 +131,8 @@ static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = {
115static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 }; 131static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 };
116 132
117/* Fan status register bitmasks */ 133/* Fan status register bitmasks */
118#define FSCHMD_FAN_ALARM_MASK 0x04 /* called fault by FSC! */ 134#define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */
119#define FSCHMD_FAN_NOT_PRESENT_MASK 0x08 /* not documented */ 135#define FSCHMD_FAN_NOT_PRESENT 0x08 /* not documented */
120 136
121 137
122/* actual temperature registers */ 138/* actual temperature registers */
@@ -158,14 +174,11 @@ static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
158static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 }; 174static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 };
159 175
160/* temp status register bitmasks */ 176/* temp status register bitmasks */
161#define FSCHMD_TEMP_WORKING_MASK 0x01 177#define FSCHMD_TEMP_WORKING 0x01
162#define FSCHMD_TEMP_ALERT_MASK 0x02 178#define FSCHMD_TEMP_ALERT 0x02
163/* there only really is an alarm if the sensor is working and alert == 1 */ 179/* there only really is an alarm if the sensor is working and alert == 1 */
164#define FSCHMD_TEMP_ALARM_MASK \ 180#define FSCHMD_TEMP_ALARM_MASK \
165 (FSCHMD_TEMP_WORKING_MASK | FSCHMD_TEMP_ALERT_MASK) 181 (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
166
167/* our driver name */
168#define FSCHMD_NAME "fschmd"
169 182
170/* 183/*
171 * Functions declarations 184 * Functions declarations
@@ -195,7 +208,7 @@ MODULE_DEVICE_TABLE(i2c, fschmd_id);
195static struct i2c_driver fschmd_driver = { 208static struct i2c_driver fschmd_driver = {
196 .class = I2C_CLASS_HWMON, 209 .class = I2C_CLASS_HWMON,
197 .driver = { 210 .driver = {
198 .name = FSCHMD_NAME, 211 .name = "fschmd",
199 }, 212 },
200 .probe = fschmd_probe, 213 .probe = fschmd_probe,
201 .remove = fschmd_remove, 214 .remove = fschmd_remove,
@@ -209,14 +222,26 @@ static struct i2c_driver fschmd_driver = {
209 */ 222 */
210 223
211struct fschmd_data { 224struct fschmd_data {
225 struct i2c_client *client;
212 struct device *hwmon_dev; 226 struct device *hwmon_dev;
213 struct mutex update_lock; 227 struct mutex update_lock;
228 struct mutex watchdog_lock;
229 struct list_head list; /* member of the watchdog_data_list */
230 struct kref kref;
231 struct miscdevice watchdog_miscdev;
214 int kind; 232 int kind;
233 unsigned long watchdog_is_open;
234 char watchdog_expect_close;
235 char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
215 char valid; /* zero until following fields are valid */ 236 char valid; /* zero until following fields are valid */
216 unsigned long last_updated; /* in jiffies */ 237 unsigned long last_updated; /* in jiffies */
217 238
218 /* register values */ 239 /* register values */
240 u8 revision; /* chip revision */
219 u8 global_control; /* global control register */ 241 u8 global_control; /* global control register */
242 u8 watchdog_control; /* watchdog control register */
243 u8 watchdog_state; /* watchdog status register */
244 u8 watchdog_preset; /* watchdog counter preset on trigger val */
220 u8 volt[3]; /* 12, 5, battery voltage */ 245 u8 volt[3]; /* 12, 5, battery voltage */
221 u8 temp_act[5]; /* temperature */ 246 u8 temp_act[5]; /* temperature */
222 u8 temp_status[5]; /* status of sensor */ 247 u8 temp_status[5]; /* status of sensor */
@@ -228,11 +253,28 @@ struct fschmd_data {
228}; 253};
229 254
230/* Global variables to hold information read from special DMI tables, which are 255/* Global variables to hold information read from special DMI tables, which are
231 available on FSC machines with an fscher or later chip. */ 256 available on FSC machines with an fscher or later chip. There is no need to
257 protect these with a lock as they are only modified from our attach function
258 which always gets called with the i2c-core lock held and never accessed
259 before the attach function is done with them. */
232static int dmi_mult[3] = { 490, 200, 100 }; 260static int dmi_mult[3] = { 490, 200, 100 };
233static int dmi_offset[3] = { 0, 0, 0 }; 261static int dmi_offset[3] = { 0, 0, 0 };
234static int dmi_vref = -1; 262static int dmi_vref = -1;
235 263
264/* Somewhat ugly :( global data pointer list with all fschmd devices, so that
265 we can find our device data as when using misc_register there is no other
266 method to get to ones device data from the open fop. */
267static LIST_HEAD(watchdog_data_list);
268/* Note this lock not only protect list access, but also data.kref access */
269static DEFINE_MUTEX(watchdog_data_mutex);
270
271/* Release our data struct when we're detached from the i2c client *and* all
272 references to our watchdog device are released */
273static void fschmd_release_resources(struct kref *ref)
274{
275 struct fschmd_data *data = container_of(ref, struct fschmd_data, kref);
276 kfree(data);
277}
236 278
237/* 279/*
238 * Sysfs attr show / store functions 280 * Sysfs attr show / store functions
@@ -300,7 +342,7 @@ static ssize_t show_temp_fault(struct device *dev,
300 struct fschmd_data *data = fschmd_update_device(dev); 342 struct fschmd_data *data = fschmd_update_device(dev);
301 343
302 /* bit 0 set means sensor working ok, so no fault! */ 344 /* bit 0 set means sensor working ok, so no fault! */
303 if (data->temp_status[index] & FSCHMD_TEMP_WORKING_MASK) 345 if (data->temp_status[index] & FSCHMD_TEMP_WORKING)
304 return sprintf(buf, "0\n"); 346 return sprintf(buf, "0\n");
305 else 347 else
306 return sprintf(buf, "1\n"); 348 return sprintf(buf, "1\n");
@@ -385,7 +427,7 @@ static ssize_t show_fan_alarm(struct device *dev,
385 int index = to_sensor_dev_attr(devattr)->index; 427 int index = to_sensor_dev_attr(devattr)->index;
386 struct fschmd_data *data = fschmd_update_device(dev); 428 struct fschmd_data *data = fschmd_update_device(dev);
387 429
388 if (data->fan_status[index] & FSCHMD_FAN_ALARM_MASK) 430 if (data->fan_status[index] & FSCHMD_FAN_ALARM)
389 return sprintf(buf, "1\n"); 431 return sprintf(buf, "1\n");
390 else 432 else
391 return sprintf(buf, "0\n"); 433 return sprintf(buf, "0\n");
@@ -397,7 +439,7 @@ static ssize_t show_fan_fault(struct device *dev,
397 int index = to_sensor_dev_attr(devattr)->index; 439 int index = to_sensor_dev_attr(devattr)->index;
398 struct fschmd_data *data = fschmd_update_device(dev); 440 struct fschmd_data *data = fschmd_update_device(dev);
399 441
400 if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT_MASK) 442 if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT)
401 return sprintf(buf, "1\n"); 443 return sprintf(buf, "1\n");
402 else 444 else
403 return sprintf(buf, "0\n"); 445 return sprintf(buf, "0\n");
@@ -449,7 +491,7 @@ static ssize_t show_alert_led(struct device *dev,
449{ 491{
450 struct fschmd_data *data = fschmd_update_device(dev); 492 struct fschmd_data *data = fschmd_update_device(dev);
451 493
452 if (data->global_control & FSCHMD_CONTROL_ALERT_LED_MASK) 494 if (data->global_control & FSCHMD_CONTROL_ALERT_LED)
453 return sprintf(buf, "1\n"); 495 return sprintf(buf, "1\n");
454 else 496 else
455 return sprintf(buf, "0\n"); 497 return sprintf(buf, "0\n");
@@ -467,9 +509,9 @@ static ssize_t store_alert_led(struct device *dev,
467 reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL); 509 reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL);
468 510
469 if (v) 511 if (v)
470 reg |= FSCHMD_CONTROL_ALERT_LED_MASK; 512 reg |= FSCHMD_CONTROL_ALERT_LED;
471 else 513 else
472 reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK; 514 reg &= ~FSCHMD_CONTROL_ALERT_LED;
473 515
474 i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg); 516 i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg);
475 517
@@ -551,7 +593,265 @@ static struct sensor_device_attribute fschmd_fan_attr[] = {
551 593
552 594
553/* 595/*
554 * Real code 596 * Watchdog routines
597 */
598
599static int watchdog_set_timeout(struct fschmd_data *data, int timeout)
600{
601 int ret, resolution;
602 int kind = data->kind + 1; /* 0-x array index -> 1-x module param */
603
604 /* 2 second or 60 second resolution? */
605 if (timeout <= 510 || kind == fscpos || kind == fscscy)
606 resolution = 2;
607 else
608 resolution = 60;
609
610 if (timeout < resolution || timeout > (resolution * 255))
611 return -EINVAL;
612
613 mutex_lock(&data->watchdog_lock);
614 if (!data->client) {
615 ret = -ENODEV;
616 goto leave;
617 }
618
619 if (resolution == 2)
620 data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_RESOLUTION;
621 else
622 data->watchdog_control |= FSCHMD_WDOG_CONTROL_RESOLUTION;
623
624 data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
625
626 /* Write new timeout value */
627 i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET,
628 data->watchdog_preset);
629 /* Write new control register, do not trigger! */
630 i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
631 data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
632
633 ret = data->watchdog_preset * resolution;
634
635leave:
636 mutex_unlock(&data->watchdog_lock);
637 return ret;
638}
639
640static int watchdog_get_timeout(struct fschmd_data *data)
641{
642 int timeout;
643
644 mutex_lock(&data->watchdog_lock);
645 if (data->watchdog_control & FSCHMD_WDOG_CONTROL_RESOLUTION)
646 timeout = data->watchdog_preset * 60;
647 else
648 timeout = data->watchdog_preset * 2;
649 mutex_unlock(&data->watchdog_lock);
650
651 return timeout;
652}
653
654static int watchdog_trigger(struct fschmd_data *data)
655{
656 int ret = 0;
657
658 mutex_lock(&data->watchdog_lock);
659 if (!data->client) {
660 ret = -ENODEV;
661 goto leave;
662 }
663
664 data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
665 i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
666 data->watchdog_control);
667leave:
668 mutex_unlock(&data->watchdog_lock);
669 return ret;
670}
671
672static int watchdog_stop(struct fschmd_data *data)
673{
674 int ret = 0;
675
676 mutex_lock(&data->watchdog_lock);
677 if (!data->client) {
678 ret = -ENODEV;
679 goto leave;
680 }
681
682 data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
683 /* Don't store the stop flag in our watchdog control register copy, as
684 its a write only bit (read always returns 0) */
685 i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL,
686 data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
687leave:
688 mutex_unlock(&data->watchdog_lock);
689 return ret;
690}
691
692static int watchdog_open(struct inode *inode, struct file *filp)
693{
694 struct fschmd_data *pos, *data = NULL;
695
696 /* We get called from drivers/char/misc.c with misc_mtx hold, and we
697 call misc_register() from fschmd_probe() with watchdog_data_mutex
698 hold, as misc_register() takes the misc_mtx lock, this is a possible
699 deadlock, so we use mutex_trylock here. */
700 if (!mutex_trylock(&watchdog_data_mutex))
701 return -ERESTARTSYS;
702 list_for_each_entry(pos, &watchdog_data_list, list) {
703 if (pos->watchdog_miscdev.minor == iminor(inode)) {
704 data = pos;
705 break;
706 }
707 }
708 /* Note we can never not have found data, so we don't check for this */
709 kref_get(&data->kref);
710 mutex_unlock(&watchdog_data_mutex);
711
712 if (test_and_set_bit(0, &data->watchdog_is_open))
713 return -EBUSY;
714
715 /* Start the watchdog */
716 watchdog_trigger(data);
717 filp->private_data = data;
718
719 return nonseekable_open(inode, filp);
720}
721
722static int watchdog_release(struct inode *inode, struct file *filp)
723{
724 struct fschmd_data *data = filp->private_data;
725
726 if (data->watchdog_expect_close) {
727 watchdog_stop(data);
728 data->watchdog_expect_close = 0;
729 } else {
730 watchdog_trigger(data);
731 dev_crit(&data->client->dev,
732 "unexpected close, not stopping watchdog!\n");
733 }
734
735 clear_bit(0, &data->watchdog_is_open);
736
737 mutex_lock(&watchdog_data_mutex);
738 kref_put(&data->kref, fschmd_release_resources);
739 mutex_unlock(&watchdog_data_mutex);
740
741 return 0;
742}
743
744static ssize_t watchdog_write(struct file *filp, const char __user *buf,
745 size_t count, loff_t *offset)
746{
747 size_t ret;
748 struct fschmd_data *data = filp->private_data;
749
750 if (count) {
751 if (!nowayout) {
752 size_t i;
753
754 /* Clear it in case it was set with a previous write */
755 data->watchdog_expect_close = 0;
756
757 for (i = 0; i != count; i++) {
758 char c;
759 if (get_user(c, buf + i))
760 return -EFAULT;
761 if (c == 'V')
762 data->watchdog_expect_close = 1;
763 }
764 }
765 ret = watchdog_trigger(data);
766 if (ret < 0)
767 return ret;
768 }
769 return count;
770}
771
772static int watchdog_ioctl(struct inode *inode, struct file *filp,
773 unsigned int cmd, unsigned long arg)
774{
775 static struct watchdog_info ident = {
776 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
777 WDIOF_CARDRESET,
778 .identity = "FSC watchdog"
779 };
780 int i, ret = 0;
781 struct fschmd_data *data = filp->private_data;
782
783 switch (cmd) {
784 case WDIOC_GETSUPPORT:
785 ident.firmware_version = data->revision;
786 if (!nowayout)
787 ident.options |= WDIOF_MAGICCLOSE;
788 if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
789 ret = -EFAULT;
790 break;
791
792 case WDIOC_GETSTATUS:
793 ret = put_user(0, (int __user *)arg);
794 break;
795
796 case WDIOC_GETBOOTSTATUS:
797 if (data->watchdog_state & FSCHMD_WDOG_STATE_CARDRESET)
798 ret = put_user(WDIOF_CARDRESET, (int __user *)arg);
799 else
800 ret = put_user(0, (int __user *)arg);
801 break;
802
803 case WDIOC_KEEPALIVE:
804 ret = watchdog_trigger(data);
805 break;
806
807 case WDIOC_GETTIMEOUT:
808 i = watchdog_get_timeout(data);
809 ret = put_user(i, (int __user *)arg);
810 break;
811
812 case WDIOC_SETTIMEOUT:
813 if (get_user(i, (int __user *)arg)) {
814 ret = -EFAULT;
815 break;
816 }
817 ret = watchdog_set_timeout(data, i);
818 if (ret > 0)
819 ret = put_user(ret, (int __user *)arg);
820 break;
821
822 case WDIOC_SETOPTIONS:
823 if (get_user(i, (int __user *)arg)) {
824 ret = -EFAULT;
825 break;
826 }
827
828 if (i & WDIOS_DISABLECARD)
829 ret = watchdog_stop(data);
830 else if (i & WDIOS_ENABLECARD)
831 ret = watchdog_trigger(data);
832 else
833 ret = -EINVAL;
834
835 break;
836 default:
837 ret = -ENOTTY;
838 }
839
840 return ret;
841}
842
843static struct file_operations watchdog_fops = {
844 .owner = THIS_MODULE,
845 .llseek = no_llseek,
846 .open = watchdog_open,
847 .release = watchdog_release,
848 .write = watchdog_write,
849 .ioctl = watchdog_ioctl,
850};
851
852
853/*
854 * Detect, register, unregister and update device functions
555 */ 855 */
556 856
557/* DMI decode routine to read voltage scaling factors from special DMI tables, 857/* DMI decode routine to read voltage scaling factors from special DMI tables,
@@ -661,9 +961,9 @@ static int fschmd_probe(struct i2c_client *client,
661 const struct i2c_device_id *id) 961 const struct i2c_device_id *id)
662{ 962{
663 struct fschmd_data *data; 963 struct fschmd_data *data;
664 u8 revision;
665 const char * const names[5] = { "Poseidon", "Hermes", "Scylla", 964 const char * const names[5] = { "Poseidon", "Hermes", "Scylla",
666 "Heracles", "Heimdall" }; 965 "Heracles", "Heimdall" };
966 const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
667 int i, err; 967 int i, err;
668 enum chips kind = id->driver_data; 968 enum chips kind = id->driver_data;
669 969
@@ -673,6 +973,13 @@ static int fschmd_probe(struct i2c_client *client,
673 973
674 i2c_set_clientdata(client, data); 974 i2c_set_clientdata(client, data);
675 mutex_init(&data->update_lock); 975 mutex_init(&data->update_lock);
976 mutex_init(&data->watchdog_lock);
977 INIT_LIST_HEAD(&data->list);
978 kref_init(&data->kref);
979 /* Store client pointer in our data struct for watchdog usage
980 (where the client is found through a data ptr instead of the
981 otherway around) */
982 data->client = client;
676 983
677 if (kind == fscpos) { 984 if (kind == fscpos) {
678 /* The Poseidon has hardwired temp limits, fill these 985 /* The Poseidon has hardwired temp limits, fill these
@@ -683,16 +990,27 @@ static int fschmd_probe(struct i2c_client *client,
683 } 990 }
684 991
685 /* Read the special DMI table for fscher and newer chips */ 992 /* Read the special DMI table for fscher and newer chips */
686 if (kind == fscher || kind >= fschrc) { 993 if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
687 dmi_walk(fschmd_dmi_decode); 994 dmi_walk(fschmd_dmi_decode);
688 if (dmi_vref == -1) { 995 if (dmi_vref == -1) {
689 printk(KERN_WARNING FSCHMD_NAME 996 dev_warn(&client->dev,
690 ": Couldn't get voltage scaling factors from " 997 "Couldn't get voltage scaling factors from "
691 "BIOS DMI table, using builtin defaults\n"); 998 "BIOS DMI table, using builtin defaults\n");
692 dmi_vref = 33; 999 dmi_vref = 33;
693 } 1000 }
694 } 1001 }
695 1002
1003 /* Read in some never changing registers */
1004 data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
1005 data->global_control = i2c_smbus_read_byte_data(client,
1006 FSCHMD_REG_CONTROL);
1007 data->watchdog_control = i2c_smbus_read_byte_data(client,
1008 FSCHMD_REG_WDOG_CONTROL);
1009 data->watchdog_state = i2c_smbus_read_byte_data(client,
1010 FSCHMD_REG_WDOG_STATE);
1011 data->watchdog_preset = i2c_smbus_read_byte_data(client,
1012 FSCHMD_REG_WDOG_PRESET);
1013
696 /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ 1014 /* i2c kind goes from 1-5, we want from 0-4 to address arrays */
697 data->kind = kind - 1; 1015 data->kind = kind - 1;
698 1016
@@ -735,9 +1053,43 @@ static int fschmd_probe(struct i2c_client *client,
735 goto exit_detach; 1053 goto exit_detach;
736 } 1054 }
737 1055
738 revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); 1056 /* We take the data_mutex lock early so that watchdog_open() cannot
739 printk(KERN_INFO FSCHMD_NAME ": Detected FSC %s chip, revision: %d\n", 1057 run when misc_register() has completed, but we've not yet added
740 names[data->kind], (int) revision); 1058 our data to the watchdog_data_list (and set the default timeout) */
1059 mutex_lock(&watchdog_data_mutex);
1060 for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
1061 /* Register our watchdog part */
1062 snprintf(data->watchdog_name, sizeof(data->watchdog_name),
1063 "watchdog%c", (i == 0) ? '\0' : ('0' + i));
1064 data->watchdog_miscdev.name = data->watchdog_name;
1065 data->watchdog_miscdev.fops = &watchdog_fops;
1066 data->watchdog_miscdev.minor = watchdog_minors[i];
1067 err = misc_register(&data->watchdog_miscdev);
1068 if (err == -EBUSY)
1069 continue;
1070 if (err) {
1071 data->watchdog_miscdev.minor = 0;
1072 dev_err(&client->dev,
1073 "Registering watchdog chardev: %d\n", err);
1074 break;
1075 }
1076
1077 list_add(&data->list, &watchdog_data_list);
1078 watchdog_set_timeout(data, 60);
1079 dev_info(&client->dev,
1080 "Registered watchdog chardev major 10, minor: %d\n",
1081 watchdog_minors[i]);
1082 break;
1083 }
1084 if (i == ARRAY_SIZE(watchdog_minors)) {
1085 data->watchdog_miscdev.minor = 0;
1086 dev_warn(&client->dev, "Couldn't register watchdog chardev "
1087 "(due to no free minor)\n");
1088 }
1089 mutex_unlock(&watchdog_data_mutex);
1090
1091 dev_info(&client->dev, "Detected FSC %s chip, revision: %d\n",
1092 names[data->kind], (int) data->revision);
741 1093
742 return 0; 1094 return 0;
743 1095
@@ -751,6 +1103,24 @@ static int fschmd_remove(struct i2c_client *client)
751 struct fschmd_data *data = i2c_get_clientdata(client); 1103 struct fschmd_data *data = i2c_get_clientdata(client);
752 int i; 1104 int i;
753 1105
1106 /* Unregister the watchdog (if registered) */
1107 if (data->watchdog_miscdev.minor) {
1108 misc_deregister(&data->watchdog_miscdev);
1109 if (data->watchdog_is_open) {
1110 dev_warn(&client->dev,
1111 "i2c client detached with watchdog open! "
1112 "Stopping watchdog.\n");
1113 watchdog_stop(data);
1114 }
1115 mutex_lock(&watchdog_data_mutex);
1116 list_del(&data->list);
1117 mutex_unlock(&watchdog_data_mutex);
1118 /* Tell the watchdog code the client is gone */
1119 mutex_lock(&data->watchdog_lock);
1120 data->client = NULL;
1121 mutex_unlock(&data->watchdog_lock);
1122 }
1123
754 /* Check if registered in case we're called from fschmd_detect 1124 /* Check if registered in case we're called from fschmd_detect
755 to cleanup after an error */ 1125 to cleanup after an error */
756 if (data->hwmon_dev) 1126 if (data->hwmon_dev)
@@ -765,7 +1135,10 @@ static int fschmd_remove(struct i2c_client *client)
765 device_remove_file(&client->dev, 1135 device_remove_file(&client->dev,
766 &fschmd_fan_attr[i].dev_attr); 1136 &fschmd_fan_attr[i].dev_attr);
767 1137
768 kfree(data); 1138 mutex_lock(&watchdog_data_mutex);
1139 kref_put(&data->kref, fschmd_release_resources);
1140 mutex_unlock(&watchdog_data_mutex);
1141
769 return 0; 1142 return 0;
770} 1143}
771 1144
@@ -798,7 +1171,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
798 data->temp_act[i] < data->temp_max[i]) 1171 data->temp_act[i] < data->temp_max[i])
799 i2c_smbus_write_byte_data(client, 1172 i2c_smbus_write_byte_data(client,
800 FSCHMD_REG_TEMP_STATE[data->kind][i], 1173 FSCHMD_REG_TEMP_STATE[data->kind][i],
801 FSCHMD_TEMP_ALERT_MASK); 1174 FSCHMD_TEMP_ALERT);
802 } 1175 }
803 1176
804 for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { 1177 for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
@@ -816,28 +1189,17 @@ static struct fschmd_data *fschmd_update_device(struct device *dev)
816 FSCHMD_REG_FAN_MIN[data->kind][i]); 1189 FSCHMD_REG_FAN_MIN[data->kind][i]);
817 1190
818 /* reset fan status if speed is back to > 0 */ 1191 /* reset fan status if speed is back to > 0 */
819 if ((data->fan_status[i] & FSCHMD_FAN_ALARM_MASK) && 1192 if ((data->fan_status[i] & FSCHMD_FAN_ALARM) &&
820 data->fan_act[i]) 1193 data->fan_act[i])
821 i2c_smbus_write_byte_data(client, 1194 i2c_smbus_write_byte_data(client,
822 FSCHMD_REG_FAN_STATE[data->kind][i], 1195 FSCHMD_REG_FAN_STATE[data->kind][i],
823 FSCHMD_FAN_ALARM_MASK); 1196 FSCHMD_FAN_ALARM);
824 } 1197 }
825 1198
826 for (i = 0; i < 3; i++) 1199 for (i = 0; i < 3; i++)
827 data->volt[i] = i2c_smbus_read_byte_data(client, 1200 data->volt[i] = i2c_smbus_read_byte_data(client,
828 FSCHMD_REG_VOLT[i]); 1201 FSCHMD_REG_VOLT[i]);
829 1202
830 data->global_control = i2c_smbus_read_byte_data(client,
831 FSCHMD_REG_CONTROL);
832
833 /* To be implemented in the future
834 data->watchdog[0] = i2c_smbus_read_byte_data(client,
835 FSCHMD_REG_WDOG_PRESET);
836 data->watchdog[1] = i2c_smbus_read_byte_data(client,
837 FSCHMD_REG_WDOG_STATE);
838 data->watchdog[2] = i2c_smbus_read_byte_data(client,
839 FSCHMD_REG_WDOG_CONTROL); */
840
841 data->last_updated = jiffies; 1203 data->last_updated = jiffies;
842 data->valid = 1; 1204 data->valid = 1;
843 } 1205 }
@@ -857,7 +1219,7 @@ static void __exit fschmd_exit(void)
857 i2c_del_driver(&fschmd_driver); 1219 i2c_del_driver(&fschmd_driver);
858} 1220}
859 1221
860MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>"); 1222MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
861MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and " 1223MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and "
862 "Heimdall driver"); 1224 "Heimdall driver");
863MODULE_LICENSE("GPL"); 1225MODULE_LICENSE("GPL");