Commit 008e5f3350e0a474baff3ed3eb4f79653a6b6745
1 parent
9d32df192d
Exists in
master
and in
4 other branches
hwmon: (pc87427) Add temperature monitoring support
Add support for the 6 temperature monitoring channels of the PC87427. Note that the sensors resolution can vary, and I couldn't find a way to figure it out, so we might have to compensate in user-space. Signed-off-by: Jean Delvare <khali@linux-fr.org> Acked-by: Guenter Roeck <guenter.roeck@ericsson.com>
Showing 3 changed files with 379 additions and 7 deletions Side-by-side Diff
Documentation/hwmon/pc87427
... | ... | @@ -18,7 +18,8 @@ |
18 | 18 | |
19 | 19 | The National Semiconductor Super I/O chip includes complete hardware |
20 | 20 | monitoring capabilities. It can monitor up to 18 voltages, 8 fans and |
21 | -6 temperature sensors. Only the fans are supported at the moment. | |
21 | +6 temperature sensors. Only the fans and temperatures are supported at | |
22 | +the moment, voltages aren't. | |
22 | 23 | |
23 | 24 | This chip also has fan controlling features (up to 4 PWM outputs), |
24 | 25 | which are partly supported by this driver. |
... | ... | @@ -45,4 +46,15 @@ |
45 | 46 | always off, always on, manual and automatic. The latter isn't supported |
46 | 47 | by the driver: you can only return to that mode if it was the original |
47 | 48 | setting, and the configuration interface is missing. |
49 | + | |
50 | + | |
51 | +Temperature Monitoring | |
52 | +---------------------- | |
53 | + | |
54 | +The PC87427 relies on external sensors (following the SensorPath | |
55 | +standard), so the resolution and range depend on the type of sensor | |
56 | +connected. The integer part can be 8-bit or 9-bit, and can be signed or | |
57 | +not. I couldn't find a way to figure out the external sensor data | |
58 | +temperature format, so user-space adjustment (typically by a factor 2) | |
59 | +may be required. |
drivers/hwmon/Kconfig
... | ... | @@ -711,8 +711,8 @@ |
711 | 711 | functions of the National Semiconductor PC87427 Super-I/O chip. |
712 | 712 | The chip has two distinct logical devices, one for fan speed |
713 | 713 | monitoring and control, and one for voltage and temperature |
714 | - monitoring. Only fan speed monitoring and control is supported | |
715 | - right now. | |
714 | + monitoring. Fan speed monitoring and control are supported, as | |
715 | + well as temperature monitoring. Voltages aren't supported yet. | |
716 | 716 | |
717 | 717 | This driver can also be built as a module. If so, the module |
718 | 718 | will be called pc87427. |
drivers/hwmon/pc87427.c
1 | 1 | /* |
2 | 2 | * pc87427.c - hardware monitoring driver for the |
3 | 3 | * National Semiconductor PC87427 Super-I/O chip |
4 | - * Copyright (C) 2006, 2008 Jean Delvare <khali@linux-fr.org> | |
4 | + * Copyright (C) 2006, 2008, 2010 Jean Delvare <khali@linux-fr.org> | |
5 | 5 | * |
6 | 6 | * This program is free software; you can redistribute it and/or modify |
7 | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | 8 | |
... | ... | @@ -15,10 +15,11 @@ |
15 | 15 | * Supports the following chips: |
16 | 16 | * |
17 | 17 | * Chip #vin #fan #pwm #temp devid |
18 | - * PC87427 - 8 4 - 0xF2 | |
18 | + * PC87427 - 8 4 6 0xF2 | |
19 | 19 | * |
20 | 20 | * This driver assumes that no more than one chip is present. |
21 | - * Only fans are supported so far, although the chip can do much more. | |
21 | + * Only fans are fully supported so far. Temperatures are in read-only | |
22 | + * mode, and voltages aren't supported at all. | |
22 | 23 | */ |
23 | 24 | |
24 | 25 | #include <linux/module.h> |
... | ... | @@ -62,6 +63,14 @@ |
62 | 63 | u8 pwm_auto_ok; /* bit vector */ |
63 | 64 | u8 pwm_enable[4]; /* register values */ |
64 | 65 | u8 pwm[4]; /* register values */ |
66 | + | |
67 | + u8 temp_enabled; /* bit vector */ | |
68 | + s16 temp[6]; /* register values */ | |
69 | + s8 temp_min[6]; /* register values */ | |
70 | + s8 temp_max[6]; /* register values */ | |
71 | + s8 temp_crit[6]; /* register values */ | |
72 | + u8 temp_status[6]; /* register values */ | |
73 | + u8 temp_type[6]; /* register values */ | |
65 | 74 | }; |
66 | 75 | |
67 | 76 | struct pc87427_sio_data { |
... | ... | @@ -120,6 +129,8 @@ |
120 | 129 | #define BANK_FM(nr) (nr) |
121 | 130 | #define BANK_FT(nr) (0x08 + (nr)) |
122 | 131 | #define BANK_FC(nr) (0x10 + (nr) * 2) |
132 | +#define BANK_TM(nr) (nr) | |
133 | +#define BANK_VM(nr) (0x08 + (nr)) | |
123 | 134 | |
124 | 135 | /* |
125 | 136 | * I/O access functions |
... | ... | @@ -252,6 +263,72 @@ |
252 | 263 | } |
253 | 264 | |
254 | 265 | /* |
266 | + * Temperature registers and conversions | |
267 | + */ | |
268 | + | |
269 | +#define PC87427_REG_TEMP_STATUS 0x10 | |
270 | +#define PC87427_REG_TEMP 0x14 | |
271 | +#define PC87427_REG_TEMP_MAX 0x18 | |
272 | +#define PC87427_REG_TEMP_MIN 0x19 | |
273 | +#define PC87427_REG_TEMP_CRIT 0x1a | |
274 | +#define PC87427_REG_TEMP_TYPE 0x1d | |
275 | + | |
276 | +#define TEMP_STATUS_CHANEN (1 << 0) | |
277 | +#define TEMP_STATUS_LOWFLG (1 << 1) | |
278 | +#define TEMP_STATUS_HIGHFLG (1 << 2) | |
279 | +#define TEMP_STATUS_CRITFLG (1 << 3) | |
280 | +#define TEMP_STATUS_SENSERR (1 << 5) | |
281 | +#define TEMP_TYPE_MASK (3 << 5) | |
282 | + | |
283 | +#define TEMP_TYPE_THERMISTOR (1 << 5) | |
284 | +#define TEMP_TYPE_REMOTE_DIODE (2 << 5) | |
285 | +#define TEMP_TYPE_LOCAL_DIODE (3 << 5) | |
286 | + | |
287 | +/* Dedicated function to read all registers related to a given temperature | |
288 | + input. This saves us quite a few locks and bank selections. | |
289 | + Must be called with data->lock held. | |
290 | + nr is from 0 to 5 */ | |
291 | +static void pc87427_readall_temp(struct pc87427_data *data, u8 nr) | |
292 | +{ | |
293 | + int iobase = data->address[LD_TEMP]; | |
294 | + | |
295 | + outb(BANK_TM(nr), iobase + PC87427_REG_BANK); | |
296 | + data->temp[nr] = le16_to_cpu(inw(iobase + PC87427_REG_TEMP)); | |
297 | + data->temp_max[nr] = inb(iobase + PC87427_REG_TEMP_MAX); | |
298 | + data->temp_min[nr] = inb(iobase + PC87427_REG_TEMP_MIN); | |
299 | + data->temp_crit[nr] = inb(iobase + PC87427_REG_TEMP_CRIT); | |
300 | + data->temp_type[nr] = inb(iobase + PC87427_REG_TEMP_TYPE); | |
301 | + data->temp_status[nr] = inb(iobase + PC87427_REG_TEMP_STATUS); | |
302 | + /* Clear fan alarm bits */ | |
303 | + outb(data->temp_status[nr], iobase + PC87427_REG_TEMP_STATUS); | |
304 | +} | |
305 | + | |
306 | +static inline unsigned int temp_type_from_reg(u8 reg) | |
307 | +{ | |
308 | + switch (reg & TEMP_TYPE_MASK) { | |
309 | + case TEMP_TYPE_THERMISTOR: | |
310 | + return 4; | |
311 | + case TEMP_TYPE_REMOTE_DIODE: | |
312 | + case TEMP_TYPE_LOCAL_DIODE: | |
313 | + return 3; | |
314 | + default: | |
315 | + return 0; | |
316 | + } | |
317 | +} | |
318 | + | |
319 | +/* We assume 8-bit thermal sensors; 9-bit thermal sensors are possible | |
320 | + too, but I have no idea how to figure out when they are used. */ | |
321 | +static inline long temp_from_reg(s16 reg) | |
322 | +{ | |
323 | + return reg * 1000 / 256; | |
324 | +} | |
325 | + | |
326 | +static inline long temp_from_reg8(s8 reg) | |
327 | +{ | |
328 | + return reg * 1000; | |
329 | +} | |
330 | + | |
331 | +/* | |
255 | 332 | * Data interface |
256 | 333 | */ |
257 | 334 | |
... | ... | @@ -279,6 +356,13 @@ |
279 | 356 | pc87427_readall_pwm(data, i); |
280 | 357 | } |
281 | 358 | |
359 | + /* Temperature channels */ | |
360 | + for (i = 0; i < 6; i++) { | |
361 | + if (!(data->temp_enabled & (1 << i))) | |
362 | + continue; | |
363 | + pc87427_readall_temp(data, i); | |
364 | + } | |
365 | + | |
282 | 366 | data->last_updated = jiffies; |
283 | 367 | |
284 | 368 | done: |
... | ... | @@ -595,6 +679,251 @@ |
595 | 679 | { .attrs = pc87427_attributes_pwm[3] }, |
596 | 680 | }; |
597 | 681 | |
682 | +static ssize_t show_temp_input(struct device *dev, struct device_attribute | |
683 | + *devattr, char *buf) | |
684 | +{ | |
685 | + struct pc87427_data *data = pc87427_update_device(dev); | |
686 | + int nr = to_sensor_dev_attr(devattr)->index; | |
687 | + | |
688 | + return sprintf(buf, "%ld\n", temp_from_reg(data->temp[nr])); | |
689 | +} | |
690 | + | |
691 | +static ssize_t show_temp_min(struct device *dev, struct device_attribute | |
692 | + *devattr, char *buf) | |
693 | +{ | |
694 | + struct pc87427_data *data = pc87427_update_device(dev); | |
695 | + int nr = to_sensor_dev_attr(devattr)->index; | |
696 | + | |
697 | + return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_min[nr])); | |
698 | +} | |
699 | + | |
700 | +static ssize_t show_temp_max(struct device *dev, struct device_attribute | |
701 | + *devattr, char *buf) | |
702 | +{ | |
703 | + struct pc87427_data *data = pc87427_update_device(dev); | |
704 | + int nr = to_sensor_dev_attr(devattr)->index; | |
705 | + | |
706 | + return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_max[nr])); | |
707 | +} | |
708 | + | |
709 | +static ssize_t show_temp_crit(struct device *dev, struct device_attribute | |
710 | + *devattr, char *buf) | |
711 | +{ | |
712 | + struct pc87427_data *data = pc87427_update_device(dev); | |
713 | + int nr = to_sensor_dev_attr(devattr)->index; | |
714 | + | |
715 | + return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_crit[nr])); | |
716 | +} | |
717 | + | |
718 | +static ssize_t show_temp_type(struct device *dev, struct device_attribute | |
719 | + *devattr, char *buf) | |
720 | +{ | |
721 | + struct pc87427_data *data = pc87427_update_device(dev); | |
722 | + int nr = to_sensor_dev_attr(devattr)->index; | |
723 | + | |
724 | + return sprintf(buf, "%u\n", temp_type_from_reg(data->temp_type[nr])); | |
725 | +} | |
726 | + | |
727 | +static ssize_t show_temp_min_alarm(struct device *dev, struct device_attribute | |
728 | + *devattr, char *buf) | |
729 | +{ | |
730 | + struct pc87427_data *data = pc87427_update_device(dev); | |
731 | + int nr = to_sensor_dev_attr(devattr)->index; | |
732 | + | |
733 | + return sprintf(buf, "%d\n", !!(data->temp_status[nr] | |
734 | + & TEMP_STATUS_LOWFLG)); | |
735 | +} | |
736 | + | |
737 | +static ssize_t show_temp_max_alarm(struct device *dev, struct device_attribute | |
738 | + *devattr, char *buf) | |
739 | +{ | |
740 | + struct pc87427_data *data = pc87427_update_device(dev); | |
741 | + int nr = to_sensor_dev_attr(devattr)->index; | |
742 | + | |
743 | + return sprintf(buf, "%d\n", !!(data->temp_status[nr] | |
744 | + & TEMP_STATUS_HIGHFLG)); | |
745 | +} | |
746 | + | |
747 | +static ssize_t show_temp_crit_alarm(struct device *dev, struct device_attribute | |
748 | + *devattr, char *buf) | |
749 | +{ | |
750 | + struct pc87427_data *data = pc87427_update_device(dev); | |
751 | + int nr = to_sensor_dev_attr(devattr)->index; | |
752 | + | |
753 | + return sprintf(buf, "%d\n", !!(data->temp_status[nr] | |
754 | + & TEMP_STATUS_CRITFLG)); | |
755 | +} | |
756 | + | |
757 | +static ssize_t show_temp_fault(struct device *dev, struct device_attribute | |
758 | + *devattr, char *buf) | |
759 | +{ | |
760 | + struct pc87427_data *data = pc87427_update_device(dev); | |
761 | + int nr = to_sensor_dev_attr(devattr)->index; | |
762 | + | |
763 | + return sprintf(buf, "%d\n", !!(data->temp_status[nr] | |
764 | + & TEMP_STATUS_SENSERR)); | |
765 | +} | |
766 | + | |
767 | +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0); | |
768 | +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1); | |
769 | +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2); | |
770 | +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3); | |
771 | +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4); | |
772 | +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5); | |
773 | + | |
774 | +static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp_min, NULL, 0); | |
775 | +static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp_min, NULL, 1); | |
776 | +static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp_min, NULL, 2); | |
777 | +static SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO, show_temp_min, NULL, 3); | |
778 | +static SENSOR_DEVICE_ATTR(temp5_min, S_IRUGO, show_temp_min, NULL, 4); | |
779 | +static SENSOR_DEVICE_ATTR(temp6_min, S_IRUGO, show_temp_min, NULL, 5); | |
780 | + | |
781 | +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL, 0); | |
782 | +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max, NULL, 1); | |
783 | +static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max, NULL, 2); | |
784 | +static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max, NULL, 3); | |
785 | +static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max, NULL, 4); | |
786 | +static SENSOR_DEVICE_ATTR(temp6_max, S_IRUGO, show_temp_max, NULL, 5); | |
787 | + | |
788 | +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); | |
789 | +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL, 1); | |
790 | +static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit, NULL, 2); | |
791 | +static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL, 3); | |
792 | +static SENSOR_DEVICE_ATTR(temp5_crit, S_IRUGO, show_temp_crit, NULL, 4); | |
793 | +static SENSOR_DEVICE_ATTR(temp6_crit, S_IRUGO, show_temp_crit, NULL, 5); | |
794 | + | |
795 | +static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0); | |
796 | +static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1); | |
797 | +static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2); | |
798 | +static SENSOR_DEVICE_ATTR(temp4_type, S_IRUGO, show_temp_type, NULL, 3); | |
799 | +static SENSOR_DEVICE_ATTR(temp5_type, S_IRUGO, show_temp_type, NULL, 4); | |
800 | +static SENSOR_DEVICE_ATTR(temp6_type, S_IRUGO, show_temp_type, NULL, 5); | |
801 | + | |
802 | +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, | |
803 | + show_temp_min_alarm, NULL, 0); | |
804 | +static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, | |
805 | + show_temp_min_alarm, NULL, 1); | |
806 | +static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, | |
807 | + show_temp_min_alarm, NULL, 2); | |
808 | +static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, | |
809 | + show_temp_min_alarm, NULL, 3); | |
810 | +static SENSOR_DEVICE_ATTR(temp5_min_alarm, S_IRUGO, | |
811 | + show_temp_min_alarm, NULL, 4); | |
812 | +static SENSOR_DEVICE_ATTR(temp6_min_alarm, S_IRUGO, | |
813 | + show_temp_min_alarm, NULL, 5); | |
814 | + | |
815 | +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, | |
816 | + show_temp_max_alarm, NULL, 0); | |
817 | +static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, | |
818 | + show_temp_max_alarm, NULL, 1); | |
819 | +static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, | |
820 | + show_temp_max_alarm, NULL, 2); | |
821 | +static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, | |
822 | + show_temp_max_alarm, NULL, 3); | |
823 | +static SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, | |
824 | + show_temp_max_alarm, NULL, 4); | |
825 | +static SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO, | |
826 | + show_temp_max_alarm, NULL, 5); | |
827 | + | |
828 | +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, | |
829 | + show_temp_crit_alarm, NULL, 0); | |
830 | +static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, | |
831 | + show_temp_crit_alarm, NULL, 1); | |
832 | +static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, | |
833 | + show_temp_crit_alarm, NULL, 2); | |
834 | +static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, | |
835 | + show_temp_crit_alarm, NULL, 3); | |
836 | +static SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO, | |
837 | + show_temp_crit_alarm, NULL, 4); | |
838 | +static SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO, | |
839 | + show_temp_crit_alarm, NULL, 5); | |
840 | + | |
841 | +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0); | |
842 | +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1); | |
843 | +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2); | |
844 | +static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3); | |
845 | +static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4); | |
846 | +static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5); | |
847 | + | |
848 | +static struct attribute *pc87427_attributes_temp[6][10] = { | |
849 | + { | |
850 | + &sensor_dev_attr_temp1_input.dev_attr.attr, | |
851 | + &sensor_dev_attr_temp1_min.dev_attr.attr, | |
852 | + &sensor_dev_attr_temp1_max.dev_attr.attr, | |
853 | + &sensor_dev_attr_temp1_crit.dev_attr.attr, | |
854 | + &sensor_dev_attr_temp1_type.dev_attr.attr, | |
855 | + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, | |
856 | + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | |
857 | + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, | |
858 | + &sensor_dev_attr_temp1_fault.dev_attr.attr, | |
859 | + NULL | |
860 | + }, { | |
861 | + &sensor_dev_attr_temp2_input.dev_attr.attr, | |
862 | + &sensor_dev_attr_temp2_min.dev_attr.attr, | |
863 | + &sensor_dev_attr_temp2_max.dev_attr.attr, | |
864 | + &sensor_dev_attr_temp2_crit.dev_attr.attr, | |
865 | + &sensor_dev_attr_temp2_type.dev_attr.attr, | |
866 | + &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, | |
867 | + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, | |
868 | + &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, | |
869 | + &sensor_dev_attr_temp2_fault.dev_attr.attr, | |
870 | + NULL | |
871 | + }, { | |
872 | + &sensor_dev_attr_temp3_input.dev_attr.attr, | |
873 | + &sensor_dev_attr_temp3_min.dev_attr.attr, | |
874 | + &sensor_dev_attr_temp3_max.dev_attr.attr, | |
875 | + &sensor_dev_attr_temp3_crit.dev_attr.attr, | |
876 | + &sensor_dev_attr_temp3_type.dev_attr.attr, | |
877 | + &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, | |
878 | + &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, | |
879 | + &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, | |
880 | + &sensor_dev_attr_temp3_fault.dev_attr.attr, | |
881 | + NULL | |
882 | + }, { | |
883 | + &sensor_dev_attr_temp4_input.dev_attr.attr, | |
884 | + &sensor_dev_attr_temp4_min.dev_attr.attr, | |
885 | + &sensor_dev_attr_temp4_max.dev_attr.attr, | |
886 | + &sensor_dev_attr_temp4_crit.dev_attr.attr, | |
887 | + &sensor_dev_attr_temp4_type.dev_attr.attr, | |
888 | + &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, | |
889 | + &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, | |
890 | + &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, | |
891 | + &sensor_dev_attr_temp4_fault.dev_attr.attr, | |
892 | + NULL | |
893 | + }, { | |
894 | + &sensor_dev_attr_temp5_input.dev_attr.attr, | |
895 | + &sensor_dev_attr_temp5_min.dev_attr.attr, | |
896 | + &sensor_dev_attr_temp5_max.dev_attr.attr, | |
897 | + &sensor_dev_attr_temp5_crit.dev_attr.attr, | |
898 | + &sensor_dev_attr_temp5_type.dev_attr.attr, | |
899 | + &sensor_dev_attr_temp5_min_alarm.dev_attr.attr, | |
900 | + &sensor_dev_attr_temp5_max_alarm.dev_attr.attr, | |
901 | + &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr, | |
902 | + &sensor_dev_attr_temp5_fault.dev_attr.attr, | |
903 | + NULL | |
904 | + }, { | |
905 | + &sensor_dev_attr_temp6_input.dev_attr.attr, | |
906 | + &sensor_dev_attr_temp6_min.dev_attr.attr, | |
907 | + &sensor_dev_attr_temp6_max.dev_attr.attr, | |
908 | + &sensor_dev_attr_temp6_crit.dev_attr.attr, | |
909 | + &sensor_dev_attr_temp6_type.dev_attr.attr, | |
910 | + &sensor_dev_attr_temp6_min_alarm.dev_attr.attr, | |
911 | + &sensor_dev_attr_temp6_max_alarm.dev_attr.attr, | |
912 | + &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr, | |
913 | + &sensor_dev_attr_temp6_fault.dev_attr.attr, | |
914 | + NULL | |
915 | + } | |
916 | +}; | |
917 | + | |
918 | +static const struct attribute_group pc87427_group_temp[6] = { | |
919 | + { .attrs = pc87427_attributes_temp[0] }, | |
920 | + { .attrs = pc87427_attributes_temp[1] }, | |
921 | + { .attrs = pc87427_attributes_temp[2] }, | |
922 | + { .attrs = pc87427_attributes_temp[3] }, | |
923 | + { .attrs = pc87427_attributes_temp[4] }, | |
924 | + { .attrs = pc87427_attributes_temp[5] }, | |
925 | +}; | |
926 | + | |
598 | 927 | static ssize_t show_name(struct device *dev, struct device_attribute |
599 | 928 | *devattr, char *buf) |
600 | 929 | { |
... | ... | @@ -659,7 +988,7 @@ |
659 | 988 | /* The FMC module should be ready */ |
660 | 989 | reg = pc87427_read8(data, LD_FAN, PC87427_REG_BANK); |
661 | 990 | if (!(reg & 0x80)) |
662 | - dev_warn(dev, "FMC module not ready!\n"); | |
991 | + dev_warn(dev, "%s module not ready!\n", "FMC"); | |
663 | 992 | |
664 | 993 | /* Check which fans are enabled */ |
665 | 994 | for (i = 0; i < 8; i++) { |
... | ... | @@ -701,6 +1030,19 @@ |
701 | 1030 | data->pwm_auto_ok |= (1 << i); |
702 | 1031 | } |
703 | 1032 | } |
1033 | + | |
1034 | + /* The HMC module should be ready */ | |
1035 | + reg = pc87427_read8(data, LD_TEMP, PC87427_REG_BANK); | |
1036 | + if (!(reg & 0x80)) | |
1037 | + dev_warn(dev, "%s module not ready!\n", "HMC"); | |
1038 | + | |
1039 | + /* Check which temperature channels are enabled */ | |
1040 | + for (i = 0; i < 6; i++) { | |
1041 | + reg = pc87427_read8_bank(data, LD_TEMP, BANK_TM(i), | |
1042 | + PC87427_REG_TEMP_STATUS); | |
1043 | + if (reg & TEMP_STATUS_CHANEN) | |
1044 | + data->temp_enabled |= (1 << i); | |
1045 | + } | |
704 | 1046 | } |
705 | 1047 | |
706 | 1048 | static int __devinit pc87427_probe(struct platform_device *pdev) |
... | ... | @@ -749,6 +1091,14 @@ |
749 | 1091 | if (err) |
750 | 1092 | goto exit_remove_files; |
751 | 1093 | } |
1094 | + for (i = 0; i < 6; i++) { | |
1095 | + if (!(data->temp_enabled & (1 << i))) | |
1096 | + continue; | |
1097 | + err = sysfs_create_group(&pdev->dev.kobj, | |
1098 | + &pc87427_group_temp[i]); | |
1099 | + if (err) | |
1100 | + goto exit_remove_files; | |
1101 | + } | |
752 | 1102 | |
753 | 1103 | data->hwmon_dev = hwmon_device_register(&pdev->dev); |
754 | 1104 | if (IS_ERR(data->hwmon_dev)) { |
... | ... | @@ -770,6 +1120,11 @@ |
770 | 1120 | continue; |
771 | 1121 | sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_pwm[i]); |
772 | 1122 | } |
1123 | + for (i = 0; i < 6; i++) { | |
1124 | + if (!(data->temp_enabled & (1 << i))) | |
1125 | + continue; | |
1126 | + sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_temp[i]); | |
1127 | + } | |
773 | 1128 | exit_release_region: |
774 | 1129 | pc87427_release_regions(pdev, res_count); |
775 | 1130 | exit_kfree: |
... | ... | @@ -797,6 +1152,11 @@ |
797 | 1152 | if (!(data->pwm_enabled & (1 << i))) |
798 | 1153 | continue; |
799 | 1154 | sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_pwm[i]); |
1155 | + } | |
1156 | + for (i = 0; i < 6; i++) { | |
1157 | + if (!(data->temp_enabled & (1 << i))) | |
1158 | + continue; | |
1159 | + sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_temp[i]); | |
800 | 1160 | } |
801 | 1161 | platform_set_drvdata(pdev, NULL); |
802 | 1162 | kfree(data); |