aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorentin Labbe <corentin.labbe@geomatys.fr>2007-02-14 15:15:04 -0500
committerJean Delvare <khali@arrakis.delvare>2007-02-14 15:15:04 -0500
commitcae2caae78258d623c7b687029a19fa6b33c76f4 (patch)
treed88452d8aff1fb6f0619bbbe4d37baf48cfa9bb8
parent657c93b10fac97467cdf1d0424a209ce2e81991a (diff)
hwmon: New driver for the Analog Devices ADM1029
Signed-off-by: Corentin Labbe <corentin.labbe@geomatys.fr> Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r--MAINTAINERS6
-rw-r--r--drivers/hwmon/Kconfig11
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/adm1029.c508
4 files changed, 526 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 93a338daedd8..0556a8de857c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -268,6 +268,12 @@ M: khali@linux-fr.org
268L: lm-sensors@lm-sensors.org 268L: lm-sensors@lm-sensors.org
269S: Maintained 269S: Maintained
270 270
271ADM1029 HARDWARE MONITOR DRIVER
272P: Corentin Labbe
273M: corentin.labbe@geomatys.fr
274L: lm-sensors@lm-sensors.org
275S: Maintained
276
271ADT746X FAN DRIVER 277ADT746X FAN DRIVER
272P: Colin Leroy 278P: Colin Leroy
273M: colin@colino.net 279M: colin@colino.net
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 891ef6d0b1bf..c3d4856fb618 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -73,6 +73,17 @@ config SENSORS_ADM1026
73 This driver can also be built as a module. If so, the module 73 This driver can also be built as a module. If so, the module
74 will be called adm1026. 74 will be called adm1026.
75 75
76config SENSORS_ADM1029
77 tristate "Analog Devices ADM1029"
78 depends on HWMON && I2C && EXPERIMENTAL
79 help
80 If you say yes here you get support for Analog Devices ADM1029
81 sensor chip.
82 Very rare chip, please let us know you use it.
83
84 This driver can also be built as a module. If so, the module
85 will be called adm1029.
86
76config SENSORS_ADM1031 87config SENSORS_ADM1031
77 tristate "Analog Devices ADM1031 and compatibles" 88 tristate "Analog Devices ADM1031 and compatibles"
78 depends on HWMON && I2C && EXPERIMENTAL 89 depends on HWMON && I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 31661124271e..4165c27a2f25 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
17obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o 17obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
18obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o 18obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
19obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o 19obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
20obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
20obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o 21obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
21obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o 22obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
22obj-$(CONFIG_SENSORS_AMS) += ams/ 23obj-$(CONFIG_SENSORS_AMS) += ams/
diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c
new file mode 100644
index 000000000000..73ce31b31511
--- /dev/null
+++ b/drivers/hwmon/adm1029.c
@@ -0,0 +1,508 @@
1/*
2 * adm1029.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
3 *
4 * Copyright (C) 2006 Corentin LABBE <corentin.labbe@geomatys.fr>
5 *
6 * Based on LM83 Driver by Jean Delvare <khali@linux-fr.org>
7 *
8 * Give only processor, motherboard temperatures and fan tachs
9 * Very rare chip please let me know if you use it
10 *
11 * http://www.analog.com/UploadedFiles/Data_Sheets/ADM1029.pdf
12 *
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation version 2 of the License
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
28#include <linux/module.h>
29#include <linux/init.h>
30#include <linux/slab.h>
31#include <linux/jiffies.h>
32#include <linux/i2c.h>
33#include <linux/hwmon-sysfs.h>
34#include <linux/hwmon.h>
35#include <linux/err.h>
36#include <linux/mutex.h>
37
38/*
39 * Addresses to scan
40 */
41
42static unsigned short normal_i2c[] = {
43 0x28, 0x29, 0x2a,
44 0x2b, 0x2c, 0x2d,
45 0x2e, 0x2f, I2C_CLIENT_END
46};
47
48/*
49 * Insmod parameters
50 */
51
52I2C_CLIENT_INSMOD_1(adm1029);
53
54/*
55 * The ADM1029 registers
56 * Manufacturer ID is 0x41 for Analog Devices
57 */
58
59#define ADM1029_REG_MAN_ID 0x0D
60#define ADM1029_REG_CHIP_ID 0x0E
61#define ADM1029_REG_CONFIG 0x01
62#define ADM1029_REG_NB_FAN_SUPPORT 0x02
63
64#define ADM1029_REG_TEMP_DEVICES_INSTALLED 0x06
65
66#define ADM1029_REG_LOCAL_TEMP 0xA0
67#define ADM1029_REG_REMOTE1_TEMP 0xA1
68#define ADM1029_REG_REMOTE2_TEMP 0xA2
69
70#define ADM1029_REG_LOCAL_TEMP_HIGH 0x90
71#define ADM1029_REG_REMOTE1_TEMP_HIGH 0x91
72#define ADM1029_REG_REMOTE2_TEMP_HIGH 0x92
73
74#define ADM1029_REG_LOCAL_TEMP_LOW 0x98
75#define ADM1029_REG_REMOTE1_TEMP_LOW 0x99
76#define ADM1029_REG_REMOTE2_TEMP_LOW 0x9A
77
78#define ADM1029_REG_FAN1 0x70
79#define ADM1029_REG_FAN2 0x71
80
81#define ADM1029_REG_FAN1_MIN 0x78
82#define ADM1029_REG_FAN2_MIN 0x79
83
84#define ADM1029_REG_FAN1_CONFIG 0x68
85#define ADM1029_REG_FAN2_CONFIG 0x69
86
87#define TEMP_FROM_REG(val) ((val) * 1000)
88
89#define DIV_FROM_REG(val) ( 1 << (((val) >> 6) - 1))
90
91/* Registers to be checked by adm1029_update_device() */
92static const u8 ADM1029_REG_TEMP[] = {
93 ADM1029_REG_LOCAL_TEMP,
94 ADM1029_REG_REMOTE1_TEMP,
95 ADM1029_REG_REMOTE2_TEMP,
96 ADM1029_REG_LOCAL_TEMP_HIGH,
97 ADM1029_REG_REMOTE1_TEMP_HIGH,
98 ADM1029_REG_REMOTE2_TEMP_HIGH,
99 ADM1029_REG_LOCAL_TEMP_LOW,
100 ADM1029_REG_REMOTE1_TEMP_LOW,
101 ADM1029_REG_REMOTE2_TEMP_LOW,
102};
103
104static const u8 ADM1029_REG_FAN[] = {
105 ADM1029_REG_FAN1,
106 ADM1029_REG_FAN2,
107 ADM1029_REG_FAN1_MIN,
108 ADM1029_REG_FAN2_MIN,
109};
110
111static const u8 ADM1029_REG_FAN_DIV[] = {
112 ADM1029_REG_FAN1_CONFIG,
113 ADM1029_REG_FAN2_CONFIG,
114};
115
116/*
117 * Functions declaration
118 */
119
120static int adm1029_attach_adapter(struct i2c_adapter *adapter);
121static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind);
122static int adm1029_detach_client(struct i2c_client *client);
123static struct adm1029_data *adm1029_update_device(struct device *dev);
124static int adm1029_init_client(struct i2c_client *client);
125
126/*
127 * Driver data (common to all clients)
128 */
129
130static struct i2c_driver adm1029_driver = {
131 .driver = {
132 .name = "adm1029",
133 },
134 .attach_adapter = adm1029_attach_adapter,
135 .detach_client = adm1029_detach_client,
136};
137
138/*
139 * Client data (each client gets its own)
140 */
141
142struct adm1029_data {
143 struct i2c_client client;
144 struct class_device *class_dev;
145 struct mutex update_lock;
146 char valid; /* zero until following fields are valid */
147 unsigned long last_updated; /* in jiffies */
148
149 /* registers values, signed for temperature, unsigned for other stuff */
150 s8 temp[ARRAY_SIZE(ADM1029_REG_TEMP)];
151 u8 fan[ARRAY_SIZE(ADM1029_REG_FAN)];
152 u8 fan_div[ARRAY_SIZE(ADM1029_REG_FAN_DIV)];
153};
154
155/*
156 * Sysfs stuff
157 */
158
159static ssize_t
160show_temp(struct device *dev, struct device_attribute *devattr, char *buf)
161{
162 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
163 struct adm1029_data *data = adm1029_update_device(dev);
164 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index]));
165}
166
167static ssize_t
168show_fan(struct device *dev, struct device_attribute *devattr, char *buf)
169{
170 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
171 struct adm1029_data *data = adm1029_update_device(dev);
172 u16 val;
173 if (data->fan[attr->index] == 0 || data->fan_div[attr->index] == 0
174 || data->fan[attr->index] == 255) {
175 return sprintf(buf, "0\n");
176 }
177
178 val = 1880 * 120 / DIV_FROM_REG(data->fan_div[attr->index])
179 / data->fan[attr->index];
180 return sprintf(buf, "%d\n", val);
181}
182
183static ssize_t
184show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf)
185{
186 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
187 struct adm1029_data *data = adm1029_update_device(dev);
188 if (data->fan_div[attr->index] == 0)
189 return sprintf(buf, "0\n");
190 return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
191}
192
193static ssize_t set_fan_div(struct device *dev,
194 struct device_attribute *devattr, const char *buf, size_t count)
195{
196 struct i2c_client *client = to_i2c_client(dev);
197 struct adm1029_data *data = i2c_get_clientdata(client);
198 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
199 long val = simple_strtol(buf, NULL, 10);
200 u8 reg;
201
202 mutex_lock(&data->update_lock);
203
204 /*Read actual config */
205 reg = i2c_smbus_read_byte_data(client,
206 ADM1029_REG_FAN_DIV[attr->index]);
207
208 switch (val) {
209 case 1:
210 val = 1;
211 break;
212 case 2:
213 val = 2;
214 break;
215 case 4:
216 val = 3;
217 break;
218 default:
219 mutex_unlock(&data->update_lock);
220 dev_err(&client->dev, "fan_div value %ld not "
221 "supported. Choose one of 1, 2 or 4!\n", val);
222 return -EINVAL;
223 }
224 /* Update the value */
225 reg = (reg & 0x3F) | (val << 6);
226
227 /* Write value */
228 i2c_smbus_write_byte_data(client,
229 ADM1029_REG_FAN_DIV[attr->index], reg);
230 mutex_unlock(&data->update_lock);
231
232 return count;
233}
234
235/*
236Access rights on sysfs, S_IRUGO stand for Is Readable by User, Group and Others
237 S_IWUSR stand for Is Writable by User
238*/
239static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
240static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
241static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
242
243static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, 3);
244static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp, NULL, 4);
245static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp, NULL, 5);
246
247static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp, NULL, 6);
248static SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp, NULL, 7);
249static SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp, NULL, 8);
250
251static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
252static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
253
254static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO, show_fan, NULL, 2);
255static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO, show_fan, NULL, 3);
256
257static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
258 show_fan_div, set_fan_div, 0);
259static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
260 show_fan_div, set_fan_div, 1);
261
262static struct attribute *adm1029_attributes[] = {
263 &sensor_dev_attr_temp1_input.dev_attr.attr,
264 &sensor_dev_attr_temp1_min.dev_attr.attr,
265 &sensor_dev_attr_temp1_max.dev_attr.attr,
266 &sensor_dev_attr_temp2_input.dev_attr.attr,
267 &sensor_dev_attr_temp2_min.dev_attr.attr,
268 &sensor_dev_attr_temp2_max.dev_attr.attr,
269 &sensor_dev_attr_temp3_input.dev_attr.attr,
270 &sensor_dev_attr_temp3_min.dev_attr.attr,
271 &sensor_dev_attr_temp3_max.dev_attr.attr,
272 &sensor_dev_attr_fan1_input.dev_attr.attr,
273 &sensor_dev_attr_fan2_input.dev_attr.attr,
274 &sensor_dev_attr_fan1_min.dev_attr.attr,
275 &sensor_dev_attr_fan2_min.dev_attr.attr,
276 &sensor_dev_attr_fan1_div.dev_attr.attr,
277 &sensor_dev_attr_fan2_div.dev_attr.attr,
278 NULL
279};
280
281static const struct attribute_group adm1029_group = {
282 .attrs = adm1029_attributes,
283};
284
285/*
286 * Real code
287 */
288
289static int adm1029_attach_adapter(struct i2c_adapter *adapter)
290{
291 if (!(adapter->class & I2C_CLASS_HWMON))
292 return 0;
293 return i2c_probe(adapter, &addr_data, adm1029_detect);
294}
295
296/*
297 * The following function does more than just detection. If detection
298 * succeeds, it also registers the new chip.
299 */
300
301static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind)
302{
303 struct i2c_client *client;
304 struct adm1029_data *data;
305 int err = 0;
306 const char *name = "";
307 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
308 goto exit;
309
310 if (!(data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL))) {
311 err = -ENOMEM;
312 goto exit;
313 }
314
315 client = &data->client;
316 i2c_set_clientdata(client, data);
317 client->addr = address;
318 client->adapter = adapter;
319 client->driver = &adm1029_driver;
320
321 /* Now we do the detection and identification. A negative kind
322 * means that the driver was loaded with no force parameter
323 * (default), so we must both detect and identify the chip
324 * (actually there is only one possible kind of chip for now, adm1029).
325 * A zero kind means that the driver was loaded with the force
326 * parameter, the detection step shall be skipped. A positive kind
327 * means that the driver was loaded with the force parameter and a
328 * given kind of chip is requested, so both the detection and the
329 * identification steps are skipped. */
330
331 /* Default to an adm1029 if forced */
332 if (kind == 0)
333 kind = adm1029;
334
335 /* ADM1029 doesn't have CHIP ID, check just MAN ID
336 * For better detection we check also ADM1029_TEMP_DEVICES_INSTALLED,
337 * ADM1029_REG_NB_FAN_SUPPORT and compare it with possible values
338 * documented
339 */
340
341 if (kind <= 0) { /* identification */
342 u8 man_id, chip_id, temp_devices_installed, nb_fan_support;
343
344 man_id = i2c_smbus_read_byte_data(client, ADM1029_REG_MAN_ID);
345 chip_id = i2c_smbus_read_byte_data(client, ADM1029_REG_CHIP_ID);
346 temp_devices_installed = i2c_smbus_read_byte_data(client,
347 ADM1029_REG_TEMP_DEVICES_INSTALLED);
348 nb_fan_support = i2c_smbus_read_byte_data(client,
349 ADM1029_REG_NB_FAN_SUPPORT);
350 /* 0x41 is Analog Devices */
351 if (man_id == 0x41 && (temp_devices_installed & 0xf9) == 0x01
352 && nb_fan_support == 0x03) {
353 if ((chip_id & 0xF0) == 0x00) {
354 kind = adm1029;
355 } else {
356 /* There are no "official" CHIP ID, so actually
357 * we use Major/Minor revision for that */
358 printk(KERN_INFO
359 "adm1029: Unknown major revision %x, "
360 "please let us know\n", chip_id);
361 }
362 }
363
364 if (kind <= 0) { /* identification failed */
365 pr_debug("adm1029: Unsupported chip (man_id=0x%02X, "
366 "chip_id=0x%02X)\n", man_id, chip_id);
367 goto exit_free;
368 }
369 }
370
371 if (kind == adm1029) {
372 name = "adm1029";
373 }
374
375 /* We can fill in the remaining client fields */
376 strlcpy(client->name, name, I2C_NAME_SIZE);
377 mutex_init(&data->update_lock);
378
379 /* Tell the I2C layer a new client has arrived */
380 if ((err = i2c_attach_client(client)))
381 goto exit_free;
382
383 /*
384 * Initialize the ADM1029 chip
385 * Check config register
386 */
387 if (adm1029_init_client(client) == 0)
388 goto exit_detach;
389
390 /* Register sysfs hooks */
391 if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group)))
392 goto exit_detach;
393
394 data->class_dev = hwmon_device_register(&client->dev);
395 if (IS_ERR(data->class_dev)) {
396 err = PTR_ERR(data->class_dev);
397 goto exit_remove_files;
398 }
399
400 return 0;
401
402 exit_remove_files:
403 sysfs_remove_group(&client->dev.kobj, &adm1029_group);
404 exit_detach:
405 i2c_detach_client(client);
406 exit_free:
407 kfree(data);
408 exit:
409 return err;
410}
411
412static int adm1029_init_client(struct i2c_client *client)
413{
414 u8 config;
415 config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
416 if ((config & 0x10) == 0) {
417 i2c_smbus_write_byte_data(client, ADM1029_REG_CONFIG,
418 config | 0x10);
419 }
420 /* recheck config */
421 config = i2c_smbus_read_byte_data(client, ADM1029_REG_CONFIG);
422 if ((config & 0x10) == 0) {
423 dev_err(&client->dev, "Initialization failed!\n");
424 return 0;
425 }
426 return 1;
427}
428
429static int adm1029_detach_client(struct i2c_client *client)
430{
431 struct adm1029_data *data = i2c_get_clientdata(client);
432 int err;
433
434 hwmon_device_unregister(data->class_dev);
435 sysfs_remove_group(&client->dev.kobj, &adm1029_group);
436
437 if ((err = i2c_detach_client(client)))
438 return err;
439
440 kfree(data);
441 return 0;
442}
443
444/*
445function that update the status of the chips (temperature for exemple)
446*/
447static struct adm1029_data *adm1029_update_device(struct device *dev)
448{
449 struct i2c_client *client = to_i2c_client(dev);
450 struct adm1029_data *data = i2c_get_clientdata(client);
451
452 mutex_lock(&data->update_lock);
453 /*
454 * Use the "cache" Luke, don't recheck values
455 * if there are already checked not a long time later
456 */
457 if (time_after(jiffies, data->last_updated + HZ * 2)
458 || !data->valid) {
459 int nr;
460
461 dev_dbg(&client->dev, "Updating adm1029 data\n");
462
463 for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_TEMP); nr++) {
464 data->temp[nr] =
465 i2c_smbus_read_byte_data(client,
466 ADM1029_REG_TEMP[nr]);
467 }
468 for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN); nr++) {
469 data->fan[nr] =
470 i2c_smbus_read_byte_data(client,
471 ADM1029_REG_FAN[nr]);
472 }
473 for (nr = 0; nr < ARRAY_SIZE(ADM1029_REG_FAN_DIV); nr++) {
474 data->fan_div[nr] =
475 i2c_smbus_read_byte_data(client,
476 ADM1029_REG_FAN_DIV[nr]);
477 }
478
479 data->last_updated = jiffies;
480 data->valid = 1;
481 }
482
483 mutex_unlock(&data->update_lock);
484
485 return data;
486}
487
488/*
489 Common module stuff
490*/
491static int __init sensors_adm1029_init(void)
492{
493
494 return i2c_add_driver(&adm1029_driver);
495}
496
497static void __exit sensors_adm1029_exit(void)
498{
499
500 i2c_del_driver(&adm1029_driver);
501}
502
503MODULE_AUTHOR("Corentin LABBE <corentin.labbe@geomatys.fr>");
504MODULE_DESCRIPTION("adm1029 driver");
505MODULE_LICENSE("GPL v2");
506
507module_init(sensors_adm1029_init);
508module_exit(sensors_adm1029_exit);