diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/Kconfig | 24 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 2 | ||||
-rw-r--r-- | drivers/hwmon/abituguru3.c | 24 | ||||
-rw-r--r-- | drivers/hwmon/adt7475.c | 1221 | ||||
-rw-r--r-- | drivers/hwmon/applesmc.c | 5 | ||||
-rw-r--r-- | drivers/hwmon/hp_accel.c | 75 | ||||
-rw-r--r-- | drivers/hwmon/k8temp.c | 55 |
7 files changed, 1385 insertions, 21 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 4b33bc82cc2..b84bf066879 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -189,6 +189,16 @@ config SENSORS_ADT7473 | |||
189 | This driver can also be built as a module. If so, the module | 189 | This driver can also be built as a module. If so, the module |
190 | will be called adt7473. | 190 | will be called adt7473. |
191 | 191 | ||
192 | config SENSORS_ADT7475 | ||
193 | tristate "Analog Devices ADT7475" | ||
194 | depends on I2C && EXPERIMENTAL | ||
195 | help | ||
196 | If you say yes here you get support for the Analog Devices | ||
197 | ADT7475 hardware monitoring chips. | ||
198 | |||
199 | This driver can also be build as a module. If so, the module | ||
200 | will be called adt7475. | ||
201 | |||
192 | config SENSORS_K8TEMP | 202 | config SENSORS_K8TEMP |
193 | tristate "AMD Athlon64/FX or Opteron temperature sensor" | 203 | tristate "AMD Athlon64/FX or Opteron temperature sensor" |
194 | depends on X86 && PCI && EXPERIMENTAL | 204 | depends on X86 && PCI && EXPERIMENTAL |
@@ -861,6 +871,8 @@ config SENSORS_HDAPS | |||
861 | config SENSORS_LIS3LV02D | 871 | config SENSORS_LIS3LV02D |
862 | tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer" | 872 | tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer" |
863 | depends on ACPI && INPUT | 873 | depends on ACPI && INPUT |
874 | select NEW_LEDS | ||
875 | select LEDS_CLASS | ||
864 | default n | 876 | default n |
865 | help | 877 | help |
866 | This driver provides support for the LIS3LV02Dx accelerometer. In | 878 | This driver provides support for the LIS3LV02Dx accelerometer. In |
@@ -872,10 +884,16 @@ config SENSORS_LIS3LV02D | |||
872 | /sys/devices/platform/lis3lv02d. | 884 | /sys/devices/platform/lis3lv02d. |
873 | 885 | ||
874 | This driver also provides an absolute input class device, allowing | 886 | This driver also provides an absolute input class device, allowing |
875 | the laptop to act as a pinball machine-esque joystick. | 887 | the laptop to act as a pinball machine-esque joystick. On HP laptops, |
888 | if the led infrastructure is activated, support for a led indicating | ||
889 | disk protection will be provided as hp:red:hddprotection. | ||
876 | 890 | ||
877 | This driver can also be built as a module. If so, the module | 891 | This driver can also be built as modules. If so, the core module |
878 | will be called lis3lv02d. | 892 | will be called lis3lv02d and a specific module for HP laptops will be |
893 | called hp_accel. | ||
894 | |||
895 | Say Y here if you have an applicable laptop and want to experience | ||
896 | the awesome power of lis3lv02d. | ||
879 | 897 | ||
880 | config SENSORS_APPLESMC | 898 | config SENSORS_APPLESMC |
881 | tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" | 899 | tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 19cb1ace3eb..2e80f37f39e 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -28,6 +28,8 @@ obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o | |||
28 | obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o | 28 | obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o |
29 | obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o | 29 | obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o |
30 | obj-$(CONFIG_SENSORS_ADT7473) += adt7473.o | 30 | obj-$(CONFIG_SENSORS_ADT7473) += adt7473.o |
31 | obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o | ||
32 | |||
31 | obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o | 33 | obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o |
32 | obj-$(CONFIG_SENSORS_AMS) += ams/ | 34 | obj-$(CONFIG_SENSORS_AMS) += ams/ |
33 | obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o | 35 | obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o |
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index 70bb854086d..e52b38806d0 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c | |||
@@ -279,7 +279,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { | |||
279 | { "OTES1 Fan", 36, 2, 60, 1, 0 }, | 279 | { "OTES1 Fan", 36, 2, 60, 1, 0 }, |
280 | { NULL, 0, 0, 0, 0, 0 } } | 280 | { NULL, 0, 0, 0, 0, 0 } } |
281 | }, | 281 | }, |
282 | { 0x0011, "AT8 32X(ATI RD580-ULI M1575)", { | 282 | { 0x0011, "AT8 32X", { |
283 | { "CPU Core", 0, 0, 10, 1, 0 }, | 283 | { "CPU Core", 0, 0, 10, 1, 0 }, |
284 | { "DDR", 1, 0, 20, 1, 0 }, | 284 | { "DDR", 1, 0, 20, 1, 0 }, |
285 | { "DDR VTT", 2, 0, 10, 1, 0 }, | 285 | { "DDR VTT", 2, 0, 10, 1, 0 }, |
@@ -402,7 +402,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { | |||
402 | { "AUX3 Fan", 36, 2, 60, 1, 0 }, | 402 | { "AUX3 Fan", 36, 2, 60, 1, 0 }, |
403 | { NULL, 0, 0, 0, 0, 0 } } | 403 | { NULL, 0, 0, 0, 0, 0 } } |
404 | }, | 404 | }, |
405 | { 0x0016, "AW9D-MAX (Intel i975-ICH7)", { | 405 | { 0x0016, "AW9D-MAX", { |
406 | { "CPU Core", 0, 0, 10, 1, 0 }, | 406 | { "CPU Core", 0, 0, 10, 1, 0 }, |
407 | { "DDR2", 1, 0, 20, 1, 0 }, | 407 | { "DDR2", 1, 0, 20, 1, 0 }, |
408 | { "DDR2 VTT", 2, 0, 10, 1, 0 }, | 408 | { "DDR2 VTT", 2, 0, 10, 1, 0 }, |
@@ -482,7 +482,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { | |||
482 | { "AUX3 Fan", 36, 2, 60, 1, 0 }, | 482 | { "AUX3 Fan", 36, 2, 60, 1, 0 }, |
483 | { NULL, 0, 0, 0, 0, 0 } } | 483 | { NULL, 0, 0, 0, 0, 0 } } |
484 | }, | 484 | }, |
485 | { 0x0019, NULL /* Unknown, need DMI string */, { | 485 | { 0x0019, "IN9 32X MAX", { |
486 | { "CPU Core", 7, 0, 10, 1, 0 }, | 486 | { "CPU Core", 7, 0, 10, 1, 0 }, |
487 | { "DDR2", 13, 0, 20, 1, 0 }, | 487 | { "DDR2", 13, 0, 20, 1, 0 }, |
488 | { "DDR2 VTT", 14, 0, 10, 1, 0 }, | 488 | { "DDR2 VTT", 14, 0, 10, 1, 0 }, |
@@ -509,7 +509,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { | |||
509 | { "AUX3 FAN", 36, 2, 60, 1, 0 }, | 509 | { "AUX3 FAN", 36, 2, 60, 1, 0 }, |
510 | { NULL, 0, 0, 0, 0, 0 } } | 510 | { NULL, 0, 0, 0, 0, 0 } } |
511 | }, | 511 | }, |
512 | { 0x001A, "IP35 Pro(Intel P35-ICH9R)", { | 512 | { 0x001A, "IP35 Pro", { |
513 | { "CPU Core", 0, 0, 10, 1, 0 }, | 513 | { "CPU Core", 0, 0, 10, 1, 0 }, |
514 | { "DDR2", 1, 0, 20, 1, 0 }, | 514 | { "DDR2", 1, 0, 20, 1, 0 }, |
515 | { "DDR2 VTT", 2, 0, 10, 1, 0 }, | 515 | { "DDR2 VTT", 2, 0, 10, 1, 0 }, |
@@ -1128,6 +1128,7 @@ static int __init abituguru3_dmi_detect(void) | |||
1128 | { | 1128 | { |
1129 | const char *board_vendor, *board_name; | 1129 | const char *board_vendor, *board_name; |
1130 | int i, err = (force) ? 1 : -ENODEV; | 1130 | int i, err = (force) ? 1 : -ENODEV; |
1131 | size_t sublen; | ||
1131 | 1132 | ||
1132 | board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); | 1133 | board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); |
1133 | if (!board_vendor || strcmp(board_vendor, "http://www.abit.com.tw/")) | 1134 | if (!board_vendor || strcmp(board_vendor, "http://www.abit.com.tw/")) |
@@ -1137,9 +1138,20 @@ static int __init abituguru3_dmi_detect(void) | |||
1137 | if (!board_name) | 1138 | if (!board_name) |
1138 | return err; | 1139 | return err; |
1139 | 1140 | ||
1141 | /* At the moment, we don't care about the part of the vendor | ||
1142 | * DMI string contained in brackets. Truncate the string at | ||
1143 | * the first occurrence of a bracket. Trim any trailing space | ||
1144 | * from the substring. | ||
1145 | */ | ||
1146 | sublen = strcspn(board_name, "("); | ||
1147 | while (sublen > 0 && board_name[sublen - 1] == ' ') | ||
1148 | sublen--; | ||
1149 | |||
1140 | for (i = 0; abituguru3_motherboards[i].id; i++) { | 1150 | for (i = 0; abituguru3_motherboards[i].id; i++) { |
1141 | const char *dmi_name = abituguru3_motherboards[i].dmi_name; | 1151 | const char *dmi_name = abituguru3_motherboards[i].dmi_name; |
1142 | if (dmi_name && !strcmp(dmi_name, board_name)) | 1152 | if (!dmi_name || strlen(dmi_name) != sublen) |
1153 | continue; | ||
1154 | if (!strncasecmp(board_name, dmi_name, sublen)) | ||
1143 | break; | 1155 | break; |
1144 | } | 1156 | } |
1145 | 1157 | ||
@@ -1153,7 +1165,7 @@ static int __init abituguru3_dmi_detect(void) | |||
1153 | 1165 | ||
1154 | static inline int abituguru3_dmi_detect(void) | 1166 | static inline int abituguru3_dmi_detect(void) |
1155 | { | 1167 | { |
1156 | return -ENODEV; | 1168 | return 1; |
1157 | } | 1169 | } |
1158 | 1170 | ||
1159 | #endif /* CONFIG_DMI */ | 1171 | #endif /* CONFIG_DMI */ |
diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c new file mode 100644 index 00000000000..d39877a7da6 --- /dev/null +++ b/drivers/hwmon/adt7475.c | |||
@@ -0,0 +1,1221 @@ | |||
1 | /* | ||
2 | * adt7475 - Thermal sensor driver for the ADT7475 chip and derivatives | ||
3 | * Copyright (C) 2007-2008, Advanced Micro Devices, Inc. | ||
4 | * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net> | ||
5 | * Copyright (C) 2008 Hans de Goede <hdegoede@redhat.com> | ||
6 | |||
7 | * Derived from the lm83 driver by Jean Delvare | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/hwmon.h> | ||
19 | #include <linux/hwmon-sysfs.h> | ||
20 | #include <linux/err.h> | ||
21 | |||
22 | /* Indexes for the sysfs hooks */ | ||
23 | |||
24 | #define INPUT 0 | ||
25 | #define MIN 1 | ||
26 | #define MAX 2 | ||
27 | #define CONTROL 3 | ||
28 | #define OFFSET 3 | ||
29 | #define AUTOMIN 4 | ||
30 | #define THERM 5 | ||
31 | #define HYSTERSIS 6 | ||
32 | |||
33 | /* These are unique identifiers for the sysfs functions - unlike the | ||
34 | numbers above, these are not also indexes into an array | ||
35 | */ | ||
36 | |||
37 | #define ALARM 9 | ||
38 | #define FAULT 10 | ||
39 | |||
40 | /* 7475 Common Registers */ | ||
41 | |||
42 | #define REG_VOLTAGE_BASE 0x21 | ||
43 | #define REG_TEMP_BASE 0x25 | ||
44 | #define REG_TACH_BASE 0x28 | ||
45 | #define REG_PWM_BASE 0x30 | ||
46 | #define REG_PWM_MAX_BASE 0x38 | ||
47 | |||
48 | #define REG_DEVID 0x3D | ||
49 | #define REG_VENDID 0x3E | ||
50 | |||
51 | #define REG_STATUS1 0x41 | ||
52 | #define REG_STATUS2 0x42 | ||
53 | |||
54 | #define REG_VOLTAGE_MIN_BASE 0x46 | ||
55 | #define REG_VOLTAGE_MAX_BASE 0x47 | ||
56 | |||
57 | #define REG_TEMP_MIN_BASE 0x4E | ||
58 | #define REG_TEMP_MAX_BASE 0x4F | ||
59 | |||
60 | #define REG_TACH_MIN_BASE 0x54 | ||
61 | |||
62 | #define REG_PWM_CONFIG_BASE 0x5C | ||
63 | |||
64 | #define REG_TEMP_TRANGE_BASE 0x5F | ||
65 | |||
66 | #define REG_PWM_MIN_BASE 0x64 | ||
67 | |||
68 | #define REG_TEMP_TMIN_BASE 0x67 | ||
69 | #define REG_TEMP_THERM_BASE 0x6A | ||
70 | |||
71 | #define REG_REMOTE1_HYSTERSIS 0x6D | ||
72 | #define REG_REMOTE2_HYSTERSIS 0x6E | ||
73 | |||
74 | #define REG_TEMP_OFFSET_BASE 0x70 | ||
75 | |||
76 | #define REG_EXTEND1 0x76 | ||
77 | #define REG_EXTEND2 0x77 | ||
78 | #define REG_CONFIG5 0x7C | ||
79 | |||
80 | #define CONFIG5_TWOSCOMP 0x01 | ||
81 | #define CONFIG5_TEMPOFFSET 0x02 | ||
82 | |||
83 | /* ADT7475 Settings */ | ||
84 | |||
85 | #define ADT7475_VOLTAGE_COUNT 2 | ||
86 | #define ADT7475_TEMP_COUNT 3 | ||
87 | #define ADT7475_TACH_COUNT 4 | ||
88 | #define ADT7475_PWM_COUNT 3 | ||
89 | |||
90 | /* Macro to read the registers */ | ||
91 | |||
92 | #define adt7475_read(reg) i2c_smbus_read_byte_data(client, (reg)) | ||
93 | |||
94 | /* Macros to easily index the registers */ | ||
95 | |||
96 | #define TACH_REG(idx) (REG_TACH_BASE + ((idx) * 2)) | ||
97 | #define TACH_MIN_REG(idx) (REG_TACH_MIN_BASE + ((idx) * 2)) | ||
98 | |||
99 | #define PWM_REG(idx) (REG_PWM_BASE + (idx)) | ||
100 | #define PWM_MAX_REG(idx) (REG_PWM_MAX_BASE + (idx)) | ||
101 | #define PWM_MIN_REG(idx) (REG_PWM_MIN_BASE + (idx)) | ||
102 | #define PWM_CONFIG_REG(idx) (REG_PWM_CONFIG_BASE + (idx)) | ||
103 | |||
104 | #define VOLTAGE_REG(idx) (REG_VOLTAGE_BASE + (idx)) | ||
105 | #define VOLTAGE_MIN_REG(idx) (REG_VOLTAGE_MIN_BASE + ((idx) * 2)) | ||
106 | #define VOLTAGE_MAX_REG(idx) (REG_VOLTAGE_MAX_BASE + ((idx) * 2)) | ||
107 | |||
108 | #define TEMP_REG(idx) (REG_TEMP_BASE + (idx)) | ||
109 | #define TEMP_MIN_REG(idx) (REG_TEMP_MIN_BASE + ((idx) * 2)) | ||
110 | #define TEMP_MAX_REG(idx) (REG_TEMP_MAX_BASE + ((idx) * 2)) | ||
111 | #define TEMP_TMIN_REG(idx) (REG_TEMP_TMIN_BASE + (idx)) | ||
112 | #define TEMP_THERM_REG(idx) (REG_TEMP_THERM_BASE + (idx)) | ||
113 | #define TEMP_OFFSET_REG(idx) (REG_TEMP_OFFSET_BASE + (idx)) | ||
114 | #define TEMP_TRANGE_REG(idx) (REG_TEMP_TRANGE_BASE + (idx)) | ||
115 | |||
116 | static unsigned short normal_i2c[] = { 0x2e, I2C_CLIENT_END }; | ||
117 | |||
118 | I2C_CLIENT_INSMOD_1(adt7475); | ||
119 | |||
120 | static const struct i2c_device_id adt7475_id[] = { | ||
121 | { "adt7475", adt7475 }, | ||
122 | { } | ||
123 | }; | ||
124 | MODULE_DEVICE_TABLE(i2c, adt7475_id); | ||
125 | |||
126 | struct adt7475_data { | ||
127 | struct device *hwmon_dev; | ||
128 | struct mutex lock; | ||
129 | |||
130 | unsigned long measure_updated; | ||
131 | unsigned long limits_updated; | ||
132 | char valid; | ||
133 | |||
134 | u8 config5; | ||
135 | u16 alarms; | ||
136 | u16 voltage[3][3]; | ||
137 | u16 temp[7][3]; | ||
138 | u16 tach[2][4]; | ||
139 | u8 pwm[4][3]; | ||
140 | u8 range[3]; | ||
141 | u8 pwmctl[3]; | ||
142 | u8 pwmchan[3]; | ||
143 | }; | ||
144 | |||
145 | static struct i2c_driver adt7475_driver; | ||
146 | static struct adt7475_data *adt7475_update_device(struct device *dev); | ||
147 | static void adt7475_read_hystersis(struct i2c_client *client); | ||
148 | static void adt7475_read_pwm(struct i2c_client *client, int index); | ||
149 | |||
150 | /* Given a temp value, convert it to register value */ | ||
151 | |||
152 | static inline u16 temp2reg(struct adt7475_data *data, long val) | ||
153 | { | ||
154 | u16 ret; | ||
155 | |||
156 | if (!(data->config5 & CONFIG5_TWOSCOMP)) { | ||
157 | val = SENSORS_LIMIT(val, -64000, 191000); | ||
158 | ret = (val + 64500) / 1000; | ||
159 | } else { | ||
160 | val = SENSORS_LIMIT(val, -128000, 127000); | ||
161 | if (val < -500) | ||
162 | ret = (256500 + val) / 1000; | ||
163 | else | ||
164 | ret = (val + 500) / 1000; | ||
165 | } | ||
166 | |||
167 | return ret << 2; | ||
168 | } | ||
169 | |||
170 | /* Given a register value, convert it to a real temp value */ | ||
171 | |||
172 | static inline int reg2temp(struct adt7475_data *data, u16 reg) | ||
173 | { | ||
174 | if (data->config5 & CONFIG5_TWOSCOMP) { | ||
175 | if (reg >= 512) | ||
176 | return (reg - 1024) * 250; | ||
177 | else | ||
178 | return reg * 250; | ||
179 | } else | ||
180 | return (reg - 256) * 250; | ||
181 | } | ||
182 | |||
183 | static inline int tach2rpm(u16 tach) | ||
184 | { | ||
185 | if (tach == 0 || tach == 0xFFFF) | ||
186 | return 0; | ||
187 | |||
188 | return (90000 * 60) / tach; | ||
189 | } | ||
190 | |||
191 | static inline u16 rpm2tach(unsigned long rpm) | ||
192 | { | ||
193 | if (rpm == 0) | ||
194 | return 0; | ||
195 | |||
196 | return SENSORS_LIMIT((90000 * 60) / rpm, 1, 0xFFFF); | ||
197 | } | ||
198 | |||
199 | static inline int reg2vcc(u16 reg) | ||
200 | { | ||
201 | return (4296 * reg) / 1000; | ||
202 | } | ||
203 | |||
204 | static inline int reg2vccp(u16 reg) | ||
205 | { | ||
206 | return (2929 * reg) / 1000; | ||
207 | } | ||
208 | |||
209 | static inline u16 vcc2reg(long vcc) | ||
210 | { | ||
211 | vcc = SENSORS_LIMIT(vcc, 0, 4396); | ||
212 | return (vcc * 1000) / 4296; | ||
213 | } | ||
214 | |||
215 | static inline u16 vccp2reg(long vcc) | ||
216 | { | ||
217 | vcc = SENSORS_LIMIT(vcc, 0, 2998); | ||
218 | return (vcc * 1000) / 2929; | ||
219 | } | ||
220 | |||
221 | static u16 adt7475_read_word(struct i2c_client *client, int reg) | ||
222 | { | ||
223 | u16 val; | ||
224 | |||
225 | val = i2c_smbus_read_byte_data(client, reg); | ||
226 | val |= (i2c_smbus_read_byte_data(client, reg + 1) << 8); | ||
227 | |||
228 | return val; | ||
229 | } | ||
230 | |||
231 | static void adt7475_write_word(struct i2c_client *client, int reg, u16 val) | ||
232 | { | ||
233 | i2c_smbus_write_byte_data(client, reg + 1, val >> 8); | ||
234 | i2c_smbus_write_byte_data(client, reg, val & 0xFF); | ||
235 | } | ||
236 | |||
237 | /* Find the nearest value in a table - used for pwm frequency and | ||
238 | auto temp range */ | ||
239 | static int find_nearest(long val, const int *array, int size) | ||
240 | { | ||
241 | int i; | ||
242 | |||
243 | if (val < array[0]) | ||
244 | return 0; | ||
245 | |||
246 | if (val > array[size - 1]) | ||
247 | return size - 1; | ||
248 | |||
249 | for (i = 0; i < size - 1; i++) { | ||
250 | int a, b; | ||
251 | |||
252 | if (val > array[i + 1]) | ||
253 | continue; | ||
254 | |||
255 | a = val - array[i]; | ||
256 | b = array[i + 1] - val; | ||
257 | |||
258 | return (a <= b) ? i : i + 1; | ||
259 | } | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static ssize_t show_voltage(struct device *dev, struct device_attribute *attr, | ||
265 | char *buf) | ||
266 | { | ||
267 | struct adt7475_data *data = adt7475_update_device(dev); | ||
268 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
269 | unsigned short val; | ||
270 | |||
271 | switch (sattr->nr) { | ||
272 | case ALARM: | ||
273 | return sprintf(buf, "%d\n", | ||
274 | (data->alarms >> (sattr->index + 1)) & 1); | ||
275 | default: | ||
276 | val = data->voltage[sattr->nr][sattr->index]; | ||
277 | return sprintf(buf, "%d\n", | ||
278 | sattr->index == | ||
279 | 0 ? reg2vccp(val) : reg2vcc(val)); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | static ssize_t set_voltage(struct device *dev, struct device_attribute *attr, | ||
284 | const char *buf, size_t count) | ||
285 | { | ||
286 | |||
287 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
288 | struct i2c_client *client = to_i2c_client(dev); | ||
289 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
290 | unsigned char reg; | ||
291 | long val; | ||
292 | |||
293 | if (strict_strtol(buf, 10, &val)) | ||
294 | return -EINVAL; | ||
295 | |||
296 | mutex_lock(&data->lock); | ||
297 | |||
298 | data->voltage[sattr->nr][sattr->index] = | ||
299 | sattr->index ? vcc2reg(val) : vccp2reg(val); | ||
300 | |||
301 | if (sattr->nr == MIN) | ||
302 | reg = VOLTAGE_MIN_REG(sattr->index); | ||
303 | else | ||
304 | reg = VOLTAGE_MAX_REG(sattr->index); | ||
305 | |||
306 | i2c_smbus_write_byte_data(client, reg, | ||
307 | data->voltage[sattr->nr][sattr->index] >> 2); | ||
308 | mutex_unlock(&data->lock); | ||
309 | |||
310 | return count; | ||
311 | } | ||
312 | |||
313 | static ssize_t show_temp(struct device *dev, struct device_attribute *attr, | ||
314 | char *buf) | ||
315 | { | ||
316 | struct adt7475_data *data = adt7475_update_device(dev); | ||
317 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
318 | int out; | ||
319 | |||
320 | switch (sattr->nr) { | ||
321 | case HYSTERSIS: | ||
322 | mutex_lock(&data->lock); | ||
323 | out = data->temp[sattr->nr][sattr->index]; | ||
324 | if (sattr->index != 1) | ||
325 | out = (out >> 4) & 0xF; | ||
326 | else | ||
327 | out = (out & 0xF); | ||
328 | /* Show the value as an absolute number tied to | ||
329 | * THERM */ | ||
330 | out = reg2temp(data, data->temp[THERM][sattr->index]) - | ||
331 | out * 1000; | ||
332 | mutex_unlock(&data->lock); | ||
333 | break; | ||
334 | |||
335 | case OFFSET: | ||
336 | /* Offset is always 2's complement, regardless of the | ||
337 | * setting in CONFIG5 */ | ||
338 | mutex_lock(&data->lock); | ||
339 | out = (s8)data->temp[sattr->nr][sattr->index]; | ||
340 | if (data->config5 & CONFIG5_TEMPOFFSET) | ||
341 | out *= 1000; | ||
342 | else | ||
343 | out *= 500; | ||
344 | mutex_unlock(&data->lock); | ||
345 | break; | ||
346 | |||
347 | case ALARM: | ||
348 | out = (data->alarms >> (sattr->index + 4)) & 1; | ||
349 | break; | ||
350 | |||
351 | case FAULT: | ||
352 | /* Note - only for remote1 and remote2 */ | ||
353 | out = data->alarms & (sattr->index ? 0x8000 : 0x4000); | ||
354 | out = out ? 0 : 1; | ||
355 | break; | ||
356 | |||
357 | default: | ||
358 | /* All other temp values are in the configured format */ | ||
359 | out = reg2temp(data, data->temp[sattr->nr][sattr->index]); | ||
360 | } | ||
361 | |||
362 | return sprintf(buf, "%d\n", out); | ||
363 | } | ||
364 | |||
365 | static ssize_t set_temp(struct device *dev, struct device_attribute *attr, | ||
366 | const char *buf, size_t count) | ||
367 | { | ||
368 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
369 | struct i2c_client *client = to_i2c_client(dev); | ||
370 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
371 | unsigned char reg = 0; | ||
372 | u8 out; | ||
373 | int temp; | ||
374 | long val; | ||
375 | |||
376 | if (strict_strtol(buf, 10, &val)) | ||
377 | return -EINVAL; | ||
378 | |||
379 | mutex_lock(&data->lock); | ||
380 | |||
381 | /* We need the config register in all cases for temp <-> reg conv. */ | ||
382 | data->config5 = adt7475_read(REG_CONFIG5); | ||
383 | |||
384 | switch (sattr->nr) { | ||
385 | case OFFSET: | ||
386 | if (data->config5 & CONFIG5_TEMPOFFSET) { | ||
387 | val = SENSORS_LIMIT(val, -63000, 127000); | ||
388 | out = data->temp[OFFSET][sattr->index] = val / 1000; | ||
389 | } else { | ||
390 | val = SENSORS_LIMIT(val, -63000, 64000); | ||
391 | out = data->temp[OFFSET][sattr->index] = val / 500; | ||
392 | } | ||
393 | break; | ||
394 | |||
395 | case HYSTERSIS: | ||
396 | /* The value will be given as an absolute value, turn it | ||
397 | into an offset based on THERM */ | ||
398 | |||
399 | /* Read fresh THERM and HYSTERSIS values from the chip */ | ||
400 | data->temp[THERM][sattr->index] = | ||
401 | adt7475_read(TEMP_THERM_REG(sattr->index)) << 2; | ||
402 | adt7475_read_hystersis(client); | ||
403 | |||
404 | temp = reg2temp(data, data->temp[THERM][sattr->index]); | ||
405 | val = SENSORS_LIMIT(val, temp - 15000, temp); | ||
406 | val = (temp - val) / 1000; | ||
407 | |||
408 | if (sattr->index != 1) { | ||
409 | data->temp[HYSTERSIS][sattr->index] &= 0xF0; | ||
410 | data->temp[HYSTERSIS][sattr->index] |= (val & 0xF) << 4; | ||
411 | } else { | ||
412 | data->temp[HYSTERSIS][sattr->index] &= 0x0F; | ||
413 | data->temp[HYSTERSIS][sattr->index] |= (val & 0xF); | ||
414 | } | ||
415 | |||
416 | out = data->temp[HYSTERSIS][sattr->index]; | ||
417 | break; | ||
418 | |||
419 | default: | ||
420 | data->temp[sattr->nr][sattr->index] = temp2reg(data, val); | ||
421 | |||
422 | /* We maintain an extra 2 digits of precision for simplicity | ||
423 | * - shift those back off before writing the value */ | ||
424 | out = (u8) (data->temp[sattr->nr][sattr->index] >> 2); | ||
425 | } | ||
426 | |||
427 | switch (sattr->nr) { | ||
428 | case MIN: | ||
429 | reg = TEMP_MIN_REG(sattr->index); | ||
430 | break; | ||
431 | case MAX: | ||
432 | reg = TEMP_MAX_REG(sattr->index); | ||
433 | break; | ||
434 | case OFFSET: | ||
435 | reg = TEMP_OFFSET_REG(sattr->index); | ||
436 | break; | ||
437 | case AUTOMIN: | ||
438 | reg = TEMP_TMIN_REG(sattr->index); | ||
439 | break; | ||
440 | case THERM: | ||
441 | reg = TEMP_THERM_REG(sattr->index); | ||
442 | break; | ||
443 | case HYSTERSIS: | ||
444 | if (sattr->index != 2) | ||
445 | reg = REG_REMOTE1_HYSTERSIS; | ||
446 | else | ||
447 | reg = REG_REMOTE2_HYSTERSIS; | ||
448 | |||
449 | break; | ||
450 | } | ||
451 | |||
452 | i2c_smbus_write_byte_data(client, reg, out); | ||
453 | |||
454 | mutex_unlock(&data->lock); | ||
455 | return count; | ||
456 | } | ||
457 | |||
458 | /* Table of autorange values - the user will write the value in millidegrees, | ||
459 | and we'll convert it */ | ||
460 | static const int autorange_table[] = { | ||
461 | 2000, 2500, 3330, 4000, 5000, 6670, 8000, | ||
462 | 10000, 13330, 16000, 20000, 26670, 32000, 40000, | ||
463 | 53330, 80000 | ||
464 | }; | ||
465 | |||
466 | static ssize_t show_point2(struct device *dev, struct device_attribute *attr, | ||
467 | char *buf) | ||
468 | { | ||
469 | struct adt7475_data *data = adt7475_update_device(dev); | ||
470 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
471 | int out, val; | ||
472 | |||
473 | mutex_lock(&data->lock); | ||
474 | out = (data->range[sattr->index] >> 4) & 0x0F; | ||
475 | val = reg2temp(data, data->temp[AUTOMIN][sattr->index]); | ||
476 | mutex_unlock(&data->lock); | ||
477 | |||
478 | return sprintf(buf, "%d\n", val + autorange_table[out]); | ||
479 | } | ||
480 | |||
481 | static ssize_t set_point2(struct device *dev, struct device_attribute *attr, | ||
482 | const char *buf, size_t count) | ||
483 | { | ||
484 | struct i2c_client *client = to_i2c_client(dev); | ||
485 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
486 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
487 | int temp; | ||
488 | long val; | ||
489 | |||
490 | if (strict_strtol(buf, 10, &val)) | ||
491 | return -EINVAL; | ||
492 | |||
493 | mutex_lock(&data->lock); | ||
494 | |||
495 | /* Get a fresh copy of the needed registers */ | ||
496 | data->config5 = adt7475_read(REG_CONFIG5); | ||
497 | data->temp[AUTOMIN][sattr->index] = | ||
498 | adt7475_read(TEMP_TMIN_REG(sattr->index)) << 2; | ||
499 | data->range[sattr->index] = | ||
500 | adt7475_read(TEMP_TRANGE_REG(sattr->index)); | ||
501 | |||
502 | /* The user will write an absolute value, so subtract the start point | ||
503 | to figure the range */ | ||
504 | temp = reg2temp(data, data->temp[AUTOMIN][sattr->index]); | ||
505 | val = SENSORS_LIMIT(val, temp + autorange_table[0], | ||
506 | temp + autorange_table[ARRAY_SIZE(autorange_table) - 1]); | ||
507 | val -= temp; | ||
508 | |||
509 | /* Find the nearest table entry to what the user wrote */ | ||
510 | val = find_nearest(val, autorange_table, ARRAY_SIZE(autorange_table)); | ||
511 | |||
512 | data->range[sattr->index] &= ~0xF0; | ||
513 | data->range[sattr->index] |= val << 4; | ||
514 | |||
515 | i2c_smbus_write_byte_data(client, TEMP_TRANGE_REG(sattr->index), | ||
516 | data->range[sattr->index]); | ||
517 | |||
518 | mutex_unlock(&data->lock); | ||
519 | return count; | ||
520 | } | ||
521 | |||
522 | static ssize_t show_tach(struct device *dev, struct device_attribute *attr, | ||
523 | char *buf) | ||
524 | { | ||
525 | struct adt7475_data *data = adt7475_update_device(dev); | ||
526 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
527 | int out; | ||
528 | |||
529 | if (sattr->nr == ALARM) | ||
530 | out = (data->alarms >> (sattr->index + 10)) & 1; | ||
531 | else | ||
532 | out = tach2rpm(data->tach[sattr->nr][sattr->index]); | ||
533 | |||
534 | return sprintf(buf, "%d\n", out); | ||
535 | } | ||
536 | |||
537 | static ssize_t set_tach(struct device *dev, struct device_attribute *attr, | ||
538 | const char *buf, size_t count) | ||
539 | { | ||
540 | |||
541 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
542 | struct i2c_client *client = to_i2c_client(dev); | ||
543 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
544 | unsigned long val; | ||
545 | |||
546 | if (strict_strtoul(buf, 10, &val)) | ||
547 | return -EINVAL; | ||
548 | |||
549 | mutex_lock(&data->lock); | ||
550 | |||
551 | data->tach[MIN][sattr->index] = rpm2tach(val); | ||
552 | |||
553 | adt7475_write_word(client, TACH_MIN_REG(sattr->index), | ||
554 | data->tach[MIN][sattr->index]); | ||
555 | |||
556 | mutex_unlock(&data->lock); | ||
557 | return count; | ||
558 | } | ||
559 | |||
560 | static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, | ||
561 | char *buf) | ||
562 | { | ||
563 | struct adt7475_data *data = adt7475_update_device(dev); | ||
564 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
565 | |||
566 | return sprintf(buf, "%d\n", data->pwm[sattr->nr][sattr->index]); | ||
567 | } | ||
568 | |||
569 | static ssize_t show_pwmchan(struct device *dev, struct device_attribute *attr, | ||
570 | char *buf) | ||
571 | { | ||
572 | struct adt7475_data *data = adt7475_update_device(dev); | ||
573 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
574 | |||
575 | return sprintf(buf, "%d\n", data->pwmchan[sattr->index]); | ||
576 | } | ||
577 | |||
578 | static ssize_t show_pwmctrl(struct device *dev, struct device_attribute *attr, | ||
579 | char *buf) | ||
580 | { | ||
581 | struct adt7475_data *data = adt7475_update_device(dev); | ||
582 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
583 | |||
584 | return sprintf(buf, "%d\n", data->pwmctl[sattr->index]); | ||
585 | } | ||
586 | |||
587 | static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, | ||
588 | const char *buf, size_t count) | ||
589 | { | ||
590 | |||
591 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
592 | struct i2c_client *client = to_i2c_client(dev); | ||
593 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
594 | unsigned char reg = 0; | ||
595 | long val; | ||
596 | |||
597 | if (strict_strtol(buf, 10, &val)) | ||
598 | return -EINVAL; | ||
599 | |||
600 | mutex_lock(&data->lock); | ||
601 | |||
602 | switch (sattr->nr) { | ||
603 | case INPUT: | ||
604 | /* Get a fresh value for CONTROL */ | ||
605 | data->pwm[CONTROL][sattr->index] = | ||
606 | adt7475_read(PWM_CONFIG_REG(sattr->index)); | ||
607 | |||
608 | /* If we are not in manual mode, then we shouldn't allow | ||
609 | * the user to set the pwm speed */ | ||
610 | if (((data->pwm[CONTROL][sattr->index] >> 5) & 7) != 7) { | ||
611 | mutex_unlock(&data->lock); | ||
612 | return count; | ||
613 | } | ||
614 | |||
615 | reg = PWM_REG(sattr->index); | ||
616 | break; | ||
617 | |||
618 | case MIN: | ||
619 | reg = PWM_MIN_REG(sattr->index); | ||
620 | break; | ||
621 | |||
622 | case MAX: | ||
623 | reg = PWM_MAX_REG(sattr->index); | ||
624 | break; | ||
625 | } | ||
626 | |||
627 | data->pwm[sattr->nr][sattr->index] = SENSORS_LIMIT(val, 0, 0xFF); | ||
628 | i2c_smbus_write_byte_data(client, reg, | ||
629 | data->pwm[sattr->nr][sattr->index]); | ||
630 | |||
631 | mutex_unlock(&data->lock); | ||
632 | |||
633 | return count; | ||
634 | } | ||
635 | |||
636 | /* Called by set_pwmctrl and set_pwmchan */ | ||
637 | |||
638 | static int hw_set_pwm(struct i2c_client *client, int index, | ||
639 | unsigned int pwmctl, unsigned int pwmchan) | ||
640 | { | ||
641 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
642 | long val = 0; | ||
643 | |||
644 | switch (pwmctl) { | ||
645 | case 0: | ||
646 | val = 0x03; /* Run at full speed */ | ||
647 | break; | ||
648 | case 1: | ||
649 | val = 0x07; /* Manual mode */ | ||
650 | break; | ||
651 | case 2: | ||
652 | switch (pwmchan) { | ||
653 | case 1: | ||
654 | /* Remote1 controls PWM */ | ||
655 | val = 0x00; | ||
656 | break; | ||
657 | case 2: | ||
658 | /* local controls PWM */ | ||
659 | val = 0x01; | ||
660 | break; | ||
661 | case 4: | ||
662 | /* remote2 controls PWM */ | ||
663 | val = 0x02; | ||
664 | break; | ||
665 | case 6: | ||
666 | /* local/remote2 control PWM */ | ||
667 | val = 0x05; | ||
668 | break; | ||
669 | case 7: | ||
670 | /* All three control PWM */ | ||
671 | val = 0x06; | ||
672 | break; | ||
673 | default: | ||
674 | return -EINVAL; | ||
675 | } | ||
676 | break; | ||
677 | default: | ||
678 | return -EINVAL; | ||
679 | } | ||
680 | |||
681 | data->pwmctl[index] = pwmctl; | ||
682 | data->pwmchan[index] = pwmchan; | ||
683 | |||
684 | data->pwm[CONTROL][index] &= ~0xE0; | ||
685 | data->pwm[CONTROL][index] |= (val & 7) << 5; | ||
686 | |||
687 | i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(index), | ||
688 | data->pwm[CONTROL][index]); | ||
689 | |||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | static ssize_t set_pwmchan(struct device *dev, struct device_attribute *attr, | ||
694 | const char *buf, size_t count) | ||
695 | { | ||
696 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
697 | struct i2c_client *client = to_i2c_client(dev); | ||
698 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
699 | int r; | ||
700 | long val; | ||
701 | |||
702 | if (strict_strtol(buf, 10, &val)) | ||
703 | return -EINVAL; | ||
704 | |||
705 | mutex_lock(&data->lock); | ||
706 | /* Read Modify Write PWM values */ | ||
707 | adt7475_read_pwm(client, sattr->index); | ||
708 | r = hw_set_pwm(client, sattr->index, data->pwmctl[sattr->index], val); | ||
709 | if (r) | ||
710 | count = r; | ||
711 | mutex_unlock(&data->lock); | ||
712 | |||
713 | return count; | ||
714 | } | ||
715 | |||
716 | static ssize_t set_pwmctrl(struct device *dev, struct device_attribute *attr, | ||
717 | const char *buf, size_t count) | ||
718 | { | ||
719 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
720 | struct i2c_client *client = to_i2c_client(dev); | ||
721 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
722 | int r; | ||
723 | long val; | ||
724 | |||
725 | if (strict_strtol(buf, 10, &val)) | ||
726 | return -EINVAL; | ||
727 | |||
728 | mutex_lock(&data->lock); | ||
729 | /* Read Modify Write PWM values */ | ||
730 | adt7475_read_pwm(client, sattr->index); | ||
731 | r = hw_set_pwm(client, sattr->index, val, data->pwmchan[sattr->index]); | ||
732 | if (r) | ||
733 | count = r; | ||
734 | mutex_unlock(&data->lock); | ||
735 | |||
736 | return count; | ||
737 | } | ||
738 | |||
739 | /* List of frequencies for the PWM */ | ||
740 | static const int pwmfreq_table[] = { | ||
741 | 11, 14, 22, 29, 35, 44, 58, 88 | ||
742 | }; | ||
743 | |||
744 | static ssize_t show_pwmfreq(struct device *dev, struct device_attribute *attr, | ||
745 | char *buf) | ||
746 | { | ||
747 | struct adt7475_data *data = adt7475_update_device(dev); | ||
748 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
749 | |||
750 | return sprintf(buf, "%d\n", | ||
751 | pwmfreq_table[data->range[sattr->index] & 7]); | ||
752 | } | ||
753 | |||
754 | static ssize_t set_pwmfreq(struct device *dev, struct device_attribute *attr, | ||
755 | const char *buf, size_t count) | ||
756 | { | ||
757 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
758 | struct i2c_client *client = to_i2c_client(dev); | ||
759 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
760 | int out; | ||
761 | long val; | ||
762 | |||
763 | if (strict_strtol(buf, 10, &val)) | ||
764 | return -EINVAL; | ||
765 | |||
766 | out = find_nearest(val, pwmfreq_table, ARRAY_SIZE(pwmfreq_table)); | ||
767 | |||
768 | mutex_lock(&data->lock); | ||
769 | |||
770 | data->range[sattr->index] = | ||
771 | adt7475_read(TEMP_TRANGE_REG(sattr->index)); | ||
772 | data->range[sattr->index] &= ~7; | ||
773 | data->range[sattr->index] |= out; | ||
774 | |||
775 | i2c_smbus_write_byte_data(client, TEMP_TRANGE_REG(sattr->index), | ||
776 | data->range[sattr->index]); | ||
777 | |||
778 | mutex_unlock(&data->lock); | ||
779 | return count; | ||
780 | } | ||
781 | |||
782 | static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_voltage, NULL, INPUT, 0); | ||
783 | static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_voltage, | ||
784 | set_voltage, MAX, 0); | ||
785 | static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_voltage, | ||
786 | set_voltage, MIN, 0); | ||
787 | static SENSOR_DEVICE_ATTR_2(in1_alarm, S_IRUGO, show_voltage, NULL, ALARM, 0); | ||
788 | static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_voltage, NULL, INPUT, 1); | ||
789 | static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_voltage, | ||
790 | set_voltage, MAX, 1); | ||
791 | static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_voltage, | ||
792 | set_voltage, MIN, 1); | ||
793 | static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, show_voltage, NULL, ALARM, 1); | ||
794 | static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, INPUT, 0); | ||
795 | static SENSOR_DEVICE_ATTR_2(temp1_alarm, S_IRUGO, show_temp, NULL, ALARM, 0); | ||
796 | static SENSOR_DEVICE_ATTR_2(temp1_fault, S_IRUGO, show_temp, NULL, FAULT, 0); | ||
797 | static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
798 | MAX, 0); | ||
799 | static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
800 | MIN, 0); | ||
801 | static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp, | ||
802 | set_temp, OFFSET, 0); | ||
803 | static SENSOR_DEVICE_ATTR_2(temp1_auto_point1_temp, S_IRUGO | S_IWUSR, | ||
804 | show_temp, set_temp, AUTOMIN, 0); | ||
805 | static SENSOR_DEVICE_ATTR_2(temp1_auto_point2_temp, S_IRUGO | S_IWUSR, | ||
806 | show_point2, set_point2, 0, 0); | ||
807 | static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
808 | THERM, 0); | ||
809 | static SENSOR_DEVICE_ATTR_2(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_temp, | ||
810 | set_temp, HYSTERSIS, 0); | ||
811 | static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, INPUT, 1); | ||
812 | static SENSOR_DEVICE_ATTR_2(temp2_alarm, S_IRUGO, show_temp, NULL, ALARM, 1); | ||
813 | static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
814 | MAX, 1); | ||
815 | static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
816 | MIN, 1); | ||
817 | static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp, | ||
818 | set_temp, OFFSET, 1); | ||
819 | static SENSOR_DEVICE_ATTR_2(temp2_auto_point1_temp, S_IRUGO | S_IWUSR, | ||
820 | show_temp, set_temp, AUTOMIN, 1); | ||
821 | static SENSOR_DEVICE_ATTR_2(temp2_auto_point2_temp, S_IRUGO | S_IWUSR, | ||
822 | show_point2, set_point2, 0, 1); | ||
823 | static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
824 | THERM, 1); | ||
825 | static SENSOR_DEVICE_ATTR_2(temp2_crit_hyst, S_IRUGO | S_IWUSR, show_temp, | ||
826 | set_temp, HYSTERSIS, 1); | ||
827 | static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, INPUT, 2); | ||
828 | static SENSOR_DEVICE_ATTR_2(temp3_alarm, S_IRUGO, show_temp, NULL, ALARM, 2); | ||
829 | static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_temp, NULL, FAULT, 2); | ||
830 | static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
831 | MAX, 2); | ||
832 | static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
833 | MIN, 2); | ||
834 | static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp, | ||
835 | set_temp, OFFSET, 2); | ||
836 | static SENSOR_DEVICE_ATTR_2(temp3_auto_point1_temp, S_IRUGO | S_IWUSR, | ||
837 | show_temp, set_temp, AUTOMIN, 2); | ||
838 | static SENSOR_DEVICE_ATTR_2(temp3_auto_point2_temp, S_IRUGO | S_IWUSR, | ||
839 | show_point2, set_point2, 0, 2); | ||
840 | static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, | ||
841 | THERM, 2); | ||
842 | static SENSOR_DEVICE_ATTR_2(temp3_crit_hyst, S_IRUGO | S_IWUSR, show_temp, | ||
843 | set_temp, HYSTERSIS, 2); | ||
844 | static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_tach, NULL, INPUT, 0); | ||
845 | static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_tach, set_tach, | ||
846 | MIN, 0); | ||
847 | static SENSOR_DEVICE_ATTR_2(fan1_alarm, S_IRUGO, show_tach, NULL, ALARM, 0); | ||
848 | static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_tach, NULL, INPUT, 1); | ||
849 | static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_tach, set_tach, | ||
850 | MIN, 1); | ||
851 | static SENSOR_DEVICE_ATTR_2(fan2_alarm, S_IRUGO, show_tach, NULL, ALARM, 1); | ||
852 | static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_tach, NULL, INPUT, 2); | ||
853 | static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_tach, set_tach, | ||
854 | MIN, 2); | ||
855 | static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_tach, NULL, ALARM, 2); | ||
856 | static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_tach, NULL, INPUT, 3); | ||
857 | static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_tach, set_tach, | ||
858 | MIN, 3); | ||
859 | static SENSOR_DEVICE_ATTR_2(fan4_alarm, S_IRUGO, show_tach, NULL, ALARM, 3); | ||
860 | static SENSOR_DEVICE_ATTR_2(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT, | ||
861 | 0); | ||
862 | static SENSOR_DEVICE_ATTR_2(pwm1_freq, S_IRUGO | S_IWUSR, show_pwmfreq, | ||
863 | set_pwmfreq, INPUT, 0); | ||
864 | static SENSOR_DEVICE_ATTR_2(pwm1_enable, S_IRUGO | S_IWUSR, show_pwmctrl, | ||
865 | set_pwmctrl, INPUT, 0); | ||
866 | static SENSOR_DEVICE_ATTR_2(pwm1_auto_channel_temp, S_IRUGO | S_IWUSR, | ||
867 | show_pwmchan, set_pwmchan, INPUT, 0); | ||
868 | static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm, | ||
869 | set_pwm, MIN, 0); | ||
870 | static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, | ||
871 | set_pwm, MAX, 0); | ||
872 | static SENSOR_DEVICE_ATTR_2(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT, | ||
873 | 1); | ||
874 | static SENSOR_DEVICE_ATTR_2(pwm2_freq, S_IRUGO | S_IWUSR, show_pwmfreq, | ||
875 | set_pwmfreq, INPUT, 1); | ||
876 | static SENSOR_DEVICE_ATTR_2(pwm2_enable, S_IRUGO | S_IWUSR, show_pwmctrl, | ||
877 | set_pwmctrl, INPUT, 1); | ||
878 | static SENSOR_DEVICE_ATTR_2(pwm2_auto_channel_temp, S_IRUGO | S_IWUSR, | ||
879 | show_pwmchan, set_pwmchan, INPUT, 1); | ||
880 | static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm, | ||
881 | set_pwm, MIN, 1); | ||
882 | static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, | ||
883 | set_pwm, MAX, 1); | ||
884 | static SENSOR_DEVICE_ATTR_2(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT, | ||
885 | 2); | ||
886 | static SENSOR_DEVICE_ATTR_2(pwm3_freq, S_IRUGO | S_IWUSR, show_pwmfreq, | ||
887 | set_pwmfreq, INPUT, 2); | ||
888 | static SENSOR_DEVICE_ATTR_2(pwm3_enable, S_IRUGO | S_IWUSR, show_pwmctrl, | ||
889 | set_pwmctrl, INPUT, 2); | ||
890 | static SENSOR_DEVICE_ATTR_2(pwm3_auto_channel_temp, S_IRUGO | S_IWUSR, | ||
891 | show_pwmchan, set_pwmchan, INPUT, 2); | ||
892 | static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm, | ||
893 | set_pwm, MIN, 2); | ||
894 | static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, | ||
895 | set_pwm, MAX, 2); | ||
896 | |||
897 | static struct attribute *adt7475_attrs[] = { | ||
898 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
899 | &sensor_dev_attr_in1_max.dev_attr.attr, | ||
900 | &sensor_dev_attr_in1_min.dev_attr.attr, | ||
901 | &sensor_dev_attr_in1_alarm.dev_attr.attr, | ||
902 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
903 | &sensor_dev_attr_in2_max.dev_attr.attr, | ||
904 | &sensor_dev_attr_in2_min.dev_attr.attr, | ||
905 | &sensor_dev_attr_in2_alarm.dev_attr.attr, | ||
906 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
907 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, | ||
908 | &sensor_dev_attr_temp1_fault.dev_attr.attr, | ||
909 | &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
910 | &sensor_dev_attr_temp1_min.dev_attr.attr, | ||
911 | &sensor_dev_attr_temp1_offset.dev_attr.attr, | ||
912 | &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, | ||
913 | &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr, | ||
914 | &sensor_dev_attr_temp1_crit.dev_attr.attr, | ||
915 | &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, | ||
916 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
917 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, | ||
918 | &sensor_dev_attr_temp2_max.dev_attr.attr, | ||
919 | &sensor_dev_attr_temp2_min.dev_attr.attr, | ||
920 | &sensor_dev_attr_temp2_offset.dev_attr.attr, | ||
921 | &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr, | ||
922 | &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr, | ||
923 | &sensor_dev_attr_temp2_crit.dev_attr.attr, | ||
924 | &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, | ||
925 | &sensor_dev_attr_temp3_input.dev_attr.attr, | ||
926 | &sensor_dev_attr_temp3_fault.dev_attr.attr, | ||
927 | &sensor_dev_attr_temp3_alarm.dev_attr.attr, | ||
928 | &sensor_dev_attr_temp3_max.dev_attr.attr, | ||
929 | &sensor_dev_attr_temp3_min.dev_attr.attr, | ||
930 | &sensor_dev_attr_temp3_offset.dev_attr.attr, | ||
931 | &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr, | ||
932 | &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr, | ||
933 | &sensor_dev_attr_temp3_crit.dev_attr.attr, | ||
934 | &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, | ||
935 | &sensor_dev_attr_fan1_input.dev_attr.attr, | ||
936 | &sensor_dev_attr_fan1_min.dev_attr.attr, | ||
937 | &sensor_dev_attr_fan1_alarm.dev_attr.attr, | ||
938 | &sensor_dev_attr_fan2_input.dev_attr.attr, | ||
939 | &sensor_dev_attr_fan2_min.dev_attr.attr, | ||
940 | &sensor_dev_attr_fan2_alarm.dev_attr.attr, | ||
941 | &sensor_dev_attr_fan3_input.dev_attr.attr, | ||
942 | &sensor_dev_attr_fan3_min.dev_attr.attr, | ||
943 | &sensor_dev_attr_fan3_alarm.dev_attr.attr, | ||
944 | &sensor_dev_attr_fan4_input.dev_attr.attr, | ||
945 | &sensor_dev_attr_fan4_min.dev_attr.attr, | ||
946 | &sensor_dev_attr_fan4_alarm.dev_attr.attr, | ||
947 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
948 | &sensor_dev_attr_pwm1_freq.dev_attr.attr, | ||
949 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | ||
950 | &sensor_dev_attr_pwm1_auto_channel_temp.dev_attr.attr, | ||
951 | &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, | ||
952 | &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, | ||
953 | &sensor_dev_attr_pwm2.dev_attr.attr, | ||
954 | &sensor_dev_attr_pwm2_freq.dev_attr.attr, | ||
955 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | ||
956 | &sensor_dev_attr_pwm2_auto_channel_temp.dev_attr.attr, | ||
957 | &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, | ||
958 | &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, | ||
959 | &sensor_dev_attr_pwm3.dev_attr.attr, | ||
960 | &sensor_dev_attr_pwm3_freq.dev_attr.attr, | ||
961 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, | ||
962 | &sensor_dev_attr_pwm3_auto_channel_temp.dev_attr.attr, | ||
963 | &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, | ||
964 | &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, | ||
965 | NULL, | ||
966 | }; | ||
967 | |||
968 | struct attribute_group adt7475_attr_group = { .attrs = adt7475_attrs }; | ||
969 | |||
970 | static int adt7475_detect(struct i2c_client *client, int kind, | ||
971 | struct i2c_board_info *info) | ||
972 | { | ||
973 | struct i2c_adapter *adapter = client->adapter; | ||
974 | |||
975 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
976 | return -ENODEV; | ||
977 | |||
978 | if (kind <= 0) { | ||
979 | if (adt7475_read(REG_VENDID) != 0x41 || | ||
980 | adt7475_read(REG_DEVID) != 0x75) { | ||
981 | dev_err(&adapter->dev, | ||
982 | "Couldn't detect a adt7475 part at 0x%02x\n", | ||
983 | (unsigned int)client->addr); | ||
984 | return -ENODEV; | ||
985 | } | ||
986 | } | ||
987 | |||
988 | strlcpy(info->type, adt7475_id[0].name, I2C_NAME_SIZE); | ||
989 | |||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static int adt7475_probe(struct i2c_client *client, | ||
994 | const struct i2c_device_id *id) | ||
995 | { | ||
996 | struct adt7475_data *data; | ||
997 | int i, ret = 0; | ||
998 | |||
999 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
1000 | if (data == NULL) | ||
1001 | return -ENOMEM; | ||
1002 | |||
1003 | mutex_init(&data->lock); | ||
1004 | i2c_set_clientdata(client, data); | ||
1005 | |||
1006 | /* Call adt7475_read_pwm for all pwm's as this will reprogram any | ||
1007 | pwm's which are disabled to manual mode with 0% duty cycle */ | ||
1008 | for (i = 0; i < ADT7475_PWM_COUNT; i++) | ||
1009 | adt7475_read_pwm(client, i); | ||
1010 | |||
1011 | ret = sysfs_create_group(&client->dev.kobj, &adt7475_attr_group); | ||
1012 | if (ret) | ||
1013 | goto efree; | ||
1014 | |||
1015 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
1016 | if (IS_ERR(data->hwmon_dev)) { | ||
1017 | ret = PTR_ERR(data->hwmon_dev); | ||
1018 | goto eremove; | ||
1019 | } | ||
1020 | |||
1021 | return 0; | ||
1022 | |||
1023 | eremove: | ||
1024 | sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group); | ||
1025 | efree: | ||
1026 | kfree(data); | ||
1027 | return ret; | ||
1028 | } | ||
1029 | |||
1030 | static int adt7475_remove(struct i2c_client *client) | ||
1031 | { | ||
1032 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
1033 | |||
1034 | hwmon_device_unregister(data->hwmon_dev); | ||
1035 | sysfs_remove_group(&client->dev.kobj, &adt7475_attr_group); | ||
1036 | kfree(data); | ||
1037 | |||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static struct i2c_driver adt7475_driver = { | ||
1042 | .class = I2C_CLASS_HWMON, | ||
1043 | .driver = { | ||
1044 | .name = "adt7475", | ||
1045 | }, | ||
1046 | .probe = adt7475_probe, | ||
1047 | .remove = adt7475_remove, | ||
1048 | .id_table = adt7475_id, | ||
1049 | .detect = adt7475_detect, | ||
1050 | .address_data = &addr_data, | ||
1051 | }; | ||
1052 | |||
1053 | static void adt7475_read_hystersis(struct i2c_client *client) | ||
1054 | { | ||
1055 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
1056 | |||
1057 | data->temp[HYSTERSIS][0] = (u16) adt7475_read(REG_REMOTE1_HYSTERSIS); | ||
1058 | data->temp[HYSTERSIS][1] = data->temp[HYSTERSIS][0]; | ||
1059 | data->temp[HYSTERSIS][2] = (u16) adt7475_read(REG_REMOTE2_HYSTERSIS); | ||
1060 | } | ||
1061 | |||
1062 | static void adt7475_read_pwm(struct i2c_client *client, int index) | ||
1063 | { | ||
1064 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
1065 | unsigned int v; | ||
1066 | |||
1067 | data->pwm[CONTROL][index] = adt7475_read(PWM_CONFIG_REG(index)); | ||
1068 | |||
1069 | /* Figure out the internal value for pwmctrl and pwmchan | ||
1070 | based on the current settings */ | ||
1071 | v = (data->pwm[CONTROL][index] >> 5) & 7; | ||
1072 | |||
1073 | if (v == 3) | ||
1074 | data->pwmctl[index] = 0; | ||
1075 | else if (v == 7) | ||
1076 | data->pwmctl[index] = 1; | ||
1077 | else if (v == 4) { | ||
1078 | /* The fan is disabled - we don't want to | ||
1079 | support that, so change to manual mode and | ||
1080 | set the duty cycle to 0 instead | ||
1081 | */ | ||
1082 | data->pwm[INPUT][index] = 0; | ||
1083 | data->pwm[CONTROL][index] &= ~0xE0; | ||
1084 | data->pwm[CONTROL][index] |= (7 << 5); | ||
1085 | |||
1086 | i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(index), | ||
1087 | data->pwm[INPUT][index]); | ||
1088 | |||
1089 | i2c_smbus_write_byte_data(client, PWM_CONFIG_REG(index), | ||
1090 | data->pwm[CONTROL][index]); | ||
1091 | |||
1092 | data->pwmctl[index] = 1; | ||
1093 | } else { | ||
1094 | data->pwmctl[index] = 2; | ||
1095 | |||
1096 | switch (v) { | ||
1097 | case 0: | ||
1098 | data->pwmchan[index] = 1; | ||
1099 | break; | ||
1100 | case 1: | ||
1101 | data->pwmchan[index] = 2; | ||
1102 | break; | ||
1103 | case 2: | ||
1104 | data->pwmchan[index] = 4; | ||
1105 | break; | ||
1106 | case 5: | ||
1107 | data->pwmchan[index] = 6; | ||
1108 | break; | ||
1109 | case 6: | ||
1110 | data->pwmchan[index] = 7; | ||
1111 | break; | ||
1112 | } | ||
1113 | } | ||
1114 | } | ||
1115 | |||
1116 | static struct adt7475_data *adt7475_update_device(struct device *dev) | ||
1117 | { | ||
1118 | struct i2c_client *client = to_i2c_client(dev); | ||
1119 | struct adt7475_data *data = i2c_get_clientdata(client); | ||
1120 | u8 ext; | ||
1121 | int i; | ||
1122 | |||
1123 | mutex_lock(&data->lock); | ||
1124 | |||
1125 | /* Measurement values update every 2 seconds */ | ||
1126 | if (time_after(jiffies, data->measure_updated + HZ * 2) || | ||
1127 | !data->valid) { | ||
1128 | data->alarms = adt7475_read(REG_STATUS2) << 8; | ||
1129 | data->alarms |= adt7475_read(REG_STATUS1); | ||
1130 | |||
1131 | ext = adt7475_read(REG_EXTEND1); | ||
1132 | for (i = 0; i < ADT7475_VOLTAGE_COUNT; i++) | ||
1133 | data->voltage[INPUT][i] = | ||
1134 | (adt7475_read(VOLTAGE_REG(i)) << 2) | | ||
1135 | ((ext >> ((i + 1) * 2)) & 3); | ||
1136 | |||
1137 | ext = adt7475_read(REG_EXTEND2); | ||
1138 | for (i = 0; i < ADT7475_TEMP_COUNT; i++) | ||
1139 | data->temp[INPUT][i] = | ||
1140 | (adt7475_read(TEMP_REG(i)) << 2) | | ||
1141 | ((ext >> ((i + 1) * 2)) & 3); | ||
1142 | |||
1143 | for (i = 0; i < ADT7475_TACH_COUNT; i++) | ||
1144 | data->tach[INPUT][i] = | ||
1145 | adt7475_read_word(client, TACH_REG(i)); | ||
1146 | |||
1147 | /* Updated by hw when in auto mode */ | ||
1148 | for (i = 0; i < ADT7475_PWM_COUNT; i++) | ||
1149 | data->pwm[INPUT][i] = adt7475_read(PWM_REG(i)); | ||
1150 | |||
1151 | data->measure_updated = jiffies; | ||
1152 | } | ||
1153 | |||
1154 | /* Limits and settings, should never change update every 60 seconds */ | ||
1155 | if (time_after(jiffies, data->limits_updated + HZ * 2) || | ||
1156 | !data->valid) { | ||
1157 | data->config5 = adt7475_read(REG_CONFIG5); | ||
1158 | |||
1159 | for (i = 0; i < ADT7475_VOLTAGE_COUNT; i++) { | ||
1160 | /* Adjust values so they match the input precision */ | ||
1161 | data->voltage[MIN][i] = | ||
1162 | adt7475_read(VOLTAGE_MIN_REG(i)) << 2; | ||
1163 | data->voltage[MAX][i] = | ||
1164 | adt7475_read(VOLTAGE_MAX_REG(i)) << 2; | ||
1165 | } | ||
1166 | |||
1167 | for (i = 0; i < ADT7475_TEMP_COUNT; i++) { | ||
1168 | /* Adjust values so they match the input precision */ | ||
1169 | data->temp[MIN][i] = | ||
1170 | adt7475_read(TEMP_MIN_REG(i)) << 2; | ||
1171 | data->temp[MAX][i] = | ||
1172 | adt7475_read(TEMP_MAX_REG(i)) << 2; | ||
1173 | data->temp[AUTOMIN][i] = | ||
1174 | adt7475_read(TEMP_TMIN_REG(i)) << 2; | ||
1175 | data->temp[THERM][i] = | ||
1176 | adt7475_read(TEMP_THERM_REG(i)) << 2; | ||
1177 | data->temp[OFFSET][i] = | ||
1178 | adt7475_read(TEMP_OFFSET_REG(i)); | ||
1179 | } | ||
1180 | adt7475_read_hystersis(client); | ||
1181 | |||
1182 | for (i = 0; i < ADT7475_TACH_COUNT; i++) | ||
1183 | data->tach[MIN][i] = | ||
1184 | adt7475_read_word(client, TACH_MIN_REG(i)); | ||
1185 | |||
1186 | for (i = 0; i < ADT7475_PWM_COUNT; i++) { | ||
1187 | data->pwm[MAX][i] = adt7475_read(PWM_MAX_REG(i)); | ||
1188 | data->pwm[MIN][i] = adt7475_read(PWM_MIN_REG(i)); | ||
1189 | /* Set the channel and control information */ | ||
1190 | adt7475_read_pwm(client, i); | ||
1191 | } | ||
1192 | |||
1193 | data->range[0] = adt7475_read(TEMP_TRANGE_REG(0)); | ||
1194 | data->range[1] = adt7475_read(TEMP_TRANGE_REG(1)); | ||
1195 | data->range[2] = adt7475_read(TEMP_TRANGE_REG(2)); | ||
1196 | |||
1197 | data->limits_updated = jiffies; | ||
1198 | data->valid = 1; | ||
1199 | } | ||
1200 | |||
1201 | mutex_unlock(&data->lock); | ||
1202 | |||
1203 | return data; | ||
1204 | } | ||
1205 | |||
1206 | static int __init sensors_adt7475_init(void) | ||
1207 | { | ||
1208 | return i2c_add_driver(&adt7475_driver); | ||
1209 | } | ||
1210 | |||
1211 | static void __exit sensors_adt7475_exit(void) | ||
1212 | { | ||
1213 | i2c_del_driver(&adt7475_driver); | ||
1214 | } | ||
1215 | |||
1216 | MODULE_AUTHOR("Advanced Micro Devices, Inc"); | ||
1217 | MODULE_DESCRIPTION("adt7475 driver"); | ||
1218 | MODULE_LICENSE("GPL"); | ||
1219 | |||
1220 | module_init(sensors_adt7475_init); | ||
1221 | module_exit(sensors_adt7475_exit); | ||
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index dca47a591ba..e3018623658 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c | |||
@@ -590,6 +590,11 @@ static ssize_t applesmc_light_show(struct device *dev, | |||
590 | } | 590 | } |
591 | 591 | ||
592 | ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length); | 592 | ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, data_length); |
593 | /* newer macbooks report a single 10-bit bigendian value */ | ||
594 | if (data_length == 10) { | ||
595 | left = be16_to_cpu(*(__be16 *)(buffer + 6)) >> 2; | ||
596 | goto out; | ||
597 | } | ||
593 | left = buffer[2]; | 598 | left = buffer[2]; |
594 | if (ret) | 599 | if (ret) |
595 | goto out; | 600 | goto out; |
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c index bf8d4058057..03705240000 100644 --- a/drivers/hwmon/hp_accel.c +++ b/drivers/hwmon/hp_accel.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2007-2008 Yan Burman | 4 | * Copyright (C) 2007-2008 Yan Burman |
5 | * Copyright (C) 2008 Eric Piel | 5 | * Copyright (C) 2008 Eric Piel |
6 | * Copyright (C) 2008 Pavel Machek | 6 | * Copyright (C) 2008-2009 Pavel Machek |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/freezer.h> | 36 | #include <linux/freezer.h> |
37 | #include <linux/version.h> | 37 | #include <linux/version.h> |
38 | #include <linux/uaccess.h> | 38 | #include <linux/uaccess.h> |
39 | #include <linux/leds.h> | ||
39 | #include <acpi/acpi_drivers.h> | 40 | #include <acpi/acpi_drivers.h> |
40 | #include <asm/atomic.h> | 41 | #include <asm/atomic.h> |
41 | #include "lis3lv02d.h" | 42 | #include "lis3lv02d.h" |
@@ -43,6 +44,36 @@ | |||
43 | #define DRIVER_NAME "lis3lv02d" | 44 | #define DRIVER_NAME "lis3lv02d" |
44 | #define ACPI_MDPS_CLASS "accelerometer" | 45 | #define ACPI_MDPS_CLASS "accelerometer" |
45 | 46 | ||
47 | /* Delayed LEDs infrastructure ------------------------------------ */ | ||
48 | |||
49 | /* Special LED class that can defer work */ | ||
50 | struct delayed_led_classdev { | ||
51 | struct led_classdev led_classdev; | ||
52 | struct work_struct work; | ||
53 | enum led_brightness new_brightness; | ||
54 | |||
55 | unsigned int led; /* For driver */ | ||
56 | void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value); | ||
57 | }; | ||
58 | |||
59 | static inline void delayed_set_status_worker(struct work_struct *work) | ||
60 | { | ||
61 | struct delayed_led_classdev *data = | ||
62 | container_of(work, struct delayed_led_classdev, work); | ||
63 | |||
64 | data->set_brightness(data, data->new_brightness); | ||
65 | } | ||
66 | |||
67 | static inline void delayed_sysfs_set(struct led_classdev *led_cdev, | ||
68 | enum led_brightness brightness) | ||
69 | { | ||
70 | struct delayed_led_classdev *data = container_of(led_cdev, | ||
71 | struct delayed_led_classdev, led_classdev); | ||
72 | data->new_brightness = brightness; | ||
73 | schedule_work(&data->work); | ||
74 | } | ||
75 | |||
76 | /* HP-specific accelerometer driver ------------------------------------ */ | ||
46 | 77 | ||
47 | /* For automatic insertion of the module */ | 78 | /* For automatic insertion of the module */ |
48 | static struct acpi_device_id lis3lv02d_device_ids[] = { | 79 | static struct acpi_device_id lis3lv02d_device_ids[] = { |
@@ -154,10 +185,33 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { | |||
154 | */ | 185 | */ |
155 | }; | 186 | }; |
156 | 187 | ||
188 | static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value) | ||
189 | { | ||
190 | acpi_handle handle = adev.device->handle; | ||
191 | unsigned long long ret; /* Not used when writing */ | ||
192 | union acpi_object in_obj[1]; | ||
193 | struct acpi_object_list args = { 1, in_obj }; | ||
194 | |||
195 | in_obj[0].type = ACPI_TYPE_INTEGER; | ||
196 | in_obj[0].integer.value = !!value; | ||
197 | |||
198 | acpi_evaluate_integer(handle, "ALED", &args, &ret); | ||
199 | } | ||
200 | |||
201 | static struct delayed_led_classdev hpled_led = { | ||
202 | .led_classdev = { | ||
203 | .name = "hp::hddprotect", | ||
204 | .default_trigger = "none", | ||
205 | .brightness_set = delayed_sysfs_set, | ||
206 | .flags = LED_CORE_SUSPENDRESUME, | ||
207 | }, | ||
208 | .set_brightness = hpled_set, | ||
209 | }; | ||
157 | 210 | ||
158 | static int lis3lv02d_add(struct acpi_device *device) | 211 | static int lis3lv02d_add(struct acpi_device *device) |
159 | { | 212 | { |
160 | u8 val; | 213 | u8 val; |
214 | int ret; | ||
161 | 215 | ||
162 | if (!device) | 216 | if (!device) |
163 | return -EINVAL; | 217 | return -EINVAL; |
@@ -183,7 +237,19 @@ static int lis3lv02d_add(struct acpi_device *device) | |||
183 | adev.ac = lis3lv02d_axis_normal; | 237 | adev.ac = lis3lv02d_axis_normal; |
184 | } | 238 | } |
185 | 239 | ||
186 | return lis3lv02d_init_device(&adev); | 240 | INIT_WORK(&hpled_led.work, delayed_set_status_worker); |
241 | ret = led_classdev_register(NULL, &hpled_led.led_classdev); | ||
242 | if (ret) | ||
243 | return ret; | ||
244 | |||
245 | ret = lis3lv02d_init_device(&adev); | ||
246 | if (ret) { | ||
247 | flush_work(&hpled_led.work); | ||
248 | led_classdev_unregister(&hpled_led.led_classdev); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | return ret; | ||
187 | } | 253 | } |
188 | 254 | ||
189 | static int lis3lv02d_remove(struct acpi_device *device, int type) | 255 | static int lis3lv02d_remove(struct acpi_device *device, int type) |
@@ -194,6 +260,9 @@ static int lis3lv02d_remove(struct acpi_device *device, int type) | |||
194 | lis3lv02d_joystick_disable(); | 260 | lis3lv02d_joystick_disable(); |
195 | lis3lv02d_poweroff(device->handle); | 261 | lis3lv02d_poweroff(device->handle); |
196 | 262 | ||
263 | flush_work(&hpled_led.work); | ||
264 | led_classdev_unregister(&hpled_led.led_classdev); | ||
265 | |||
197 | return lis3lv02d_remove_fs(); | 266 | return lis3lv02d_remove_fs(); |
198 | } | 267 | } |
199 | 268 | ||
@@ -256,7 +325,7 @@ static void __exit lis3lv02d_exit_module(void) | |||
256 | acpi_bus_unregister_driver(&lis3lv02d_driver); | 325 | acpi_bus_unregister_driver(&lis3lv02d_driver); |
257 | } | 326 | } |
258 | 327 | ||
259 | MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS"); | 328 | MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS and support for disk protection LED."); |
260 | MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); | 329 | MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); |
261 | MODULE_LICENSE("GPL"); | 330 | MODULE_LICENSE("GPL"); |
262 | 331 | ||
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index bd2bde0ef95..1fe99511184 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/hwmon-sysfs.h> | 31 | #include <linux/hwmon-sysfs.h> |
32 | #include <linux/err.h> | 32 | #include <linux/err.h> |
33 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | #include <asm/processor.h> | ||
34 | 35 | ||
35 | #define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000) | 36 | #define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000) |
36 | #define REG_TEMP 0xe4 | 37 | #define REG_TEMP 0xe4 |
@@ -47,6 +48,8 @@ struct k8temp_data { | |||
47 | /* registers values */ | 48 | /* registers values */ |
48 | u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */ | 49 | u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */ |
49 | u32 temp[2][2]; /* core, place */ | 50 | u32 temp[2][2]; /* core, place */ |
51 | u8 swap_core_select; /* meaning of SEL_CORE is inverted */ | ||
52 | u32 temp_offset; | ||
50 | }; | 53 | }; |
51 | 54 | ||
52 | static struct k8temp_data *k8temp_update_device(struct device *dev) | 55 | static struct k8temp_data *k8temp_update_device(struct device *dev) |
@@ -114,10 +117,15 @@ static ssize_t show_temp(struct device *dev, | |||
114 | to_sensor_dev_attr_2(devattr); | 117 | to_sensor_dev_attr_2(devattr); |
115 | int core = attr->nr; | 118 | int core = attr->nr; |
116 | int place = attr->index; | 119 | int place = attr->index; |
120 | int temp; | ||
117 | struct k8temp_data *data = k8temp_update_device(dev); | 121 | struct k8temp_data *data = k8temp_update_device(dev); |
118 | 122 | ||
119 | return sprintf(buf, "%d\n", | 123 | if (data->swap_core_select) |
120 | TEMP_FROM_REG(data->temp[core][place])); | 124 | core = core ? 0 : 1; |
125 | |||
126 | temp = TEMP_FROM_REG(data->temp[core][place]) + data->temp_offset; | ||
127 | |||
128 | return sprintf(buf, "%d\n", temp); | ||
121 | } | 129 | } |
122 | 130 | ||
123 | /* core, place */ | 131 | /* core, place */ |
@@ -141,20 +149,49 @@ static int __devinit k8temp_probe(struct pci_dev *pdev, | |||
141 | int err; | 149 | int err; |
142 | u8 scfg; | 150 | u8 scfg; |
143 | u32 temp; | 151 | u32 temp; |
152 | u8 model, stepping; | ||
144 | struct k8temp_data *data; | 153 | struct k8temp_data *data; |
145 | u32 cpuid = cpuid_eax(1); | ||
146 | |||
147 | /* this feature should be available since SH-C0 core */ | ||
148 | if ((cpuid == 0xf40) || (cpuid == 0xf50) || (cpuid == 0xf51)) { | ||
149 | err = -ENODEV; | ||
150 | goto exit; | ||
151 | } | ||
152 | 154 | ||
153 | if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) { | 155 | if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) { |
154 | err = -ENOMEM; | 156 | err = -ENOMEM; |
155 | goto exit; | 157 | goto exit; |
156 | } | 158 | } |
157 | 159 | ||
160 | model = boot_cpu_data.x86_model; | ||
161 | stepping = boot_cpu_data.x86_mask; | ||
162 | |||
163 | switch (boot_cpu_data.x86) { | ||
164 | case 0xf: | ||
165 | /* feature available since SH-C0, exclude older revisions */ | ||
166 | if (((model == 4) && (stepping == 0)) || | ||
167 | ((model == 5) && (stepping <= 1))) { | ||
168 | err = -ENODEV; | ||
169 | goto exit_free; | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * AMD NPT family 0fh, i.e. RevF and RevG: | ||
174 | * meaning of SEL_CORE bit is inverted | ||
175 | */ | ||
176 | if (model >= 0x40) { | ||
177 | data->swap_core_select = 1; | ||
178 | dev_warn(&pdev->dev, "Temperature readouts might be " | ||
179 | "wrong - check erratum #141\n"); | ||
180 | } | ||
181 | |||
182 | if ((model >= 0x69) && | ||
183 | !(model == 0xc1 || model == 0x6c || model == 0x7c)) { | ||
184 | /* | ||
185 | * RevG desktop CPUs (i.e. no socket S1G1 parts) | ||
186 | * need additional offset, otherwise reported | ||
187 | * temperature is below ambient temperature | ||
188 | */ | ||
189 | data->temp_offset = 21000; | ||
190 | } | ||
191 | |||
192 | break; | ||
193 | } | ||
194 | |||
158 | pci_read_config_byte(pdev, REG_TEMP, &scfg); | 195 | pci_read_config_byte(pdev, REG_TEMP, &scfg); |
159 | scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ | 196 | scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */ |
160 | pci_write_config_byte(pdev, REG_TEMP, scfg); | 197 | pci_write_config_byte(pdev, REG_TEMP, scfg); |