diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/Kconfig | 12 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/adt7462.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/amc6821.c | 1115 | ||||
-rw-r--r-- | drivers/hwmon/asus_atk0110.c | 304 | ||||
-rw-r--r-- | drivers/hwmon/coretemp.c | 16 | ||||
-rw-r--r-- | drivers/hwmon/fschmd.c | 7 | ||||
-rw-r--r-- | drivers/hwmon/k10temp.c | 40 | ||||
-rw-r--r-- | drivers/hwmon/k8temp.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/sis5595.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/smsc47m1.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/via686a.c | 2 | ||||
-rw-r--r-- | drivers/hwmon/vt8231.c | 2 |
13 files changed, 1427 insertions, 80 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 46c3c566307e..68cf87749a42 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -392,7 +392,7 @@ config SENSORS_GL520SM | |||
392 | 392 | ||
393 | config SENSORS_CORETEMP | 393 | config SENSORS_CORETEMP |
394 | tristate "Intel Core/Core2/Atom temperature sensor" | 394 | tristate "Intel Core/Core2/Atom temperature sensor" |
395 | depends on X86 && EXPERIMENTAL | 395 | depends on X86 && PCI && EXPERIMENTAL |
396 | help | 396 | help |
397 | If you say yes here you get support for the temperature | 397 | If you say yes here you get support for the temperature |
398 | sensor inside your CPU. Most of the family 6 CPUs | 398 | sensor inside your CPU. Most of the family 6 CPUs |
@@ -792,6 +792,16 @@ config SENSORS_ADS7828 | |||
792 | This driver can also be built as a module. If so, the module | 792 | This driver can also be built as a module. If so, the module |
793 | will be called ads7828. | 793 | will be called ads7828. |
794 | 794 | ||
795 | config SENSORS_AMC6821 | ||
796 | tristate "Texas Instruments AMC6821" | ||
797 | depends on I2C && EXPERIMENTAL | ||
798 | help | ||
799 | If you say yes here you get support for the Texas Instruments | ||
800 | AMC6821 hardware monitoring chips. | ||
801 | |||
802 | This driver can also be build as a module. If so, the module | ||
803 | will be called amc6821. | ||
804 | |||
795 | config SENSORS_THMC50 | 805 | config SENSORS_THMC50 |
796 | tristate "Texas Instruments THMC50 / Analog Devices ADM1022" | 806 | tristate "Texas Instruments THMC50 / Analog Devices ADM1022" |
797 | depends on I2C && EXPERIMENTAL | 807 | depends on I2C && EXPERIMENTAL |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 450c8e894277..4bc215c0953f 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -86,6 +86,7 @@ obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o | |||
86 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o | 86 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o |
87 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o | 87 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o |
88 | obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o | 88 | obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o |
89 | obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o | ||
89 | obj-$(CONFIG_SENSORS_THMC50) += thmc50.o | 90 | obj-$(CONFIG_SENSORS_THMC50) += thmc50.o |
90 | obj-$(CONFIG_SENSORS_TMP401) += tmp401.o | 91 | obj-$(CONFIG_SENSORS_TMP401) += tmp401.o |
91 | obj-$(CONFIG_SENSORS_TMP421) += tmp421.o | 92 | obj-$(CONFIG_SENSORS_TMP421) += tmp421.o |
diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index a1a7ef14b519..a31e77c776ae 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c | |||
@@ -94,7 +94,7 @@ static const unsigned short normal_i2c[] = { 0x58, 0x5C, I2C_CLIENT_END }; | |||
94 | #define ADT7462_PIN24_SHIFT 6 | 94 | #define ADT7462_PIN24_SHIFT 6 |
95 | #define ADT7462_PIN26_VOLT_INPUT 0x08 | 95 | #define ADT7462_PIN26_VOLT_INPUT 0x08 |
96 | #define ADT7462_PIN25_VOLT_INPUT 0x20 | 96 | #define ADT7462_PIN25_VOLT_INPUT 0x20 |
97 | #define ADT7462_PIN28_SHIFT 6 /* cfg3 */ | 97 | #define ADT7462_PIN28_SHIFT 4 /* cfg3 */ |
98 | #define ADT7462_PIN28_VOLT 0x5 | 98 | #define ADT7462_PIN28_VOLT 0x5 |
99 | 99 | ||
100 | #define ADT7462_REG_ALARM1 0xB8 | 100 | #define ADT7462_REG_ALARM1 0xB8 |
diff --git a/drivers/hwmon/amc6821.c b/drivers/hwmon/amc6821.c new file mode 100644 index 000000000000..fa9708c2d723 --- /dev/null +++ b/drivers/hwmon/amc6821.c | |||
@@ -0,0 +1,1115 @@ | |||
1 | /* | ||
2 | amc6821.c - Part of lm_sensors, Linux kernel modules for hardware | ||
3 | monitoring | ||
4 | Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si> | ||
5 | |||
6 | Based on max6650.c: | ||
7 | Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de> | ||
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 as published by | ||
11 | the Free Software Foundation; either version 2 of the License, or | ||
12 | (at your option) any later version. | ||
13 | |||
14 | This program is distributed in the hope that it will be useful, | ||
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | GNU General Public License for more details. | ||
18 | |||
19 | You should have received a copy of the GNU General Public License | ||
20 | along with this program; if not, write to the Free Software | ||
21 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | |||
25 | #include <linux/kernel.h> /* Needed for KERN_INFO */ | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/jiffies.h> | ||
30 | #include <linux/i2c.h> | ||
31 | #include <linux/hwmon.h> | ||
32 | #include <linux/hwmon-sysfs.h> | ||
33 | #include <linux/err.h> | ||
34 | #include <linux/mutex.h> | ||
35 | |||
36 | |||
37 | /* | ||
38 | * Addresses to scan. | ||
39 | */ | ||
40 | |||
41 | static const unsigned short normal_i2c[] = {0x18, 0x19, 0x1a, 0x2c, 0x2d, 0x2e, | ||
42 | 0x4c, 0x4d, 0x4e, I2C_CLIENT_END}; | ||
43 | |||
44 | |||
45 | |||
46 | /* | ||
47 | * Insmod parameters | ||
48 | */ | ||
49 | |||
50 | static int pwminv = 0; /*Inverted PWM output. */ | ||
51 | module_param(pwminv, int, S_IRUGO); | ||
52 | |||
53 | static int init = 1; /*Power-on initialization.*/ | ||
54 | module_param(init, int, S_IRUGO); | ||
55 | |||
56 | |||
57 | enum chips { amc6821 }; | ||
58 | |||
59 | #define AMC6821_REG_DEV_ID 0x3D | ||
60 | #define AMC6821_REG_COMP_ID 0x3E | ||
61 | #define AMC6821_REG_CONF1 0x00 | ||
62 | #define AMC6821_REG_CONF2 0x01 | ||
63 | #define AMC6821_REG_CONF3 0x3F | ||
64 | #define AMC6821_REG_CONF4 0x04 | ||
65 | #define AMC6821_REG_STAT1 0x02 | ||
66 | #define AMC6821_REG_STAT2 0x03 | ||
67 | #define AMC6821_REG_TDATA_LOW 0x08 | ||
68 | #define AMC6821_REG_TDATA_HI 0x09 | ||
69 | #define AMC6821_REG_LTEMP_HI 0x0A | ||
70 | #define AMC6821_REG_RTEMP_HI 0x0B | ||
71 | #define AMC6821_REG_LTEMP_LIMIT_MIN 0x15 | ||
72 | #define AMC6821_REG_LTEMP_LIMIT_MAX 0x14 | ||
73 | #define AMC6821_REG_RTEMP_LIMIT_MIN 0x19 | ||
74 | #define AMC6821_REG_RTEMP_LIMIT_MAX 0x18 | ||
75 | #define AMC6821_REG_LTEMP_CRIT 0x1B | ||
76 | #define AMC6821_REG_RTEMP_CRIT 0x1D | ||
77 | #define AMC6821_REG_PSV_TEMP 0x1C | ||
78 | #define AMC6821_REG_DCY 0x22 | ||
79 | #define AMC6821_REG_LTEMP_FAN_CTRL 0x24 | ||
80 | #define AMC6821_REG_RTEMP_FAN_CTRL 0x25 | ||
81 | #define AMC6821_REG_DCY_LOW_TEMP 0x21 | ||
82 | |||
83 | #define AMC6821_REG_TACH_LLIMITL 0x10 | ||
84 | #define AMC6821_REG_TACH_LLIMITH 0x11 | ||
85 | #define AMC6821_REG_TACH_HLIMITL 0x12 | ||
86 | #define AMC6821_REG_TACH_HLIMITH 0x13 | ||
87 | |||
88 | #define AMC6821_CONF1_START 0x01 | ||
89 | #define AMC6821_CONF1_FAN_INT_EN 0x02 | ||
90 | #define AMC6821_CONF1_FANIE 0x04 | ||
91 | #define AMC6821_CONF1_PWMINV 0x08 | ||
92 | #define AMC6821_CONF1_FAN_FAULT_EN 0x10 | ||
93 | #define AMC6821_CONF1_FDRC0 0x20 | ||
94 | #define AMC6821_CONF1_FDRC1 0x40 | ||
95 | #define AMC6821_CONF1_THERMOVIE 0x80 | ||
96 | |||
97 | #define AMC6821_CONF2_PWM_EN 0x01 | ||
98 | #define AMC6821_CONF2_TACH_MODE 0x02 | ||
99 | #define AMC6821_CONF2_TACH_EN 0x04 | ||
100 | #define AMC6821_CONF2_RTFIE 0x08 | ||
101 | #define AMC6821_CONF2_LTOIE 0x10 | ||
102 | #define AMC6821_CONF2_RTOIE 0x20 | ||
103 | #define AMC6821_CONF2_PSVIE 0x40 | ||
104 | #define AMC6821_CONF2_RST 0x80 | ||
105 | |||
106 | #define AMC6821_CONF3_THERM_FAN_EN 0x80 | ||
107 | #define AMC6821_CONF3_REV_MASK 0x0F | ||
108 | |||
109 | #define AMC6821_CONF4_OVREN 0x10 | ||
110 | #define AMC6821_CONF4_TACH_FAST 0x20 | ||
111 | #define AMC6821_CONF4_PSPR 0x40 | ||
112 | #define AMC6821_CONF4_MODE 0x80 | ||
113 | |||
114 | #define AMC6821_STAT1_RPM_ALARM 0x01 | ||
115 | #define AMC6821_STAT1_FANS 0x02 | ||
116 | #define AMC6821_STAT1_RTH 0x04 | ||
117 | #define AMC6821_STAT1_RTL 0x08 | ||
118 | #define AMC6821_STAT1_R_THERM 0x10 | ||
119 | #define AMC6821_STAT1_RTF 0x20 | ||
120 | #define AMC6821_STAT1_LTH 0x40 | ||
121 | #define AMC6821_STAT1_LTL 0x80 | ||
122 | |||
123 | #define AMC6821_STAT2_RTC 0x08 | ||
124 | #define AMC6821_STAT2_LTC 0x10 | ||
125 | #define AMC6821_STAT2_LPSV 0x20 | ||
126 | #define AMC6821_STAT2_L_THERM 0x40 | ||
127 | #define AMC6821_STAT2_THERM_IN 0x80 | ||
128 | |||
129 | enum {IDX_TEMP1_INPUT = 0, IDX_TEMP1_MIN, IDX_TEMP1_MAX, | ||
130 | IDX_TEMP1_CRIT, IDX_TEMP2_INPUT, IDX_TEMP2_MIN, | ||
131 | IDX_TEMP2_MAX, IDX_TEMP2_CRIT, | ||
132 | TEMP_IDX_LEN, }; | ||
133 | |||
134 | static const u8 temp_reg[] = {AMC6821_REG_LTEMP_HI, | ||
135 | AMC6821_REG_LTEMP_LIMIT_MIN, | ||
136 | AMC6821_REG_LTEMP_LIMIT_MAX, | ||
137 | AMC6821_REG_LTEMP_CRIT, | ||
138 | AMC6821_REG_RTEMP_HI, | ||
139 | AMC6821_REG_RTEMP_LIMIT_MIN, | ||
140 | AMC6821_REG_RTEMP_LIMIT_MAX, | ||
141 | AMC6821_REG_RTEMP_CRIT, }; | ||
142 | |||
143 | enum {IDX_FAN1_INPUT = 0, IDX_FAN1_MIN, IDX_FAN1_MAX, | ||
144 | FAN1_IDX_LEN, }; | ||
145 | |||
146 | static const u8 fan_reg_low[] = {AMC6821_REG_TDATA_LOW, | ||
147 | AMC6821_REG_TACH_LLIMITL, | ||
148 | AMC6821_REG_TACH_HLIMITL, }; | ||
149 | |||
150 | |||
151 | static const u8 fan_reg_hi[] = {AMC6821_REG_TDATA_HI, | ||
152 | AMC6821_REG_TACH_LLIMITH, | ||
153 | AMC6821_REG_TACH_HLIMITH, }; | ||
154 | |||
155 | static int amc6821_probe( | ||
156 | struct i2c_client *client, | ||
157 | const struct i2c_device_id *id); | ||
158 | static int amc6821_detect( | ||
159 | struct i2c_client *client, | ||
160 | struct i2c_board_info *info); | ||
161 | static int amc6821_init_client(struct i2c_client *client); | ||
162 | static int amc6821_remove(struct i2c_client *client); | ||
163 | static struct amc6821_data *amc6821_update_device(struct device *dev); | ||
164 | |||
165 | /* | ||
166 | * Driver data (common to all clients) | ||
167 | */ | ||
168 | |||
169 | static const struct i2c_device_id amc6821_id[] = { | ||
170 | { "amc6821", amc6821 }, | ||
171 | { } | ||
172 | }; | ||
173 | |||
174 | MODULE_DEVICE_TABLE(i2c, amc6821_id); | ||
175 | |||
176 | static struct i2c_driver amc6821_driver = { | ||
177 | .class = I2C_CLASS_HWMON, | ||
178 | .driver = { | ||
179 | .name = "amc6821", | ||
180 | }, | ||
181 | .probe = amc6821_probe, | ||
182 | .remove = amc6821_remove, | ||
183 | .id_table = amc6821_id, | ||
184 | .detect = amc6821_detect, | ||
185 | .address_list = normal_i2c, | ||
186 | }; | ||
187 | |||
188 | |||
189 | /* | ||
190 | * Client data (each client gets its own) | ||
191 | */ | ||
192 | |||
193 | struct amc6821_data { | ||
194 | struct device *hwmon_dev; | ||
195 | struct mutex update_lock; | ||
196 | char valid; /* zero until following fields are valid */ | ||
197 | unsigned long last_updated; /* in jiffies */ | ||
198 | |||
199 | /* register values */ | ||
200 | int temp[TEMP_IDX_LEN]; | ||
201 | |||
202 | u16 fan[FAN1_IDX_LEN]; | ||
203 | u8 fan1_div; | ||
204 | |||
205 | u8 pwm1; | ||
206 | u8 temp1_auto_point_temp[3]; | ||
207 | u8 temp2_auto_point_temp[3]; | ||
208 | u8 pwm1_auto_point_pwm[3]; | ||
209 | u8 pwm1_enable; | ||
210 | u8 pwm1_auto_channels_temp; | ||
211 | |||
212 | u8 stat1; | ||
213 | u8 stat2; | ||
214 | }; | ||
215 | |||
216 | |||
217 | static ssize_t get_temp( | ||
218 | struct device *dev, | ||
219 | struct device_attribute *devattr, | ||
220 | char *buf) | ||
221 | { | ||
222 | struct amc6821_data *data = amc6821_update_device(dev); | ||
223 | int ix = to_sensor_dev_attr(devattr)->index; | ||
224 | |||
225 | return sprintf(buf, "%d\n", data->temp[ix] * 1000); | ||
226 | } | ||
227 | |||
228 | |||
229 | |||
230 | static ssize_t set_temp( | ||
231 | struct device *dev, | ||
232 | struct device_attribute *attr, | ||
233 | const char *buf, | ||
234 | size_t count) | ||
235 | { | ||
236 | struct i2c_client *client = to_i2c_client(dev); | ||
237 | struct amc6821_data *data = i2c_get_clientdata(client); | ||
238 | int ix = to_sensor_dev_attr(attr)->index; | ||
239 | long val; | ||
240 | |||
241 | int ret = strict_strtol(buf, 10, &val); | ||
242 | if (ret) | ||
243 | return ret; | ||
244 | val = SENSORS_LIMIT(val / 1000, -128, 127); | ||
245 | |||
246 | mutex_lock(&data->update_lock); | ||
247 | data->temp[ix] = val; | ||
248 | if (i2c_smbus_write_byte_data(client, temp_reg[ix], data->temp[ix])) { | ||
249 | dev_err(&client->dev, "Register write error, aborting.\n"); | ||
250 | count = -EIO; | ||
251 | } | ||
252 | mutex_unlock(&data->update_lock); | ||
253 | return count; | ||
254 | } | ||
255 | |||
256 | |||
257 | |||
258 | |||
259 | static ssize_t get_temp_alarm( | ||
260 | struct device *dev, | ||
261 | struct device_attribute *devattr, | ||
262 | char *buf) | ||
263 | { | ||
264 | struct amc6821_data *data = amc6821_update_device(dev); | ||
265 | int ix = to_sensor_dev_attr(devattr)->index; | ||
266 | u8 flag; | ||
267 | |||
268 | switch (ix) { | ||
269 | case IDX_TEMP1_MIN: | ||
270 | flag = data->stat1 & AMC6821_STAT1_LTL; | ||
271 | break; | ||
272 | case IDX_TEMP1_MAX: | ||
273 | flag = data->stat1 & AMC6821_STAT1_LTH; | ||
274 | break; | ||
275 | case IDX_TEMP1_CRIT: | ||
276 | flag = data->stat2 & AMC6821_STAT2_LTC; | ||
277 | break; | ||
278 | case IDX_TEMP2_MIN: | ||
279 | flag = data->stat1 & AMC6821_STAT1_RTL; | ||
280 | break; | ||
281 | case IDX_TEMP2_MAX: | ||
282 | flag = data->stat1 & AMC6821_STAT1_RTH; | ||
283 | break; | ||
284 | case IDX_TEMP2_CRIT: | ||
285 | flag = data->stat2 & AMC6821_STAT2_RTC; | ||
286 | break; | ||
287 | default: | ||
288 | dev_dbg(dev, "Unknown attr->index (%d).\n", ix); | ||
289 | return -EINVAL; | ||
290 | } | ||
291 | if (flag) | ||
292 | return sprintf(buf, "1"); | ||
293 | else | ||
294 | return sprintf(buf, "0"); | ||
295 | } | ||
296 | |||
297 | |||
298 | |||
299 | |||
300 | static ssize_t get_temp2_fault( | ||
301 | struct device *dev, | ||
302 | struct device_attribute *devattr, | ||
303 | char *buf) | ||
304 | { | ||
305 | struct amc6821_data *data = amc6821_update_device(dev); | ||
306 | if (data->stat1 & AMC6821_STAT1_RTF) | ||
307 | return sprintf(buf, "1"); | ||
308 | else | ||
309 | return sprintf(buf, "0"); | ||
310 | } | ||
311 | |||
312 | static ssize_t get_pwm1( | ||
313 | struct device *dev, | ||
314 | struct device_attribute *devattr, | ||
315 | char *buf) | ||
316 | { | ||
317 | struct amc6821_data *data = amc6821_update_device(dev); | ||
318 | return sprintf(buf, "%d\n", data->pwm1); | ||
319 | } | ||
320 | |||
321 | static ssize_t set_pwm1( | ||
322 | struct device *dev, | ||
323 | struct device_attribute *devattr, | ||
324 | const char *buf, | ||
325 | size_t count) | ||
326 | { | ||
327 | struct i2c_client *client = to_i2c_client(dev); | ||
328 | struct amc6821_data *data = i2c_get_clientdata(client); | ||
329 | long val; | ||
330 | int ret = strict_strtol(buf, 10, &val); | ||
331 | if (ret) | ||
332 | return ret; | ||
333 | |||
334 | mutex_lock(&data->update_lock); | ||
335 | data->pwm1 = SENSORS_LIMIT(val , 0, 255); | ||
336 | i2c_smbus_write_byte_data(client, AMC6821_REG_DCY, data->pwm1); | ||
337 | mutex_unlock(&data->update_lock); | ||
338 | return count; | ||
339 | } | ||
340 | |||
341 | static ssize_t get_pwm1_enable( | ||
342 | struct device *dev, | ||
343 | struct device_attribute *devattr, | ||
344 | char *buf) | ||
345 | { | ||
346 | struct amc6821_data *data = amc6821_update_device(dev); | ||
347 | return sprintf(buf, "%d\n", data->pwm1_enable); | ||
348 | } | ||
349 | |||
350 | static ssize_t set_pwm1_enable( | ||
351 | struct device *dev, | ||
352 | struct device_attribute *attr, | ||
353 | const char *buf, | ||
354 | size_t count) | ||
355 | { | ||
356 | struct i2c_client *client = to_i2c_client(dev); | ||
357 | struct amc6821_data *data = i2c_get_clientdata(client); | ||
358 | long val; | ||
359 | int config = strict_strtol(buf, 10, &val); | ||
360 | if (config) | ||
361 | return config; | ||
362 | |||
363 | config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1); | ||
364 | if (config < 0) { | ||
365 | dev_err(&client->dev, | ||
366 | "Error reading configuration register, aborting.\n"); | ||
367 | return -EIO; | ||
368 | } | ||
369 | |||
370 | switch (val) { | ||
371 | case 1: | ||
372 | config &= ~AMC6821_CONF1_FDRC0; | ||
373 | config &= ~AMC6821_CONF1_FDRC1; | ||
374 | break; | ||
375 | case 2: | ||
376 | config &= ~AMC6821_CONF1_FDRC0; | ||
377 | config |= AMC6821_CONF1_FDRC1; | ||
378 | break; | ||
379 | case 3: | ||
380 | config |= AMC6821_CONF1_FDRC0; | ||
381 | config |= AMC6821_CONF1_FDRC1; | ||
382 | break; | ||
383 | default: | ||
384 | return -EINVAL; | ||
385 | } | ||
386 | mutex_lock(&data->update_lock); | ||
387 | if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF1, config)) { | ||
388 | dev_err(&client->dev, | ||
389 | "Configuration register write error, aborting.\n"); | ||
390 | count = -EIO; | ||
391 | } | ||
392 | mutex_unlock(&data->update_lock); | ||
393 | return count; | ||
394 | } | ||
395 | |||
396 | |||
397 | static ssize_t get_pwm1_auto_channels_temp( | ||
398 | struct device *dev, | ||
399 | struct device_attribute *devattr, | ||
400 | char *buf) | ||
401 | { | ||
402 | struct amc6821_data *data = amc6821_update_device(dev); | ||
403 | return sprintf(buf, "%d\n", data->pwm1_auto_channels_temp); | ||
404 | } | ||
405 | |||
406 | |||
407 | static ssize_t get_temp_auto_point_temp( | ||
408 | struct device *dev, | ||
409 | struct device_attribute *devattr, | ||
410 | char *buf) | ||
411 | { | ||
412 | int ix = to_sensor_dev_attr_2(devattr)->index; | ||
413 | int nr = to_sensor_dev_attr_2(devattr)->nr; | ||
414 | struct amc6821_data *data = amc6821_update_device(dev); | ||
415 | switch (nr) { | ||
416 | case 1: | ||
417 | return sprintf(buf, "%d\n", | ||
418 | data->temp1_auto_point_temp[ix] * 1000); | ||
419 | break; | ||
420 | case 2: | ||
421 | return sprintf(buf, "%d\n", | ||
422 | data->temp2_auto_point_temp[ix] * 1000); | ||
423 | break; | ||
424 | default: | ||
425 | dev_dbg(dev, "Unknown attr->nr (%d).\n", nr); | ||
426 | return -EINVAL; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | |||
431 | static ssize_t get_pwm1_auto_point_pwm( | ||
432 | struct device *dev, | ||
433 | struct device_attribute *devattr, | ||
434 | char *buf) | ||
435 | { | ||
436 | int ix = to_sensor_dev_attr(devattr)->index; | ||
437 | struct amc6821_data *data = amc6821_update_device(dev); | ||
438 | return sprintf(buf, "%d\n", data->pwm1_auto_point_pwm[ix]); | ||
439 | } | ||
440 | |||
441 | |||
442 | static inline ssize_t set_slope_register(struct i2c_client *client, | ||
443 | u8 reg, | ||
444 | u8 dpwm, | ||
445 | u8 *ptemp) | ||
446 | { | ||
447 | int dt; | ||
448 | u8 tmp; | ||
449 | |||
450 | dt = ptemp[2]-ptemp[1]; | ||
451 | for (tmp = 4; tmp > 0; tmp--) { | ||
452 | if (dt * (0x20 >> tmp) >= dpwm) | ||
453 | break; | ||
454 | } | ||
455 | tmp |= (ptemp[1] & 0x7C) << 1; | ||
456 | if (i2c_smbus_write_byte_data(client, | ||
457 | reg, tmp)) { | ||
458 | dev_err(&client->dev, "Register write error, aborting.\n"); | ||
459 | return -EIO; | ||
460 | } | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | |||
465 | |||
466 | static ssize_t set_temp_auto_point_temp( | ||
467 | struct device *dev, | ||
468 | struct device_attribute *attr, | ||
469 | const char *buf, | ||
470 | size_t count) | ||
471 | { | ||
472 | struct i2c_client *client = to_i2c_client(dev); | ||
473 | struct amc6821_data *data = amc6821_update_device(dev); | ||
474 | int ix = to_sensor_dev_attr_2(attr)->index; | ||
475 | int nr = to_sensor_dev_attr_2(attr)->nr; | ||
476 | u8 *ptemp; | ||
477 | u8 reg; | ||
478 | int dpwm; | ||
479 | long val; | ||
480 | int ret = strict_strtol(buf, 10, &val); | ||
481 | if (ret) | ||
482 | return ret; | ||
483 | |||
484 | switch (nr) { | ||
485 | case 1: | ||
486 | ptemp = data->temp1_auto_point_temp; | ||
487 | reg = AMC6821_REG_LTEMP_FAN_CTRL; | ||
488 | break; | ||
489 | case 2: | ||
490 | ptemp = data->temp2_auto_point_temp; | ||
491 | reg = AMC6821_REG_RTEMP_FAN_CTRL; | ||
492 | break; | ||
493 | default: | ||
494 | dev_dbg(dev, "Unknown attr->nr (%d).\n", nr); | ||
495 | return -EINVAL; | ||
496 | } | ||
497 | |||
498 | data->valid = 0; | ||
499 | mutex_lock(&data->update_lock); | ||
500 | switch (ix) { | ||
501 | case 0: | ||
502 | ptemp[0] = SENSORS_LIMIT(val / 1000, 0, | ||
503 | data->temp1_auto_point_temp[1]); | ||
504 | ptemp[0] = SENSORS_LIMIT(ptemp[0], 0, | ||
505 | data->temp2_auto_point_temp[1]); | ||
506 | ptemp[0] = SENSORS_LIMIT(ptemp[0], 0, 63); | ||
507 | if (i2c_smbus_write_byte_data( | ||
508 | client, | ||
509 | AMC6821_REG_PSV_TEMP, | ||
510 | ptemp[0])) { | ||
511 | dev_err(&client->dev, | ||
512 | "Register write error, aborting.\n"); | ||
513 | count = -EIO; | ||
514 | } | ||
515 | goto EXIT; | ||
516 | break; | ||
517 | case 1: | ||
518 | ptemp[1] = SENSORS_LIMIT( | ||
519 | val / 1000, | ||
520 | (ptemp[0] & 0x7C) + 4, | ||
521 | 124); | ||
522 | ptemp[1] &= 0x7C; | ||
523 | ptemp[2] = SENSORS_LIMIT( | ||
524 | ptemp[2], ptemp[1] + 1, | ||
525 | 255); | ||
526 | break; | ||
527 | case 2: | ||
528 | ptemp[2] = SENSORS_LIMIT( | ||
529 | val / 1000, | ||
530 | ptemp[1]+1, | ||
531 | 255); | ||
532 | break; | ||
533 | default: | ||
534 | dev_dbg(dev, "Unknown attr->index (%d).\n", ix); | ||
535 | count = -EINVAL; | ||
536 | goto EXIT; | ||
537 | } | ||
538 | dpwm = data->pwm1_auto_point_pwm[2] - data->pwm1_auto_point_pwm[1]; | ||
539 | if (set_slope_register(client, reg, dpwm, ptemp)) | ||
540 | count = -EIO; | ||
541 | |||
542 | EXIT: | ||
543 | mutex_unlock(&data->update_lock); | ||
544 | return count; | ||
545 | } | ||
546 | |||
547 | |||
548 | |||
549 | static ssize_t set_pwm1_auto_point_pwm( | ||
550 | struct device *dev, | ||
551 | struct device_attribute *attr, | ||
552 | const char *buf, | ||
553 | size_t count) | ||
554 | { | ||
555 | struct i2c_client *client = to_i2c_client(dev); | ||
556 | struct amc6821_data *data = i2c_get_clientdata(client); | ||
557 | int dpwm; | ||
558 | long val; | ||
559 | int ret = strict_strtol(buf, 10, &val); | ||
560 | if (ret) | ||
561 | return ret; | ||
562 | |||
563 | mutex_lock(&data->update_lock); | ||
564 | data->pwm1_auto_point_pwm[1] = SENSORS_LIMIT(val, 0, 254); | ||
565 | if (i2c_smbus_write_byte_data(client, AMC6821_REG_DCY_LOW_TEMP, | ||
566 | data->pwm1_auto_point_pwm[1])) { | ||
567 | dev_err(&client->dev, "Register write error, aborting.\n"); | ||
568 | count = -EIO; | ||
569 | goto EXIT; | ||
570 | } | ||
571 | dpwm = data->pwm1_auto_point_pwm[2] - data->pwm1_auto_point_pwm[1]; | ||
572 | if (set_slope_register(client, AMC6821_REG_LTEMP_FAN_CTRL, dpwm, | ||
573 | data->temp1_auto_point_temp)) { | ||
574 | count = -EIO; | ||
575 | goto EXIT; | ||
576 | } | ||
577 | if (set_slope_register(client, AMC6821_REG_RTEMP_FAN_CTRL, dpwm, | ||
578 | data->temp2_auto_point_temp)) { | ||
579 | count = -EIO; | ||
580 | goto EXIT; | ||
581 | } | ||
582 | |||
583 | EXIT: | ||
584 | data->valid = 0; | ||
585 | mutex_unlock(&data->update_lock); | ||
586 | return count; | ||
587 | } | ||
588 | |||
589 | static ssize_t get_fan( | ||
590 | struct device *dev, | ||
591 | struct device_attribute *devattr, | ||
592 | char *buf) | ||
593 | { | ||
594 | struct amc6821_data *data = amc6821_update_device(dev); | ||
595 | int ix = to_sensor_dev_attr(devattr)->index; | ||
596 | if (0 == data->fan[ix]) | ||
597 | return sprintf(buf, "0"); | ||
598 | return sprintf(buf, "%d\n", (int)(6000000 / data->fan[ix])); | ||
599 | } | ||
600 | |||
601 | |||
602 | |||
603 | static ssize_t get_fan1_fault( | ||
604 | struct device *dev, | ||
605 | struct device_attribute *devattr, | ||
606 | char *buf) | ||
607 | { | ||
608 | struct amc6821_data *data = amc6821_update_device(dev); | ||
609 | if (data->stat1 & AMC6821_STAT1_FANS) | ||
610 | return sprintf(buf, "1"); | ||
611 | else | ||
612 | return sprintf(buf, "0"); | ||
613 | } | ||
614 | |||
615 | |||
616 | |||
617 | static ssize_t set_fan( | ||
618 | struct device *dev, | ||
619 | struct device_attribute *attr, | ||
620 | const char *buf, size_t count) | ||
621 | { | ||
622 | struct i2c_client *client = to_i2c_client(dev); | ||
623 | struct amc6821_data *data = i2c_get_clientdata(client); | ||
624 | long val; | ||
625 | int ix = to_sensor_dev_attr(attr)->index; | ||
626 | int ret = strict_strtol(buf, 10, &val); | ||
627 | if (ret) | ||
628 | return ret; | ||
629 | val = 1 > val ? 0xFFFF : 6000000/val; | ||
630 | |||
631 | mutex_lock(&data->update_lock); | ||
632 | data->fan[ix] = (u16) SENSORS_LIMIT(val, 1, 0xFFFF); | ||
633 | if (i2c_smbus_write_byte_data(client, fan_reg_low[ix], | ||
634 | data->fan[ix] & 0xFF)) { | ||
635 | dev_err(&client->dev, "Register write error, aborting.\n"); | ||
636 | count = -EIO; | ||
637 | goto EXIT; | ||
638 | } | ||
639 | if (i2c_smbus_write_byte_data(client, | ||
640 | fan_reg_hi[ix], data->fan[ix] >> 8)) { | ||
641 | dev_err(&client->dev, "Register write error, aborting.\n"); | ||
642 | count = -EIO; | ||
643 | } | ||
644 | EXIT: | ||
645 | mutex_unlock(&data->update_lock); | ||
646 | return count; | ||
647 | } | ||
648 | |||
649 | |||
650 | |||
651 | static ssize_t get_fan1_div( | ||
652 | struct device *dev, | ||
653 | struct device_attribute *devattr, | ||
654 | char *buf) | ||
655 | { | ||
656 | struct amc6821_data *data = amc6821_update_device(dev); | ||
657 | return sprintf(buf, "%d\n", data->fan1_div); | ||
658 | } | ||
659 | |||
660 | static ssize_t set_fan1_div( | ||
661 | struct device *dev, | ||
662 | struct device_attribute *attr, | ||
663 | const char *buf, size_t count) | ||
664 | { | ||
665 | struct i2c_client *client = to_i2c_client(dev); | ||
666 | struct amc6821_data *data = i2c_get_clientdata(client); | ||
667 | long val; | ||
668 | int config = strict_strtol(buf, 10, &val); | ||
669 | if (config) | ||
670 | return config; | ||
671 | |||
672 | config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4); | ||
673 | if (config < 0) { | ||
674 | dev_err(&client->dev, | ||
675 | "Error reading configuration register, aborting.\n"); | ||
676 | return -EIO; | ||
677 | } | ||
678 | mutex_lock(&data->update_lock); | ||
679 | switch (val) { | ||
680 | case 2: | ||
681 | config &= ~AMC6821_CONF4_PSPR; | ||
682 | data->fan1_div = 2; | ||
683 | break; | ||
684 | case 4: | ||
685 | config |= AMC6821_CONF4_PSPR; | ||
686 | data->fan1_div = 4; | ||
687 | break; | ||
688 | default: | ||
689 | count = -EINVAL; | ||
690 | goto EXIT; | ||
691 | } | ||
692 | if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4, config)) { | ||
693 | dev_err(&client->dev, | ||
694 | "Configuration register write error, aborting.\n"); | ||
695 | count = -EIO; | ||
696 | } | ||
697 | EXIT: | ||
698 | mutex_unlock(&data->update_lock); | ||
699 | return count; | ||
700 | } | ||
701 | |||
702 | |||
703 | |||
704 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, | ||
705 | get_temp, NULL, IDX_TEMP1_INPUT); | ||
706 | static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, get_temp, | ||
707 | set_temp, IDX_TEMP1_MIN); | ||
708 | static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, get_temp, | ||
709 | set_temp, IDX_TEMP1_MAX); | ||
710 | static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, get_temp, | ||
711 | set_temp, IDX_TEMP1_CRIT); | ||
712 | static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, | ||
713 | get_temp_alarm, NULL, IDX_TEMP1_MIN); | ||
714 | static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, | ||
715 | get_temp_alarm, NULL, IDX_TEMP1_MAX); | ||
716 | static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, | ||
717 | get_temp_alarm, NULL, IDX_TEMP1_CRIT); | ||
718 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO | S_IWUSR, | ||
719 | get_temp, NULL, IDX_TEMP2_INPUT); | ||
720 | static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, get_temp, | ||
721 | set_temp, IDX_TEMP2_MIN); | ||
722 | static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, get_temp, | ||
723 | set_temp, IDX_TEMP2_MAX); | ||
724 | static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, get_temp, | ||
725 | set_temp, IDX_TEMP2_CRIT); | ||
726 | static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, | ||
727 | get_temp2_fault, NULL, 0); | ||
728 | static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, | ||
729 | get_temp_alarm, NULL, IDX_TEMP2_MIN); | ||
730 | static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, | ||
731 | get_temp_alarm, NULL, IDX_TEMP2_MAX); | ||
732 | static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, | ||
733 | get_temp_alarm, NULL, IDX_TEMP2_CRIT); | ||
734 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, IDX_FAN1_INPUT); | ||
735 | static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, | ||
736 | get_fan, set_fan, IDX_FAN1_MIN); | ||
737 | static SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO | S_IWUSR, | ||
738 | get_fan, set_fan, IDX_FAN1_MAX); | ||
739 | static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan1_fault, NULL, 0); | ||
740 | static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, | ||
741 | get_fan1_div, set_fan1_div, 0); | ||
742 | |||
743 | static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm1, set_pwm1, 0); | ||
744 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, | ||
745 | get_pwm1_enable, set_pwm1_enable, 0); | ||
746 | static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, | ||
747 | get_pwm1_auto_point_pwm, NULL, 0); | ||
748 | static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO, | ||
749 | get_pwm1_auto_point_pwm, set_pwm1_auto_point_pwm, 1); | ||
750 | static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, | ||
751 | get_pwm1_auto_point_pwm, NULL, 2); | ||
752 | static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO, | ||
753 | get_pwm1_auto_channels_temp, NULL, 0); | ||
754 | static SENSOR_DEVICE_ATTR_2(temp1_auto_point1_temp, S_IRUGO, | ||
755 | get_temp_auto_point_temp, NULL, 1, 0); | ||
756 | static SENSOR_DEVICE_ATTR_2(temp1_auto_point2_temp, S_IWUSR | S_IRUGO, | ||
757 | get_temp_auto_point_temp, set_temp_auto_point_temp, 1, 1); | ||
758 | static SENSOR_DEVICE_ATTR_2(temp1_auto_point3_temp, S_IWUSR | S_IRUGO, | ||
759 | get_temp_auto_point_temp, set_temp_auto_point_temp, 1, 2); | ||
760 | |||
761 | static SENSOR_DEVICE_ATTR_2(temp2_auto_point1_temp, S_IWUSR | S_IRUGO, | ||
762 | get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 0); | ||
763 | static SENSOR_DEVICE_ATTR_2(temp2_auto_point2_temp, S_IWUSR | S_IRUGO, | ||
764 | get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 1); | ||
765 | static SENSOR_DEVICE_ATTR_2(temp2_auto_point3_temp, S_IWUSR | S_IRUGO, | ||
766 | get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 2); | ||
767 | |||
768 | |||
769 | |||
770 | static struct attribute *amc6821_attrs[] = { | ||
771 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
772 | &sensor_dev_attr_temp1_min.dev_attr.attr, | ||
773 | &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
774 | &sensor_dev_attr_temp1_crit.dev_attr.attr, | ||
775 | &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, | ||
776 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | ||
777 | &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, | ||
778 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
779 | &sensor_dev_attr_temp2_min.dev_attr.attr, | ||
780 | &sensor_dev_attr_temp2_max.dev_attr.attr, | ||
781 | &sensor_dev_attr_temp2_crit.dev_attr.attr, | ||
782 | &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, | ||
783 | &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, | ||
784 | &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, | ||
785 | &sensor_dev_attr_temp2_fault.dev_attr.attr, | ||
786 | &sensor_dev_attr_fan1_input.dev_attr.attr, | ||
787 | &sensor_dev_attr_fan1_min.dev_attr.attr, | ||
788 | &sensor_dev_attr_fan1_max.dev_attr.attr, | ||
789 | &sensor_dev_attr_fan1_fault.dev_attr.attr, | ||
790 | &sensor_dev_attr_fan1_div.dev_attr.attr, | ||
791 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
792 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | ||
793 | &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr, | ||
794 | &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, | ||
795 | &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, | ||
796 | &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, | ||
797 | &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, | ||
798 | &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr, | ||
799 | &sensor_dev_attr_temp1_auto_point3_temp.dev_attr.attr, | ||
800 | &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr, | ||
801 | &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr, | ||
802 | &sensor_dev_attr_temp2_auto_point3_temp.dev_attr.attr, | ||
803 | NULL | ||
804 | }; | ||
805 | |||
806 | static struct attribute_group amc6821_attr_grp = { | ||
807 | .attrs = amc6821_attrs, | ||
808 | }; | ||
809 | |||
810 | |||
811 | |||
812 | /* Return 0 if detection is successful, -ENODEV otherwise */ | ||
813 | static int amc6821_detect( | ||
814 | struct i2c_client *client, | ||
815 | struct i2c_board_info *info) | ||
816 | { | ||
817 | struct i2c_adapter *adapter = client->adapter; | ||
818 | int address = client->addr; | ||
819 | int dev_id, comp_id; | ||
820 | |||
821 | dev_dbg(&adapter->dev, "amc6821_detect called.\n"); | ||
822 | |||
823 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | ||
824 | dev_dbg(&adapter->dev, | ||
825 | "amc6821: I2C bus doesn't support byte mode, " | ||
826 | "skipping.\n"); | ||
827 | return -ENODEV; | ||
828 | } | ||
829 | |||
830 | dev_id = i2c_smbus_read_byte_data(client, AMC6821_REG_DEV_ID); | ||
831 | comp_id = i2c_smbus_read_byte_data(client, AMC6821_REG_COMP_ID); | ||
832 | if (dev_id != 0x21 || comp_id != 0x49) { | ||
833 | dev_dbg(&adapter->dev, | ||
834 | "amc6821: detection failed at 0x%02x.\n", | ||
835 | address); | ||
836 | return -ENODEV; | ||
837 | } | ||
838 | |||
839 | /* Bit 7 of the address register is ignored, so we can check the | ||
840 | ID registers again */ | ||
841 | dev_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_DEV_ID); | ||
842 | comp_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_COMP_ID); | ||
843 | if (dev_id != 0x21 || comp_id != 0x49) { | ||
844 | dev_dbg(&adapter->dev, | ||
845 | "amc6821: detection failed at 0x%02x.\n", | ||
846 | address); | ||
847 | return -ENODEV; | ||
848 | } | ||
849 | |||
850 | dev_info(&adapter->dev, "amc6821: chip found at 0x%02x.\n", address); | ||
851 | strlcpy(info->type, "amc6821", I2C_NAME_SIZE); | ||
852 | |||
853 | return 0; | ||
854 | } | ||
855 | |||
856 | static int amc6821_probe( | ||
857 | struct i2c_client *client, | ||
858 | const struct i2c_device_id *id) | ||
859 | { | ||
860 | struct amc6821_data *data; | ||
861 | int err; | ||
862 | |||
863 | data = kzalloc(sizeof(struct amc6821_data), GFP_KERNEL); | ||
864 | if (!data) { | ||
865 | dev_err(&client->dev, "out of memory.\n"); | ||
866 | return -ENOMEM; | ||
867 | } | ||
868 | |||
869 | |||
870 | i2c_set_clientdata(client, data); | ||
871 | mutex_init(&data->update_lock); | ||
872 | |||
873 | /* | ||
874 | * Initialize the amc6821 chip | ||
875 | */ | ||
876 | err = amc6821_init_client(client); | ||
877 | if (err) | ||
878 | goto err_free; | ||
879 | |||
880 | err = sysfs_create_group(&client->dev.kobj, &amc6821_attr_grp); | ||
881 | if (err) | ||
882 | goto err_free; | ||
883 | |||
884 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
885 | if (!IS_ERR(data->hwmon_dev)) | ||
886 | return 0; | ||
887 | |||
888 | err = PTR_ERR(data->hwmon_dev); | ||
889 | dev_err(&client->dev, "error registering hwmon device.\n"); | ||
890 | sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp); | ||
891 | err_free: | ||
892 | kfree(data); | ||
893 | return err; | ||
894 | } | ||
895 | |||
896 | static int amc6821_remove(struct i2c_client *client) | ||
897 | { | ||
898 | struct amc6821_data *data = i2c_get_clientdata(client); | ||
899 | |||
900 | hwmon_device_unregister(data->hwmon_dev); | ||
901 | sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp); | ||
902 | |||
903 | kfree(data); | ||
904 | |||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | |||
909 | static int amc6821_init_client(struct i2c_client *client) | ||
910 | { | ||
911 | int config; | ||
912 | int err = -EIO; | ||
913 | |||
914 | if (init) { | ||
915 | config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4); | ||
916 | |||
917 | if (config < 0) { | ||
918 | dev_err(&client->dev, | ||
919 | "Error reading configuration register, aborting.\n"); | ||
920 | return err; | ||
921 | } | ||
922 | |||
923 | config |= AMC6821_CONF4_MODE; | ||
924 | |||
925 | if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4, | ||
926 | config)) { | ||
927 | dev_err(&client->dev, | ||
928 | "Configuration register write error, aborting.\n"); | ||
929 | return err; | ||
930 | } | ||
931 | |||
932 | config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF3); | ||
933 | |||
934 | if (config < 0) { | ||
935 | dev_err(&client->dev, | ||
936 | "Error reading configuration register, aborting.\n"); | ||
937 | return err; | ||
938 | } | ||
939 | |||
940 | dev_info(&client->dev, "Revision %d\n", config & 0x0f); | ||
941 | |||
942 | config &= ~AMC6821_CONF3_THERM_FAN_EN; | ||
943 | |||
944 | if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF3, | ||
945 | config)) { | ||
946 | dev_err(&client->dev, | ||
947 | "Configuration register write error, aborting.\n"); | ||
948 | return err; | ||
949 | } | ||
950 | |||
951 | config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF2); | ||
952 | |||
953 | if (config < 0) { | ||
954 | dev_err(&client->dev, | ||
955 | "Error reading configuration register, aborting.\n"); | ||
956 | return err; | ||
957 | } | ||
958 | |||
959 | config &= ~AMC6821_CONF2_RTFIE; | ||
960 | config &= ~AMC6821_CONF2_LTOIE; | ||
961 | config &= ~AMC6821_CONF2_RTOIE; | ||
962 | if (i2c_smbus_write_byte_data(client, | ||
963 | AMC6821_REG_CONF2, config)) { | ||
964 | dev_err(&client->dev, | ||
965 | "Configuration register write error, aborting.\n"); | ||
966 | return err; | ||
967 | } | ||
968 | |||
969 | config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1); | ||
970 | |||
971 | if (config < 0) { | ||
972 | dev_err(&client->dev, | ||
973 | "Error reading configuration register, aborting.\n"); | ||
974 | return err; | ||
975 | } | ||
976 | |||
977 | config &= ~AMC6821_CONF1_THERMOVIE; | ||
978 | config &= ~AMC6821_CONF1_FANIE; | ||
979 | config |= AMC6821_CONF1_START; | ||
980 | if (pwminv) | ||
981 | config |= AMC6821_CONF1_PWMINV; | ||
982 | else | ||
983 | config &= ~AMC6821_CONF1_PWMINV; | ||
984 | |||
985 | if (i2c_smbus_write_byte_data( | ||
986 | client, AMC6821_REG_CONF1, config)) { | ||
987 | dev_err(&client->dev, | ||
988 | "Configuration register write error, aborting.\n"); | ||
989 | return err; | ||
990 | } | ||
991 | } | ||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | |||
996 | static struct amc6821_data *amc6821_update_device(struct device *dev) | ||
997 | { | ||
998 | struct i2c_client *client = to_i2c_client(dev); | ||
999 | struct amc6821_data *data = i2c_get_clientdata(client); | ||
1000 | int timeout = HZ; | ||
1001 | u8 reg; | ||
1002 | int i; | ||
1003 | |||
1004 | mutex_lock(&data->update_lock); | ||
1005 | |||
1006 | if (time_after(jiffies, data->last_updated + timeout) || | ||
1007 | !data->valid) { | ||
1008 | |||
1009 | for (i = 0; i < TEMP_IDX_LEN; i++) | ||
1010 | data->temp[i] = i2c_smbus_read_byte_data(client, | ||
1011 | temp_reg[i]); | ||
1012 | |||
1013 | data->stat1 = i2c_smbus_read_byte_data(client, | ||
1014 | AMC6821_REG_STAT1); | ||
1015 | data->stat2 = i2c_smbus_read_byte_data(client, | ||
1016 | AMC6821_REG_STAT2); | ||
1017 | |||
1018 | data->pwm1 = i2c_smbus_read_byte_data(client, | ||
1019 | AMC6821_REG_DCY); | ||
1020 | for (i = 0; i < FAN1_IDX_LEN; i++) { | ||
1021 | data->fan[i] = i2c_smbus_read_byte_data( | ||
1022 | client, | ||
1023 | fan_reg_low[i]); | ||
1024 | data->fan[i] += i2c_smbus_read_byte_data( | ||
1025 | client, | ||
1026 | fan_reg_hi[i]) << 8; | ||
1027 | } | ||
1028 | data->fan1_div = i2c_smbus_read_byte_data(client, | ||
1029 | AMC6821_REG_CONF4); | ||
1030 | data->fan1_div = data->fan1_div & AMC6821_CONF4_PSPR ? 4 : 2; | ||
1031 | |||
1032 | data->pwm1_auto_point_pwm[0] = 0; | ||
1033 | data->pwm1_auto_point_pwm[2] = 255; | ||
1034 | data->pwm1_auto_point_pwm[1] = i2c_smbus_read_byte_data(client, | ||
1035 | AMC6821_REG_DCY_LOW_TEMP); | ||
1036 | |||
1037 | data->temp1_auto_point_temp[0] = | ||
1038 | i2c_smbus_read_byte_data(client, | ||
1039 | AMC6821_REG_PSV_TEMP); | ||
1040 | data->temp2_auto_point_temp[0] = | ||
1041 | data->temp1_auto_point_temp[0]; | ||
1042 | reg = i2c_smbus_read_byte_data(client, | ||
1043 | AMC6821_REG_LTEMP_FAN_CTRL); | ||
1044 | data->temp1_auto_point_temp[1] = (reg & 0xF8) >> 1; | ||
1045 | reg &= 0x07; | ||
1046 | reg = 0x20 >> reg; | ||
1047 | if (reg > 0) | ||
1048 | data->temp1_auto_point_temp[2] = | ||
1049 | data->temp1_auto_point_temp[1] + | ||
1050 | (data->pwm1_auto_point_pwm[2] - | ||
1051 | data->pwm1_auto_point_pwm[1]) / reg; | ||
1052 | else | ||
1053 | data->temp1_auto_point_temp[2] = 255; | ||
1054 | |||
1055 | reg = i2c_smbus_read_byte_data(client, | ||
1056 | AMC6821_REG_RTEMP_FAN_CTRL); | ||
1057 | data->temp2_auto_point_temp[1] = (reg & 0xF8) >> 1; | ||
1058 | reg &= 0x07; | ||
1059 | reg = 0x20 >> reg; | ||
1060 | if (reg > 0) | ||
1061 | data->temp2_auto_point_temp[2] = | ||
1062 | data->temp2_auto_point_temp[1] + | ||
1063 | (data->pwm1_auto_point_pwm[2] - | ||
1064 | data->pwm1_auto_point_pwm[1]) / reg; | ||
1065 | else | ||
1066 | data->temp2_auto_point_temp[2] = 255; | ||
1067 | |||
1068 | reg = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1); | ||
1069 | reg = (reg >> 5) & 0x3; | ||
1070 | switch (reg) { | ||
1071 | case 0: /*open loop: software sets pwm1*/ | ||
1072 | data->pwm1_auto_channels_temp = 0; | ||
1073 | data->pwm1_enable = 1; | ||
1074 | break; | ||
1075 | case 2: /*closed loop: remote T (temp2)*/ | ||
1076 | data->pwm1_auto_channels_temp = 2; | ||
1077 | data->pwm1_enable = 2; | ||
1078 | break; | ||
1079 | case 3: /*closed loop: local and remote T (temp2)*/ | ||
1080 | data->pwm1_auto_channels_temp = 3; | ||
1081 | data->pwm1_enable = 3; | ||
1082 | break; | ||
1083 | case 1: /*semi-open loop: software sets rpm, chip controls pwm1, | ||
1084 | *currently not implemented | ||
1085 | */ | ||
1086 | data->pwm1_auto_channels_temp = 0; | ||
1087 | data->pwm1_enable = 0; | ||
1088 | break; | ||
1089 | } | ||
1090 | |||
1091 | data->last_updated = jiffies; | ||
1092 | data->valid = 1; | ||
1093 | } | ||
1094 | mutex_unlock(&data->update_lock); | ||
1095 | return data; | ||
1096 | } | ||
1097 | |||
1098 | |||
1099 | static int __init amc6821_init(void) | ||
1100 | { | ||
1101 | return i2c_add_driver(&amc6821_driver); | ||
1102 | } | ||
1103 | |||
1104 | static void __exit amc6821_exit(void) | ||
1105 | { | ||
1106 | i2c_del_driver(&amc6821_driver); | ||
1107 | } | ||
1108 | |||
1109 | module_init(amc6821_init); | ||
1110 | module_exit(amc6821_exit); | ||
1111 | |||
1112 | |||
1113 | MODULE_LICENSE("GPL"); | ||
1114 | MODULE_AUTHOR("T. Mertelj <tomaz.mertelj@guest.arnes.si>"); | ||
1115 | MODULE_DESCRIPTION("Texas Instruments amc6821 hwmon driver"); | ||
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 5a3ee00c0e7d..028284f544e3 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * See COPYING in the top level directory of the kernel tree. | 5 | * See COPYING in the top level directory of the kernel tree. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/debugfs.h> | ||
8 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
9 | #include <linux/hwmon.h> | 10 | #include <linux/hwmon.h> |
10 | #include <linux/list.h> | 11 | #include <linux/list.h> |
@@ -101,6 +102,11 @@ struct atk_data { | |||
101 | int temperature_count; | 102 | int temperature_count; |
102 | int fan_count; | 103 | int fan_count; |
103 | struct list_head sensor_list; | 104 | struct list_head sensor_list; |
105 | |||
106 | struct { | ||
107 | struct dentry *root; | ||
108 | u32 id; | ||
109 | } debugfs; | ||
104 | }; | 110 | }; |
105 | 111 | ||
106 | 112 | ||
@@ -624,6 +630,187 @@ static int atk_read_value(struct atk_sensor_data *sensor, u64 *value) | |||
624 | return err; | 630 | return err; |
625 | } | 631 | } |
626 | 632 | ||
633 | #ifdef CONFIG_DEBUG_FS | ||
634 | static int atk_debugfs_gitm_get(void *p, u64 *val) | ||
635 | { | ||
636 | struct atk_data *data = p; | ||
637 | union acpi_object *ret; | ||
638 | struct atk_acpi_ret_buffer *buf; | ||
639 | int err = 0; | ||
640 | |||
641 | if (!data->read_handle) | ||
642 | return -ENODEV; | ||
643 | |||
644 | if (!data->debugfs.id) | ||
645 | return -EINVAL; | ||
646 | |||
647 | ret = atk_gitm(data, data->debugfs.id); | ||
648 | if (IS_ERR(ret)) | ||
649 | return PTR_ERR(ret); | ||
650 | |||
651 | buf = (struct atk_acpi_ret_buffer *)ret->buffer.pointer; | ||
652 | if (buf->flags) | ||
653 | *val = buf->value; | ||
654 | else | ||
655 | err = -EIO; | ||
656 | |||
657 | return err; | ||
658 | } | ||
659 | |||
660 | DEFINE_SIMPLE_ATTRIBUTE(atk_debugfs_gitm, | ||
661 | atk_debugfs_gitm_get, | ||
662 | NULL, | ||
663 | "0x%08llx\n") | ||
664 | |||
665 | static int atk_acpi_print(char *buf, size_t sz, union acpi_object *obj) | ||
666 | { | ||
667 | int ret = 0; | ||
668 | |||
669 | switch (obj->type) { | ||
670 | case ACPI_TYPE_INTEGER: | ||
671 | ret = snprintf(buf, sz, "0x%08llx\n", obj->integer.value); | ||
672 | break; | ||
673 | case ACPI_TYPE_STRING: | ||
674 | ret = snprintf(buf, sz, "%s\n", obj->string.pointer); | ||
675 | break; | ||
676 | } | ||
677 | |||
678 | return ret; | ||
679 | } | ||
680 | |||
681 | static void atk_pack_print(char *buf, size_t sz, union acpi_object *pack) | ||
682 | { | ||
683 | int ret; | ||
684 | int i; | ||
685 | |||
686 | for (i = 0; i < pack->package.count; i++) { | ||
687 | union acpi_object *obj = &pack->package.elements[i]; | ||
688 | |||
689 | ret = atk_acpi_print(buf, sz, obj); | ||
690 | if (ret >= sz) | ||
691 | break; | ||
692 | buf += ret; | ||
693 | sz -= ret; | ||
694 | } | ||
695 | } | ||
696 | |||
697 | static int atk_debugfs_ggrp_open(struct inode *inode, struct file *file) | ||
698 | { | ||
699 | struct atk_data *data = inode->i_private; | ||
700 | char *buf = NULL; | ||
701 | union acpi_object *ret; | ||
702 | u8 cls; | ||
703 | int i; | ||
704 | |||
705 | if (!data->enumerate_handle) | ||
706 | return -ENODEV; | ||
707 | if (!data->debugfs.id) | ||
708 | return -EINVAL; | ||
709 | |||
710 | cls = (data->debugfs.id & 0xff000000) >> 24; | ||
711 | ret = atk_ggrp(data, cls); | ||
712 | if (IS_ERR(ret)) | ||
713 | return PTR_ERR(ret); | ||
714 | |||
715 | for (i = 0; i < ret->package.count; i++) { | ||
716 | union acpi_object *pack = &ret->package.elements[i]; | ||
717 | union acpi_object *id; | ||
718 | |||
719 | if (pack->type != ACPI_TYPE_PACKAGE) | ||
720 | continue; | ||
721 | if (!pack->package.count) | ||
722 | continue; | ||
723 | id = &pack->package.elements[0]; | ||
724 | if (id->integer.value == data->debugfs.id) { | ||
725 | /* Print the package */ | ||
726 | buf = kzalloc(512, GFP_KERNEL); | ||
727 | if (!buf) { | ||
728 | ACPI_FREE(ret); | ||
729 | return -ENOMEM; | ||
730 | } | ||
731 | atk_pack_print(buf, 512, pack); | ||
732 | break; | ||
733 | } | ||
734 | } | ||
735 | ACPI_FREE(ret); | ||
736 | |||
737 | if (!buf) | ||
738 | return -EINVAL; | ||
739 | |||
740 | file->private_data = buf; | ||
741 | |||
742 | return nonseekable_open(inode, file); | ||
743 | } | ||
744 | |||
745 | static ssize_t atk_debugfs_ggrp_read(struct file *file, char __user *buf, | ||
746 | size_t count, loff_t *pos) | ||
747 | { | ||
748 | char *str = file->private_data; | ||
749 | size_t len = strlen(str); | ||
750 | |||
751 | return simple_read_from_buffer(buf, count, pos, str, len); | ||
752 | } | ||
753 | |||
754 | static int atk_debugfs_ggrp_release(struct inode *inode, struct file *file) | ||
755 | { | ||
756 | kfree(file->private_data); | ||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | static const struct file_operations atk_debugfs_ggrp_fops = { | ||
761 | .read = atk_debugfs_ggrp_read, | ||
762 | .open = atk_debugfs_ggrp_open, | ||
763 | .release = atk_debugfs_ggrp_release, | ||
764 | }; | ||
765 | |||
766 | static void atk_debugfs_init(struct atk_data *data) | ||
767 | { | ||
768 | struct dentry *d; | ||
769 | struct dentry *f; | ||
770 | |||
771 | data->debugfs.id = 0; | ||
772 | |||
773 | d = debugfs_create_dir("asus_atk0110", NULL); | ||
774 | if (!d || IS_ERR(d)) | ||
775 | return; | ||
776 | |||
777 | f = debugfs_create_x32("id", S_IRUSR | S_IWUSR, d, &data->debugfs.id); | ||
778 | if (!f || IS_ERR(f)) | ||
779 | goto cleanup; | ||
780 | |||
781 | f = debugfs_create_file("gitm", S_IRUSR, d, data, | ||
782 | &atk_debugfs_gitm); | ||
783 | if (!f || IS_ERR(f)) | ||
784 | goto cleanup; | ||
785 | |||
786 | f = debugfs_create_file("ggrp", S_IRUSR, d, data, | ||
787 | &atk_debugfs_ggrp_fops); | ||
788 | if (!f || IS_ERR(f)) | ||
789 | goto cleanup; | ||
790 | |||
791 | data->debugfs.root = d; | ||
792 | |||
793 | return; | ||
794 | cleanup: | ||
795 | debugfs_remove_recursive(d); | ||
796 | } | ||
797 | |||
798 | static void atk_debugfs_cleanup(struct atk_data *data) | ||
799 | { | ||
800 | debugfs_remove_recursive(data->debugfs.root); | ||
801 | } | ||
802 | |||
803 | #else /* CONFIG_DEBUG_FS */ | ||
804 | |||
805 | static void atk_debugfs_init(struct atk_data *data) | ||
806 | { | ||
807 | } | ||
808 | |||
809 | static void atk_debugfs_cleanup(struct atk_data *data) | ||
810 | { | ||
811 | } | ||
812 | #endif | ||
813 | |||
627 | static int atk_add_sensor(struct atk_data *data, union acpi_object *obj) | 814 | static int atk_add_sensor(struct atk_data *data, union acpi_object *obj) |
628 | { | 815 | { |
629 | struct device *dev = &data->acpi_dev->dev; | 816 | struct device *dev = &data->acpi_dev->dev; |
@@ -1047,76 +1234,75 @@ remove: | |||
1047 | return err; | 1234 | return err; |
1048 | } | 1235 | } |
1049 | 1236 | ||
1050 | static int atk_check_old_if(struct atk_data *data) | 1237 | static int atk_probe_if(struct atk_data *data) |
1051 | { | 1238 | { |
1052 | struct device *dev = &data->acpi_dev->dev; | 1239 | struct device *dev = &data->acpi_dev->dev; |
1053 | acpi_handle ret; | 1240 | acpi_handle ret; |
1054 | acpi_status status; | 1241 | acpi_status status; |
1242 | int err = 0; | ||
1055 | 1243 | ||
1056 | /* RTMP: read temperature */ | 1244 | /* RTMP: read temperature */ |
1057 | status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret); | 1245 | status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret); |
1058 | if (status != AE_OK) { | 1246 | if (ACPI_SUCCESS(status)) |
1247 | data->rtmp_handle = ret; | ||
1248 | else | ||
1059 | dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n", | 1249 | dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n", |
1060 | acpi_format_exception(status)); | 1250 | acpi_format_exception(status)); |
1061 | return -ENODEV; | ||
1062 | } | ||
1063 | data->rtmp_handle = ret; | ||
1064 | 1251 | ||
1065 | /* RVLT: read voltage */ | 1252 | /* RVLT: read voltage */ |
1066 | status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret); | 1253 | status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret); |
1067 | if (status != AE_OK) { | 1254 | if (ACPI_SUCCESS(status)) |
1255 | data->rvlt_handle = ret; | ||
1256 | else | ||
1068 | dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n", | 1257 | dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n", |
1069 | acpi_format_exception(status)); | 1258 | acpi_format_exception(status)); |
1070 | return -ENODEV; | ||
1071 | } | ||
1072 | data->rvlt_handle = ret; | ||
1073 | 1259 | ||
1074 | /* RFAN: read fan status */ | 1260 | /* RFAN: read fan status */ |
1075 | status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret); | 1261 | status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret); |
1076 | if (status != AE_OK) { | 1262 | if (ACPI_SUCCESS(status)) |
1263 | data->rfan_handle = ret; | ||
1264 | else | ||
1077 | dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n", | 1265 | dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n", |
1078 | acpi_format_exception(status)); | 1266 | acpi_format_exception(status)); |
1079 | return -ENODEV; | ||
1080 | } | ||
1081 | data->rfan_handle = ret; | ||
1082 | |||
1083 | return 0; | ||
1084 | } | ||
1085 | |||
1086 | static int atk_check_new_if(struct atk_data *data) | ||
1087 | { | ||
1088 | struct device *dev = &data->acpi_dev->dev; | ||
1089 | acpi_handle ret; | ||
1090 | acpi_status status; | ||
1091 | 1267 | ||
1092 | /* Enumeration */ | 1268 | /* Enumeration */ |
1093 | status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret); | 1269 | status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret); |
1094 | if (status != AE_OK) { | 1270 | if (ACPI_SUCCESS(status)) |
1271 | data->enumerate_handle = ret; | ||
1272 | else | ||
1095 | dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n", | 1273 | dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n", |
1096 | acpi_format_exception(status)); | 1274 | acpi_format_exception(status)); |
1097 | return -ENODEV; | ||
1098 | } | ||
1099 | data->enumerate_handle = ret; | ||
1100 | 1275 | ||
1101 | /* De-multiplexer (read) */ | 1276 | /* De-multiplexer (read) */ |
1102 | status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret); | 1277 | status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret); |
1103 | if (status != AE_OK) { | 1278 | if (ACPI_SUCCESS(status)) |
1279 | data->read_handle = ret; | ||
1280 | else | ||
1104 | dev_dbg(dev, "method " METHOD_READ " not found: %s\n", | 1281 | dev_dbg(dev, "method " METHOD_READ " not found: %s\n", |
1105 | acpi_format_exception(status)); | 1282 | acpi_format_exception(status)); |
1106 | return -ENODEV; | ||
1107 | } | ||
1108 | data->read_handle = ret; | ||
1109 | 1283 | ||
1110 | /* De-multiplexer (write) */ | 1284 | /* De-multiplexer (write) */ |
1111 | status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret); | 1285 | status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret); |
1112 | if (status != AE_OK) { | 1286 | if (ACPI_SUCCESS(status)) |
1113 | dev_dbg(dev, "method " METHOD_READ " not found: %s\n", | 1287 | data->write_handle = ret; |
1288 | else | ||
1289 | dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n", | ||
1114 | acpi_format_exception(status)); | 1290 | acpi_format_exception(status)); |
1115 | return -ENODEV; | ||
1116 | } | ||
1117 | data->write_handle = ret; | ||
1118 | 1291 | ||
1119 | return 0; | 1292 | /* Check for hwmon methods: first check "old" style methods; note that |
1293 | * both may be present: in this case we stick to the old interface; | ||
1294 | * analysis of multiple DSDTs indicates that when both interfaces | ||
1295 | * are present the new one (GGRP/GITM) is not functional. | ||
1296 | */ | ||
1297 | if (data->rtmp_handle && data->rvlt_handle && data->rfan_handle) | ||
1298 | data->old_interface = true; | ||
1299 | else if (data->enumerate_handle && data->read_handle && | ||
1300 | data->write_handle) | ||
1301 | data->old_interface = false; | ||
1302 | else | ||
1303 | err = -ENODEV; | ||
1304 | |||
1305 | return err; | ||
1120 | } | 1306 | } |
1121 | 1307 | ||
1122 | static int atk_add(struct acpi_device *device) | 1308 | static int atk_add(struct acpi_device *device) |
@@ -1143,40 +1329,30 @@ static int atk_add(struct acpi_device *device) | |||
1143 | &buf, ACPI_TYPE_PACKAGE); | 1329 | &buf, ACPI_TYPE_PACKAGE); |
1144 | if (ret != AE_OK) { | 1330 | if (ret != AE_OK) { |
1145 | dev_dbg(&device->dev, "atk: method MBIF not found\n"); | 1331 | dev_dbg(&device->dev, "atk: method MBIF not found\n"); |
1146 | err = -ENODEV; | 1332 | } else { |
1147 | goto out; | 1333 | obj = buf.pointer; |
1334 | if (obj->package.count >= 2) { | ||
1335 | union acpi_object *id = &obj->package.elements[1]; | ||
1336 | if (id->type == ACPI_TYPE_STRING) | ||
1337 | dev_dbg(&device->dev, "board ID = %s\n", | ||
1338 | id->string.pointer); | ||
1339 | } | ||
1340 | ACPI_FREE(buf.pointer); | ||
1148 | } | 1341 | } |
1149 | 1342 | ||
1150 | obj = buf.pointer; | 1343 | err = atk_probe_if(data); |
1151 | if (obj->package.count >= 2 && | 1344 | if (err) { |
1152 | obj->package.elements[1].type == ACPI_TYPE_STRING) { | 1345 | dev_err(&device->dev, "No usable hwmon interface detected\n"); |
1153 | dev_dbg(&device->dev, "board ID = %s\n", | 1346 | goto out; |
1154 | obj->package.elements[1].string.pointer); | ||
1155 | } | 1347 | } |
1156 | ACPI_FREE(buf.pointer); | ||
1157 | 1348 | ||
1158 | /* Check for hwmon methods: first check "old" style methods; note that | 1349 | if (data->old_interface) { |
1159 | * both may be present: in this case we stick to the old interface; | ||
1160 | * analysis of multiple DSDTs indicates that when both interfaces | ||
1161 | * are present the new one (GGRP/GITM) is not functional. | ||
1162 | */ | ||
1163 | err = atk_check_old_if(data); | ||
1164 | if (!err) { | ||
1165 | dev_dbg(&device->dev, "Using old hwmon interface\n"); | 1350 | dev_dbg(&device->dev, "Using old hwmon interface\n"); |
1166 | data->old_interface = true; | 1351 | err = atk_enumerate_old_hwmon(data); |
1167 | } else { | 1352 | } else { |
1168 | err = atk_check_new_if(data); | ||
1169 | if (err) | ||
1170 | goto out; | ||
1171 | |||
1172 | dev_dbg(&device->dev, "Using new hwmon interface\n"); | 1353 | dev_dbg(&device->dev, "Using new hwmon interface\n"); |
1173 | data->old_interface = false; | ||
1174 | } | ||
1175 | |||
1176 | if (data->old_interface) | ||
1177 | err = atk_enumerate_old_hwmon(data); | ||
1178 | else | ||
1179 | err = atk_enumerate_new_hwmon(data); | 1354 | err = atk_enumerate_new_hwmon(data); |
1355 | } | ||
1180 | if (err < 0) | 1356 | if (err < 0) |
1181 | goto out; | 1357 | goto out; |
1182 | if (err == 0) { | 1358 | if (err == 0) { |
@@ -1190,6 +1366,8 @@ static int atk_add(struct acpi_device *device) | |||
1190 | if (err) | 1366 | if (err) |
1191 | goto cleanup; | 1367 | goto cleanup; |
1192 | 1368 | ||
1369 | atk_debugfs_init(data); | ||
1370 | |||
1193 | device->driver_data = data; | 1371 | device->driver_data = data; |
1194 | return 0; | 1372 | return 0; |
1195 | cleanup: | 1373 | cleanup: |
@@ -1208,6 +1386,8 @@ static int atk_remove(struct acpi_device *device, int type) | |||
1208 | 1386 | ||
1209 | device->driver_data = NULL; | 1387 | device->driver_data = NULL; |
1210 | 1388 | ||
1389 | atk_debugfs_cleanup(data); | ||
1390 | |||
1211 | atk_remove_files(data); | 1391 | atk_remove_files(data); |
1212 | atk_free_sensors(data); | 1392 | atk_free_sensors(data); |
1213 | hwmon_device_unregister(data->hwmon_dev); | 1393 | hwmon_device_unregister(data->hwmon_dev); |
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index caef39cda8c8..2d7bceeed0bc 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/list.h> | 33 | #include <linux/list.h> |
34 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
35 | #include <linux/cpu.h> | 35 | #include <linux/cpu.h> |
36 | #include <linux/pci.h> | ||
36 | #include <asm/msr.h> | 37 | #include <asm/msr.h> |
37 | #include <asm/processor.h> | 38 | #include <asm/processor.h> |
38 | 39 | ||
@@ -161,6 +162,7 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device * | |||
161 | int usemsr_ee = 1; | 162 | int usemsr_ee = 1; |
162 | int err; | 163 | int err; |
163 | u32 eax, edx; | 164 | u32 eax, edx; |
165 | struct pci_dev *host_bridge; | ||
164 | 166 | ||
165 | /* Early chips have no MSR for TjMax */ | 167 | /* Early chips have no MSR for TjMax */ |
166 | 168 | ||
@@ -168,11 +170,21 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device * | |||
168 | usemsr_ee = 0; | 170 | usemsr_ee = 0; |
169 | } | 171 | } |
170 | 172 | ||
171 | /* Atoms seems to have TjMax at 90C */ | 173 | /* Atom CPUs */ |
172 | 174 | ||
173 | if (c->x86_model == 0x1c) { | 175 | if (c->x86_model == 0x1c) { |
174 | usemsr_ee = 0; | 176 | usemsr_ee = 0; |
175 | tjmax = 90000; | 177 | |
178 | host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); | ||
179 | |||
180 | if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL | ||
181 | && (host_bridge->device == 0xa000 /* NM10 based nettop */ | ||
182 | || host_bridge->device == 0xa010)) /* NM10 based netbook */ | ||
183 | tjmax = 100000; | ||
184 | else | ||
185 | tjmax = 90000; | ||
186 | |||
187 | pci_dev_put(host_bridge); | ||
176 | } | 188 | } |
177 | 189 | ||
178 | if ((c->x86_model > 0xe) && (usemsr_ee)) { | 190 | if ((c->x86_model > 0xe) && (usemsr_ee)) { |
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index bd0fc67e804b..fa0728232e71 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c | |||
@@ -768,6 +768,7 @@ leave: | |||
768 | static int watchdog_open(struct inode *inode, struct file *filp) | 768 | static int watchdog_open(struct inode *inode, struct file *filp) |
769 | { | 769 | { |
770 | struct fschmd_data *pos, *data = NULL; | 770 | struct fschmd_data *pos, *data = NULL; |
771 | int watchdog_is_open; | ||
771 | 772 | ||
772 | /* We get called from drivers/char/misc.c with misc_mtx hold, and we | 773 | /* We get called from drivers/char/misc.c with misc_mtx hold, and we |
773 | call misc_register() from fschmd_probe() with watchdog_data_mutex | 774 | call misc_register() from fschmd_probe() with watchdog_data_mutex |
@@ -782,10 +783,12 @@ static int watchdog_open(struct inode *inode, struct file *filp) | |||
782 | } | 783 | } |
783 | } | 784 | } |
784 | /* Note we can never not have found data, so we don't check for this */ | 785 | /* Note we can never not have found data, so we don't check for this */ |
785 | kref_get(&data->kref); | 786 | watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open); |
787 | if (!watchdog_is_open) | ||
788 | kref_get(&data->kref); | ||
786 | mutex_unlock(&watchdog_data_mutex); | 789 | mutex_unlock(&watchdog_data_mutex); |
787 | 790 | ||
788 | if (test_and_set_bit(0, &data->watchdog_is_open)) | 791 | if (watchdog_is_open) |
789 | return -EBUSY; | 792 | return -EBUSY; |
790 | 793 | ||
791 | /* Start the watchdog */ | 794 | /* Start the watchdog */ |
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index d8a26d16d948..099a2138cdf6 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c | |||
@@ -33,6 +33,16 @@ static bool force; | |||
33 | module_param(force, bool, 0444); | 33 | module_param(force, bool, 0444); |
34 | MODULE_PARM_DESC(force, "force loading on processors with erratum 319"); | 34 | MODULE_PARM_DESC(force, "force loading on processors with erratum 319"); |
35 | 35 | ||
36 | /* CPUID function 0x80000001, ebx */ | ||
37 | #define CPUID_PKGTYPE_MASK 0xf0000000 | ||
38 | #define CPUID_PKGTYPE_F 0x00000000 | ||
39 | #define CPUID_PKGTYPE_AM2R2_AM3 0x10000000 | ||
40 | |||
41 | /* DRAM controller (PCI function 2) */ | ||
42 | #define REG_DCT0_CONFIG_HIGH 0x094 | ||
43 | #define DDR3_MODE 0x00000100 | ||
44 | |||
45 | /* miscellaneous (PCI function 3) */ | ||
36 | #define REG_HARDWARE_THERMAL_CONTROL 0x64 | 46 | #define REG_HARDWARE_THERMAL_CONTROL 0x64 |
37 | #define HTC_ENABLE 0x00000001 | 47 | #define HTC_ENABLE 0x00000001 |
38 | 48 | ||
@@ -85,13 +95,28 @@ static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); | |||
85 | static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1); | 95 | static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1); |
86 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 96 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
87 | 97 | ||
88 | static bool __devinit has_erratum_319(void) | 98 | static bool __devinit has_erratum_319(struct pci_dev *pdev) |
89 | { | 99 | { |
100 | u32 pkg_type, reg_dram_cfg; | ||
101 | |||
102 | if (boot_cpu_data.x86 != 0x10) | ||
103 | return false; | ||
104 | |||
90 | /* | 105 | /* |
91 | * Erratum 319: The thermal sensor of older Family 10h processors | 106 | * Erratum 319: The thermal sensor of Socket F/AM2+ processors |
92 | * (B steppings) may be unreliable. | 107 | * may be unreliable. |
93 | */ | 108 | */ |
94 | return boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model <= 2; | 109 | pkg_type = cpuid_ebx(0x80000001) & CPUID_PKGTYPE_MASK; |
110 | if (pkg_type == CPUID_PKGTYPE_F) | ||
111 | return true; | ||
112 | if (pkg_type != CPUID_PKGTYPE_AM2R2_AM3) | ||
113 | return false; | ||
114 | |||
115 | /* Differentiate between AM2+ (bad) and AM3 (good) */ | ||
116 | pci_bus_read_config_dword(pdev->bus, | ||
117 | PCI_DEVFN(PCI_SLOT(pdev->devfn), 2), | ||
118 | REG_DCT0_CONFIG_HIGH, ®_dram_cfg); | ||
119 | return !(reg_dram_cfg & DDR3_MODE); | ||
95 | } | 120 | } |
96 | 121 | ||
97 | static int __devinit k10temp_probe(struct pci_dev *pdev, | 122 | static int __devinit k10temp_probe(struct pci_dev *pdev, |
@@ -99,9 +124,10 @@ static int __devinit k10temp_probe(struct pci_dev *pdev, | |||
99 | { | 124 | { |
100 | struct device *hwmon_dev; | 125 | struct device *hwmon_dev; |
101 | u32 reg_caps, reg_htc; | 126 | u32 reg_caps, reg_htc; |
127 | int unreliable = has_erratum_319(pdev); | ||
102 | int err; | 128 | int err; |
103 | 129 | ||
104 | if (has_erratum_319() && !force) { | 130 | if (unreliable && !force) { |
105 | dev_err(&pdev->dev, | 131 | dev_err(&pdev->dev, |
106 | "unreliable CPU thermal sensor; monitoring disabled\n"); | 132 | "unreliable CPU thermal sensor; monitoring disabled\n"); |
107 | err = -ENODEV; | 133 | err = -ENODEV; |
@@ -139,7 +165,7 @@ static int __devinit k10temp_probe(struct pci_dev *pdev, | |||
139 | } | 165 | } |
140 | dev_set_drvdata(&pdev->dev, hwmon_dev); | 166 | dev_set_drvdata(&pdev->dev, hwmon_dev); |
141 | 167 | ||
142 | if (has_erratum_319() && force) | 168 | if (unreliable && force) |
143 | dev_warn(&pdev->dev, | 169 | dev_warn(&pdev->dev, |
144 | "unreliable CPU thermal sensor; check erratum 319\n"); | 170 | "unreliable CPU thermal sensor; check erratum 319\n"); |
145 | return 0; | 171 | return 0; |
@@ -169,7 +195,7 @@ static void __devexit k10temp_remove(struct pci_dev *pdev) | |||
169 | dev_set_drvdata(&pdev->dev, NULL); | 195 | dev_set_drvdata(&pdev->dev, NULL); |
170 | } | 196 | } |
171 | 197 | ||
172 | static struct pci_device_id k10temp_id_table[] = { | 198 | static const struct pci_device_id k10temp_id_table[] = { |
173 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) }, | 199 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) }, |
174 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) }, | 200 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) }, |
175 | {} | 201 | {} |
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index 1fe995111841..0ceb6d6200a3 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c | |||
@@ -136,7 +136,7 @@ static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0); | |||
136 | static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1); | 136 | static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1); |
137 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 137 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
138 | 138 | ||
139 | static struct pci_device_id k8temp_ids[] = { | 139 | static const struct pci_device_id k8temp_ids[] = { |
140 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, | 140 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, |
141 | { 0 }, | 141 | { 0 }, |
142 | }; | 142 | }; |
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 12f2e7086560..79c2931e3008 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c | |||
@@ -697,7 +697,7 @@ static struct sis5595_data *sis5595_update_device(struct device *dev) | |||
697 | return data; | 697 | return data; |
698 | } | 698 | } |
699 | 699 | ||
700 | static struct pci_device_id sis5595_pci_ids[] = { | 700 | static const struct pci_device_id sis5595_pci_ids[] = { |
701 | { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, | 701 | { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, |
702 | { 0, } | 702 | { 0, } |
703 | }; | 703 | }; |
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 9ca97818bd4b..8fa462f2b570 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c | |||
@@ -488,7 +488,7 @@ static int __init smsc47m1_find(unsigned short *addr, | |||
488 | } | 488 | } |
489 | 489 | ||
490 | /* Restore device to its initial state */ | 490 | /* Restore device to its initial state */ |
491 | static void __init smsc47m1_restore(const struct smsc47m1_sio_data *sio_data) | 491 | static void smsc47m1_restore(const struct smsc47m1_sio_data *sio_data) |
492 | { | 492 | { |
493 | if ((sio_data->activate & 0x01) == 0) { | 493 | if ((sio_data->activate & 0x01) == 0) { |
494 | superio_enter(); | 494 | superio_enter(); |
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 39e82a492f26..f397ce7ad598 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c | |||
@@ -767,7 +767,7 @@ static struct via686a_data *via686a_update_device(struct device *dev) | |||
767 | return data; | 767 | return data; |
768 | } | 768 | } |
769 | 769 | ||
770 | static struct pci_device_id via686a_pci_ids[] = { | 770 | static const struct pci_device_id via686a_pci_ids[] = { |
771 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, | 771 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, |
772 | { 0, } | 772 | { 0, } |
773 | }; | 773 | }; |
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 470a1226ba2b..d47b4c9949c2 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c | |||
@@ -697,7 +697,7 @@ static struct platform_driver vt8231_driver = { | |||
697 | .remove = __devexit_p(vt8231_remove), | 697 | .remove = __devexit_p(vt8231_remove), |
698 | }; | 698 | }; |
699 | 699 | ||
700 | static struct pci_device_id vt8231_pci_ids[] = { | 700 | static const struct pci_device_id vt8231_pci_ids[] = { |
701 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4) }, | 701 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4) }, |
702 | { 0, } | 702 | { 0, } |
703 | }; | 703 | }; |