root/lm-sensors/trunk/kernel/chips/adm9240.c @ 1101

Revision 1101, 27.3 KB (checked in by mds, 14 years ago)

Change from sensors_x to i2c_x for x =

_sysctl_real
_register_entry
_proc_real
_detect
_deregister_entry
_chips_data

which were the global symbols renamed in i2c-proc.[ch] in the
i2c package.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    adm9240.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 1999  Frodo Looijaard <frodol@dds.nl>
5    and Philip Edelbrock <phil@netroedge.com>
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22/* Supports ADM9240, DS1780, and LM81. See doc/chips/adm9240 for details */
23
24/*
25        A couple notes about the ADM9240:
26
27* It claims to be 'LM7x' register compatible.  This must be in reference
28  to only the LM78, because it is missing stuff to emulate LM75's as well.
29  (like the Winbond W83781 does)
30 
31* This driver was written from rev. 0 of the PDF, but it seems well
32  written and complete (unlike the W83781 which is horrible and has
33  supposidly gone through a few revisions.. rev 0 of that one must
34  have been in crayon on construction paper...)
35 
36* All analog inputs can range from 0 to 2.5, eventhough some inputs are
37  marked as being 5V, 12V, etc.  I don't have any real voltages going
38  into my prototype, so I'm not sure that things are computed right,
39  but at least the limits seem to be working OK.
40 
41* Another curiousity is that the fan_div seems to be read-only.  I.e.,
42  any written value to it doesn't seem to make any difference.  The
43  fan_div seems to be 'stuck' at 2 (which isn't a bad value in most cases).
44 
45 
46  --Phil
47
48*/
49
50
51#include <linux/version.h>
52#include <linux/module.h>
53#include <linux/malloc.h>
54#include <linux/proc_fs.h>
55#include <linux/ioport.h>
56#include <linux/sysctl.h>
57#include <asm/errno.h>
58#include <asm/io.h>
59#include <linux/types.h>
60#include <linux/i2c.h>
61#include "version.h"
62#include "sensors.h"
63#include <linux/init.h>
64
65#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \
66    (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0))
67#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
68#endif
69
70#ifndef THIS_MODULE
71#define THIS_MODULE NULL
72#endif
73
74/* Addresses to scan */
75static unsigned short normal_i2c[] = { SENSORS_I2C_END };
76static unsigned short normal_i2c_range[] = { 0x2c, 0x2f, SENSORS_I2C_END };
77static unsigned int normal_isa[] = { SENSORS_ISA_END };
78static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
79
80/* Insmod parameters */
81SENSORS_INSMOD_3(adm9240, ds1780, lm81);
82
83/* Many ADM9240 constants specified below */
84
85#define ADM9240_REG_IN_MAX(nr) (0x2b + (nr) * 2)
86#define ADM9240_REG_IN_MIN(nr) (0x2c + (nr) * 2)
87#define ADM9240_REG_IN(nr) (0x20 + (nr))
88
89/* The ADM9240 registers */
90#define ADM9240_REG_TEST 0x15
91#define ADM9240_REG_ANALOG_OUT 0x19
92/* These are all read-only */
93#define ADM9240_REG_2_5V 0x20
94#define ADM9240_REG_VCCP1 0x21
95#define ADM9240_REG_3_3V 0x22
96#define ADM9240_REG_5V 0x23
97#define ADM9240_REG_12V 0x24
98#define ADM9240_REG_VCCP2 0x25
99#define ADM9240_REG_TEMP 0x27
100#define ADM9240_REG_FAN1 0x28
101#define ADM9240_REG_FAN2 0x29
102#define ADM9240_REG_COMPANY_ID 0x3E     /* 0x23 for ADM9240; 0xDA for DS1780 */
103                                     /* 0x01 for LM81 */
104#define ADM9240_REG_DIE_REV 0x3F
105/* These are read/write */
106#define ADM9240_REG_2_5V_HIGH 0x2B
107#define ADM9240_REG_2_5V_LOW 0x2C
108#define ADM9240_REG_VCCP1_HIGH 0x2D
109#define ADM9240_REG_VCCP1_LOW 0x2E
110#define ADM9240_REG_3_3V_HIGH 0x2F
111#define ADM9240_REG_3_3V_LOW 0x30
112#define ADM9240_REG_5V_HIGH 0x31
113#define ADM9240_REG_5V_LOW 0x32
114#define ADM9240_REG_12V_HIGH 0x33
115#define ADM9240_REG_12V_LOW 0x34
116#define ADM9240_REG_VCCP2_HIGH 0x35
117#define ADM9240_REG_VCCP2_LOW 0x36
118#define ADM9240_REG_TCRIT_LIMIT 0x37    /* LM81 only - not supported */
119#define ADM9240_REG_LOW_LIMIT 0x38      /* LM81 only - not supported */
120#define ADM9240_REG_TOS 0x39
121#define ADM9240_REG_THYST 0x3A
122#define ADM9240_REG_FAN1_MIN 0x3B
123#define ADM9240_REG_FAN2_MIN 0x3C
124
125#define ADM9240_REG_CONFIG 0x40
126#define ADM9240_REG_INT1_STAT 0x41
127#define ADM9240_REG_INT2_STAT 0x42
128#define ADM9240_REG_INT1_MASK 0x43
129#define ADM9240_REG_INT2_MASK 0x44
130
131#define ADM9240_REG_COMPAT 0x45 /* dummy compat. register for other drivers? */
132#define ADM9240_REG_CHASSIS_CLEAR 0x46
133#define ADM9240_REG_VID_FAN_DIV 0x47
134#define ADM9240_REG_I2C_ADDR 0x48
135#define ADM9240_REG_VID4 0x49
136#define ADM9240_REG_TEMP_CONFIG 0x4B
137#define ADM9240_REG_EXTMODE1 0x4C       /* LM81 only - not supported */
138#define ADM9240_REG_EXTMODE2 0x4D       /* LM81 only - not supported */
139
140/* Conversions. Rounding and limit checking is only done on the TO_REG
141   variants. Note that you should be a bit careful with which arguments
142   these macros are called: arguments may be evaluated more than once.
143   Fixing this is just not worth it. */
144#define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255))
145#define IN_FROM_REG(val,nr) (val)
146
147extern inline u8 FAN_TO_REG(long rpm, int div)
148{
149        if (rpm == 0)
150                return 255;
151        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
152        return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,
153                             254);
154}
155
156#define FAN_FROM_REG(val,div) ((val)==0?-1:\
157                               (val)==255?0:1350000/((div)*(val)))
158
159#define TEMP_FROM_REG(temp) \
160   ((temp)<256?((((temp)&0x1fe) >> 1) * 10)      + ((temp) & 1) * 5:  \
161               ((((temp)&0x1fe) >> 1) -255) * 10 - ((temp) & 1) * 5)  \
162
163#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
164
165#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\
166                                                      ((val)+5)/10), \
167                                             0,255)
168
169#define ALARMS_FROM_REG(val) (val)
170
171#define DIV_FROM_REG(val) (1 << (val))
172#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1)))
173
174#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\
175                           205-(val)*5)
176
177/* Initial limits */
178#define ADM9240_INIT_IN_0 190
179#define ADM9240_INIT_IN_1 190
180#define ADM9240_INIT_IN_2 190
181#define ADM9240_INIT_IN_3 190
182#define ADM9240_INIT_IN_4 190
183#define ADM9240_INIT_IN_5 190
184
185#define ADM9240_INIT_IN_PERCENTAGE 10
186
187#define ADM9240_INIT_IN_MIN_0 \
188        (ADM9240_INIT_IN_0 - ADM9240_INIT_IN_0 * ADM9240_INIT_IN_PERCENTAGE / 100)
189#define ADM9240_INIT_IN_MAX_0 \
190        (ADM9240_INIT_IN_0 + ADM9240_INIT_IN_0 * ADM9240_INIT_IN_PERCENTAGE / 100)
191#define ADM9240_INIT_IN_MIN_1 \
192        (ADM9240_INIT_IN_1 - ADM9240_INIT_IN_1 * ADM9240_INIT_IN_PERCENTAGE / 100)
193#define ADM9240_INIT_IN_MAX_1 \
194        (ADM9240_INIT_IN_1 + ADM9240_INIT_IN_1 * ADM9240_INIT_IN_PERCENTAGE / 100)
195#define ADM9240_INIT_IN_MIN_2 \
196        (ADM9240_INIT_IN_2 - ADM9240_INIT_IN_2 * ADM9240_INIT_IN_PERCENTAGE / 100)
197#define ADM9240_INIT_IN_MAX_2 \
198        (ADM9240_INIT_IN_2 + ADM9240_INIT_IN_2 * ADM9240_INIT_IN_PERCENTAGE / 100)
199#define ADM9240_INIT_IN_MIN_3 \
200        (ADM9240_INIT_IN_3 - ADM9240_INIT_IN_3 * ADM9240_INIT_IN_PERCENTAGE / 100)
201#define ADM9240_INIT_IN_MAX_3 \
202        (ADM9240_INIT_IN_3 + ADM9240_INIT_IN_3 * ADM9240_INIT_IN_PERCENTAGE / 100)
203#define ADM9240_INIT_IN_MIN_4 \
204        (ADM9240_INIT_IN_4 - ADM9240_INIT_IN_4 * ADM9240_INIT_IN_PERCENTAGE / 100)
205#define ADM9240_INIT_IN_MAX_4 \
206        (ADM9240_INIT_IN_4 + ADM9240_INIT_IN_4 * ADM9240_INIT_IN_PERCENTAGE / 100)
207#define ADM9240_INIT_IN_MIN_5 \
208        (ADM9240_INIT_IN_5 - ADM9240_INIT_IN_5 * ADM9240_INIT_IN_PERCENTAGE / 100)
209#define ADM9240_INIT_IN_MAX_5 \
210        (ADM9240_INIT_IN_5 + ADM9240_INIT_IN_5 * ADM9240_INIT_IN_PERCENTAGE / 100)
211
212#define ADM9240_INIT_FAN_MIN_1 3000
213#define ADM9240_INIT_FAN_MIN_2 3000
214
215#define ADM9240_INIT_TEMP_OS_MAX 600
216#define ADM9240_INIT_TEMP_OS_HYST 500
217#define ADM9240_INIT_TEMP_HOT_MAX 700
218#define ADM9240_INIT_TEMP_HOT_HYST 600
219
220#ifdef MODULE
221extern int init_module(void);
222extern int cleanup_module(void);
223#endif                          /* MODULE */
224
225/* For each registered ADM9240, we need to keep some data in memory. That
226   data is pointed to by adm9240_list[NR]->data. The structure itself is
227   dynamically allocated, at the same time when a new adm9240 client is
228   allocated. */
229struct adm9240_data {
230        int sysctl_id;
231        enum chips type;
232
233        struct semaphore update_lock;
234        char valid;             /* !=0 if following fields are valid */
235        unsigned long last_updated;     /* In jiffies */
236
237        u8 in[6];               /* Register value */
238        u8 in_max[6];           /* Register value */
239        u8 in_min[6];           /* Register value */
240        u8 fan[2];              /* Register value */
241        u8 fan_min[2];          /* Register value */
242        u8 fan_div[2];          /* Register encoding, shifted right */
243        int temp;               /* Temp, shifted right */
244        u8 temp_os_max;         /* Register value */
245        u8 temp_os_hyst;        /* Register value */
246        u16 alarms;             /* Register encoding, combined */
247        u8 analog_out;          /* Register value */
248        u8 vid;                 /* Register value combined */
249};
250
251
252#ifdef MODULE
253static
254#else
255extern
256#endif
257int __init sensors_adm9240_init(void);
258static int __init adm9240_cleanup(void);
259
260static int adm9240_attach_adapter(struct i2c_adapter *adapter);
261static int adm9240_detect(struct i2c_adapter *adapter, int address,
262                          unsigned short flags, int kind);
263static int adm9240_detach_client(struct i2c_client *client);
264static int adm9240_command(struct i2c_client *client, unsigned int cmd,
265                           void *arg);
266static void adm9240_inc_use(struct i2c_client *client);
267static void adm9240_dec_use(struct i2c_client *client);
268
269static int adm9240_read_value(struct i2c_client *client, u8 register);
270static int adm9240_write_value(struct i2c_client *client, u8 register,
271                               u8 value);
272static void adm9240_update_client(struct i2c_client *client);
273static void adm9240_init_client(struct i2c_client *client);
274
275
276static void adm9240_in(struct i2c_client *client, int operation,
277                       int ctl_name, int *nrels_mag, long *results);
278static void adm9240_fan(struct i2c_client *client, int operation,
279                        int ctl_name, int *nrels_mag, long *results);
280static void adm9240_temp(struct i2c_client *client, int operation,
281                         int ctl_name, int *nrels_mag, long *results);
282static void adm9240_alarms(struct i2c_client *client, int operation,
283                           int ctl_name, int *nrels_mag, long *results);
284static void adm9240_fan_div(struct i2c_client *client, int operation,
285                            int ctl_name, int *nrels_mag, long *results);
286static void adm9240_analog_out(struct i2c_client *client, int operation,
287                               int ctl_name, int *nrels_mag,
288                               long *results);
289static void adm9240_vid(struct i2c_client *client, int operation,
290                        int ctl_name, int *nrels_mag, long *results);
291
292/* I choose here for semi-static ADM9240 allocation. Complete dynamic
293   allocation could also be used; the code needed for this would probably
294   take more memory than the datastructure takes now. */
295static int adm9240_id = 0;
296
297static struct i2c_driver adm9240_driver = {
298        /* name */ "ADM9240 sensor driver",
299        /* id */ I2C_DRIVERID_ADM9240,
300        /* flags */ I2C_DF_NOTIFY,
301        /* attach_adapter */ &adm9240_attach_adapter,
302        /* detach_client */ &adm9240_detach_client,
303        /* command */ &adm9240_command,
304        /* inc_use */ &adm9240_inc_use,
305        /* dec_use */ &adm9240_dec_use
306};
307
308/* Used by adm9240_init/cleanup */
309static int __initdata adm9240_initialized = 0;
310
311/* The /proc/sys entries */
312/* These files are created for each detected ADM9240. This is just a template;
313   though at first sight, you might think we could use a statically
314   allocated list, we need some way to get back to the parent - which
315   is done through one of the 'extra' fields which are initialized
316   when a new copy is allocated. */
317static ctl_table adm9240_dir_table_template[] = {
318        {ADM9240_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
319         &i2c_sysctl_real, NULL, &adm9240_in},
320        {ADM9240_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
321         &i2c_sysctl_real, NULL, &adm9240_in},
322        {ADM9240_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
323         &i2c_sysctl_real, NULL, &adm9240_in},
324        {ADM9240_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
325         &i2c_sysctl_real, NULL, &adm9240_in},
326        {ADM9240_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real,
327         &i2c_sysctl_real, NULL, &adm9240_in},
328        {ADM9240_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &i2c_proc_real,
329         &i2c_sysctl_real, NULL, &adm9240_in},
330        {ADM9240_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
331         &i2c_sysctl_real, NULL, &adm9240_fan},
332        {ADM9240_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
333         &i2c_sysctl_real, NULL, &adm9240_fan},
334        {ADM9240_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
335         &i2c_sysctl_real, NULL, &adm9240_temp},
336        {ADM9240_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
337         &i2c_sysctl_real, NULL, &adm9240_fan_div},
338        {ADM9240_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
339         &i2c_sysctl_real, NULL, &adm9240_alarms},
340        {ADM9240_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real,
341         &i2c_sysctl_real, NULL, &adm9240_analog_out},
342        {ADM9240_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &i2c_proc_real,
343         &i2c_sysctl_real, NULL, &adm9240_vid},
344        {0}
345};
346
347int adm9240_attach_adapter(struct i2c_adapter *adapter)
348{
349        return i2c_detect(adapter, &addr_data, adm9240_detect);
350}
351
352static int adm9240_detect(struct i2c_adapter *adapter, int address,
353                          unsigned short flags, int kind)
354{
355        int i;
356        struct i2c_client *new_client;
357        struct adm9240_data *data;
358        int err = 0;
359        const char *type_name = "";
360        const char *client_name = "";
361
362        /* Make sure we aren't probing the ISA bus!! This is just a safety check
363           at this moment; i2c_detect really won't call us. */
364#ifdef DEBUG
365        if (i2c_is_isa_adapter(adapter)) {
366                printk
367                    ("adm9240.o: adm9240_detect called for an ISA bus adapter?!?\n");
368                return 0;
369        }
370#endif
371
372        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
373                goto ERROR0;
374
375        /* OK. For now, we presume we have a valid client. We now create the
376           client structure, even though we cannot fill it completely yet.
377           But it allows us to access adm9240_{read,write}_value. */
378
379        if (!(new_client = kmalloc(sizeof(struct i2c_client) +
380                                   sizeof(struct adm9240_data),
381                                   GFP_KERNEL))) {
382                err = -ENOMEM;
383                goto ERROR0;
384        }
385
386        data = (struct adm9240_data *) (new_client + 1);
387        new_client->addr = address;
388        new_client->data = data;
389        new_client->adapter = adapter;
390        new_client->driver = &adm9240_driver;
391        new_client->flags = 0;
392
393        /* Now, we do the remaining detection. */
394
395        if (kind < 0) {
396                if (
397                    ((adm9240_read_value
398                      (new_client, ADM9240_REG_CONFIG) & 0x80) != 0x00)
399                    ||
400                    (adm9240_read_value(new_client, ADM9240_REG_I2C_ADDR)
401                     != address))
402                        goto ERROR1;
403        }
404
405        /* Determine the chip type. */
406        if (kind <= 0) {
407                i = adm9240_read_value(new_client, ADM9240_REG_COMPANY_ID);
408                if (i == 0x23)
409                        kind = adm9240;
410                else if (i == 0xda)
411                        kind = ds1780;
412                else if (i == 0x01)
413                        kind = lm81;
414                else {
415                        if (kind == 0)
416                                printk
417                                    ("adm9240.o: Ignoring 'force' parameter for unknown chip at "
418                                     "adapter %d, address 0x%02x\n",
419                                     i2c_adapter_id(adapter), address);
420                        goto ERROR1;
421                }
422        }
423
424        if (kind == adm9240) {
425                type_name = "adm9240";
426                client_name = "ADM9240 chip";
427        } else if (kind == ds1780) {
428                type_name = "ds1780";
429                client_name = "DS1780 chip";
430        } else if (kind == lm81) {
431                type_name = "lm81";
432                client_name = "LM81 chip";
433        } else {
434#ifdef DEBUG
435                printk("adm9240.o: Internal error: unknown kind (%d)?!?",
436                       kind);
437#endif
438                goto ERROR1;
439        }
440
441        /* Fill in the remaining client fields and put it into the global list */
442        strcpy(new_client->name, client_name);
443        data->type = kind;
444
445        new_client->id = adm9240_id++;
446        data->valid = 0;
447        init_MUTEX(&data->update_lock);
448
449        /* Tell the I2C layer a new client has arrived */
450        if ((err = i2c_attach_client(new_client)))
451                goto ERROR3;
452
453        /* Register a new directory entry with module sensors */
454        if ((i = i2c_register_entry(new_client,
455                                        type_name,
456                                        adm9240_dir_table_template,
457                                        THIS_MODULE)) < 0) {
458                err = i;
459                goto ERROR4;
460        }
461        data->sysctl_id = i;
462
463        /* Initialize the ADM9240 chip */
464        adm9240_init_client(new_client);
465        return 0;
466
467/* OK, this is not exactly good programming practice, usually. But it is
468   very code-efficient in this case. */
469
470      ERROR4:
471        i2c_detach_client(new_client);
472      ERROR3:
473      ERROR1:
474        kfree(new_client);
475      ERROR0:
476        return err;
477}
478
479int adm9240_detach_client(struct i2c_client *client)
480{
481        int err;
482
483        i2c_deregister_entry(((struct adm9240_data *) (client->data))->
484                                 sysctl_id);
485
486        if ((err = i2c_detach_client(client))) {
487                printk
488                    ("adm9240.o: Client deregistration failed, client not detached.\n");
489                return err;
490        }
491
492        kfree(client);
493
494        return 0;
495
496}
497
498/* No commands defined yet */
499int adm9240_command(struct i2c_client *client, unsigned int cmd, void *arg)
500{
501        return 0;
502}
503
504void adm9240_inc_use(struct i2c_client *client)
505{
506#ifdef MODULE
507        MOD_INC_USE_COUNT;
508#endif
509}
510
511void adm9240_dec_use(struct i2c_client *client)
512{
513#ifdef MODULE
514        MOD_DEC_USE_COUNT;
515#endif
516}
517
518int adm9240_read_value(struct i2c_client *client, u8 reg)
519{
520        return 0xFF & i2c_smbus_read_byte_data(client, reg);
521}
522
523int adm9240_write_value(struct i2c_client *client, u8 reg, u8 value)
524{
525        return i2c_smbus_write_byte_data(client, reg, value);
526}
527
528/* Called when we have found a new ADM9240. It should set limits, etc. */
529void adm9240_init_client(struct i2c_client *client)
530{
531        /* Reset all except Watchdog values and last conversion values
532           This sets fan-divs to 2, among others. This makes most other
533           initializations unnecessary */
534        adm9240_write_value(client, ADM9240_REG_CONFIG, 0x80);
535
536        adm9240_write_value(client, ADM9240_REG_IN_MIN(0),
537                            IN_TO_REG(ADM9240_INIT_IN_MIN_0, 0));
538        adm9240_write_value(client, ADM9240_REG_IN_MAX(0),
539                            IN_TO_REG(ADM9240_INIT_IN_MAX_0, 0));
540        adm9240_write_value(client, ADM9240_REG_IN_MIN(1),
541                            IN_TO_REG(ADM9240_INIT_IN_MIN_1, 1));
542        adm9240_write_value(client, ADM9240_REG_IN_MAX(1),
543                            IN_TO_REG(ADM9240_INIT_IN_MAX_1, 1));
544        adm9240_write_value(client, ADM9240_REG_IN_MIN(2),
545                            IN_TO_REG(ADM9240_INIT_IN_MIN_2, 2));
546        adm9240_write_value(client, ADM9240_REG_IN_MAX(2),
547                            IN_TO_REG(ADM9240_INIT_IN_MAX_2, 2));
548        adm9240_write_value(client, ADM9240_REG_IN_MIN(3),
549                            IN_TO_REG(ADM9240_INIT_IN_MIN_3, 3));
550        adm9240_write_value(client, ADM9240_REG_IN_MAX(3),
551                            IN_TO_REG(ADM9240_INIT_IN_MAX_3, 3));
552        adm9240_write_value(client, ADM9240_REG_IN_MIN(4),
553                            IN_TO_REG(ADM9240_INIT_IN_MIN_4, 4));
554        adm9240_write_value(client, ADM9240_REG_IN_MAX(4),
555                            IN_TO_REG(ADM9240_INIT_IN_MAX_4, 4));
556        adm9240_write_value(client, ADM9240_REG_IN_MIN(5),
557                            IN_TO_REG(ADM9240_INIT_IN_MIN_5, 5));
558        adm9240_write_value(client, ADM9240_REG_IN_MAX(5),
559                            IN_TO_REG(ADM9240_INIT_IN_MAX_5, 5));
560        adm9240_write_value(client, ADM9240_REG_FAN1_MIN,
561                            FAN_TO_REG(ADM9240_INIT_FAN_MIN_1, 2));
562        adm9240_write_value(client, ADM9240_REG_FAN2_MIN,
563                            FAN_TO_REG(ADM9240_INIT_FAN_MIN_2, 2));
564        adm9240_write_value(client, ADM9240_REG_TOS,
565                            TEMP_LIMIT_TO_REG(ADM9240_INIT_TEMP_OS_MAX));
566        adm9240_write_value(client, ADM9240_REG_THYST,
567                            TEMP_LIMIT_TO_REG(ADM9240_INIT_TEMP_OS_HYST));
568        adm9240_write_value(client, ADM9240_REG_TEMP_CONFIG, 0x00);
569
570        /* Start monitoring */
571        adm9240_write_value(client, ADM9240_REG_CONFIG, 0x01);
572}
573
574void adm9240_update_client(struct i2c_client *client)
575{
576        struct adm9240_data *data = client->data;
577        u8 i;
578
579        down(&data->update_lock);
580
581        if (
582            (jiffies - data->last_updated >
583             (data->type == adm9240 ? HZ / 2 : HZ * 2))
584            || (jiffies < data->last_updated) || !data->valid) {
585
586#ifdef DEBUG
587                printk("Starting adm9240 update\n");
588#endif
589                for (i = 0; i <= 5; i++) {
590                        data->in[i] =
591                            adm9240_read_value(client, ADM9240_REG_IN(i));
592                        data->in_min[i] =
593                            adm9240_read_value(client,
594                                               ADM9240_REG_IN_MIN(i));
595                        data->in_max[i] =
596                            adm9240_read_value(client,
597                                               ADM9240_REG_IN_MAX(i));
598                }
599                data->fan[0] =
600                    adm9240_read_value(client, ADM9240_REG_FAN1);
601                data->fan_min[0] =
602                    adm9240_read_value(client, ADM9240_REG_FAN1_MIN);
603                data->fan[1] =
604                    adm9240_read_value(client, ADM9240_REG_FAN2);
605                data->fan_min[1] =
606                    adm9240_read_value(client, ADM9240_REG_FAN2_MIN);
607                data->temp =
608                    (adm9240_read_value(client, ADM9240_REG_TEMP) << 1) +
609                    ((adm9240_read_value
610                      (client, ADM9240_REG_TEMP_CONFIG) & 0x80) >> 7);
611                data->temp_os_max =
612                    adm9240_read_value(client, ADM9240_REG_TOS);
613                data->temp_os_hyst =
614                    adm9240_read_value(client, ADM9240_REG_THYST);
615
616                i = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
617                data->fan_div[0] = (i >> 4) & 0x03;
618                data->fan_div[1] = (i >> 6) & 0x03;
619                data->vid = i & 0x0f;
620                data->vid |=
621                    (adm9240_read_value(client, ADM9240_REG_VID4) & 0x01)
622                    << 4;
623
624                data->alarms =
625                    adm9240_read_value(client,
626                                       ADM9240_REG_INT1_STAT) +
627                    (adm9240_read_value(client, ADM9240_REG_INT2_STAT) <<
628                     8);
629                data->analog_out =
630                    adm9240_read_value(client, ADM9240_REG_ANALOG_OUT);
631                data->last_updated = jiffies;
632                data->valid = 1;
633        }
634
635        up(&data->update_lock);
636}
637
638
639/* The next few functions are the call-back functions of the /proc/sys and
640   sysctl files. Which function is used is defined in the ctl_table in
641   the extra1 field.
642   Each function must return the magnitude (power of 10 to divide the date
643   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
644   put a maximum of *nrels elements in results reflecting the data of this
645   file, and set *nrels to the number it actually put in it, if operation==
646   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
647   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
648   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
649   large enough (by checking the incoming value of *nrels). This is not very
650   good practice, but as long as you put less than about 5 values in results,
651   you can assume it is large enough. */
652void adm9240_in(struct i2c_client *client, int operation, int ctl_name,
653                int *nrels_mag, long *results)
654{
655
656        int scales[6] = { 250, 270, 330, 500, 1200, 270 };
657
658        struct adm9240_data *data = client->data;
659        int nr = ctl_name - ADM9240_SYSCTL_IN0;
660
661        if (operation == SENSORS_PROC_REAL_INFO)
662                *nrels_mag = 2;
663        else if (operation == SENSORS_PROC_REAL_READ) {
664                adm9240_update_client(client);
665                results[0] =
666                    IN_FROM_REG(data->in_min[nr], nr) * scales[nr] / 192;
667                results[1] =
668                    IN_FROM_REG(data->in_max[nr], nr) * scales[nr] / 192;
669                results[2] =
670                    IN_FROM_REG(data->in[nr], nr) * scales[nr] / 192;
671                *nrels_mag = 3;
672        } else if (operation == SENSORS_PROC_REAL_WRITE) {
673                if (*nrels_mag >= 1) {
674                        data->in_min[nr] =
675                            IN_TO_REG((results[0] * 192) / scales[nr], nr);
676                        adm9240_write_value(client, ADM9240_REG_IN_MIN(nr),
677                                            data->in_min[nr]);
678                }
679                if (*nrels_mag >= 2) {
680                        data->in_max[nr] =
681                            IN_TO_REG((results[1] * 192) / scales[nr], nr);
682                        adm9240_write_value(client, ADM9240_REG_IN_MAX(nr),
683                                            data->in_max[nr]);
684                }
685        }
686}
687
688void adm9240_fan(struct i2c_client *client, int operation, int ctl_name,
689                 int *nrels_mag, long *results)
690{
691        struct adm9240_data *data = client->data;
692        int nr = ctl_name - ADM9240_SYSCTL_FAN1 + 1;
693
694        if (operation == SENSORS_PROC_REAL_INFO)
695                *nrels_mag = 0;
696        else if (operation == SENSORS_PROC_REAL_READ) {
697                adm9240_update_client(client);
698                results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
699                                          DIV_FROM_REG(data->
700                                                       fan_div[nr - 1]));
701                results[1] =
702                    FAN_FROM_REG(data->fan[nr - 1],
703                                 DIV_FROM_REG(data->fan_div[nr - 1]));
704                *nrels_mag = 2;
705        } else if (operation == SENSORS_PROC_REAL_WRITE) {
706                if (*nrels_mag >= 1) {
707                        data->fan_min[nr - 1] = FAN_TO_REG(results[0],
708                                                           DIV_FROM_REG
709                                                           (data->
710                                                            fan_div[nr -
711                                                                    1]));
712                        adm9240_write_value(client,
713                                            nr ==
714                                            1 ? ADM9240_REG_FAN1_MIN :
715                                            ADM9240_REG_FAN2_MIN,
716                                            data->fan_min[nr - 1]);
717                }
718        }
719}
720
721
722void adm9240_temp(struct i2c_client *client, int operation, int ctl_name,
723                  int *nrels_mag, long *results)
724{
725        struct adm9240_data *data = client->data;
726        if (operation == SENSORS_PROC_REAL_INFO)
727                *nrels_mag = 1;
728        else if (operation == SENSORS_PROC_REAL_READ) {
729                adm9240_update_client(client);
730                results[0] = TEMP_LIMIT_FROM_REG(data->temp_os_max);
731                results[1] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst);
732                results[2] = TEMP_FROM_REG(data->temp);
733                *nrels_mag = 3;
734        } else if (operation == SENSORS_PROC_REAL_WRITE) {
735                if (*nrels_mag >= 1) {
736                        data->temp_os_max = TEMP_LIMIT_TO_REG(results[0]);
737                        adm9240_write_value(client, ADM9240_REG_TOS,
738                                            data->temp_os_max);
739                }
740                if (*nrels_mag >= 2) {
741                        data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[1]);
742                        adm9240_write_value(client, ADM9240_REG_THYST,
743                                            data->temp_os_hyst);
744                }
745        }
746}
747
748void adm9240_alarms(struct i2c_client *client, int operation, int ctl_name,
749                    int *nrels_mag, long *results)
750{
751        struct adm9240_data *data = client->data;
752        if (operation == SENSORS_PROC_REAL_INFO)
753                *nrels_mag = 0;
754        else if (operation == SENSORS_PROC_REAL_READ) {
755                adm9240_update_client(client);
756                results[0] = ALARMS_FROM_REG(data->alarms);
757                *nrels_mag = 1;
758        }
759}
760
761void adm9240_fan_div(struct i2c_client *client, int operation,
762                     int ctl_name, int *nrels_mag, long *results)
763{
764        struct adm9240_data *data = client->data;
765        int old;
766
767        if (operation == SENSORS_PROC_REAL_INFO)
768                *nrels_mag = 0;
769        else if (operation == SENSORS_PROC_REAL_READ) {
770                adm9240_update_client(client);
771                results[0] = DIV_FROM_REG(data->fan_div[0]);
772                results[1] = DIV_FROM_REG(data->fan_div[1]);
773                *nrels_mag = 2;
774        } else if (operation == SENSORS_PROC_REAL_WRITE) {
775                old = adm9240_read_value(client, ADM9240_REG_VID_FAN_DIV);
776                if (*nrels_mag >= 2) {
777                        data->fan_div[1] = DIV_TO_REG(results[1]);
778                        old = (old & 0x3f) | (data->fan_div[1] << 6);
779                }
780                if (*nrels_mag >= 1) {
781                        data->fan_div[0] = DIV_TO_REG(results[0]);
782                        old = (old & 0xcf) | (data->fan_div[0] << 4);
783                        adm9240_write_value(client,
784                                            ADM9240_REG_VID_FAN_DIV, old);
785                }
786        }
787}
788
789void adm9240_analog_out(struct i2c_client *client, int operation,
790                        int ctl_name, int *nrels_mag, long *results)
791{
792        struct adm9240_data *data = client->data;
793
794        if (operation == SENSORS_PROC_REAL_INFO)
795                *nrels_mag = 0;
796        else if (operation == SENSORS_PROC_REAL_READ) {
797                adm9240_update_client(client);
798                results[0] = data->analog_out;
799                *nrels_mag = 1;
800        } else if (operation == SENSORS_PROC_REAL_WRITE) {
801                if (*nrels_mag >= 1) {
802                        data->analog_out = results[0];
803                        adm9240_write_value(client, ADM9240_REG_ANALOG_OUT,
804                                            data->analog_out);
805                }
806        }
807}
808
809void adm9240_vid(struct i2c_client *client, int operation, int ctl_name,
810                 int *nrels_mag, long *results)
811{
812        struct adm9240_data *data = client->data;
813
814        if (operation == SENSORS_PROC_REAL_INFO)
815                *nrels_mag = 2;
816        else if (operation == SENSORS_PROC_REAL_READ) {
817                adm9240_update_client(client);
818                results[0] = VID_FROM_REG(data->vid);
819                *nrels_mag = 1;
820        }
821}
822
823int __init sensors_adm9240_init(void)
824{
825        int res;
826
827        printk("adm9240.o version %s (%s)\n", LM_VERSION, LM_DATE);
828        adm9240_initialized = 0;
829
830        if ((res = i2c_add_driver(&adm9240_driver))) {
831                printk
832                    ("adm9240.o: Driver registration failed, module not inserted.\n");
833                adm9240_cleanup();
834                return res;
835        }
836        adm9240_initialized++;
837        return 0;
838}
839
840int __init adm9240_cleanup(void)
841{
842        int res;
843
844        if (adm9240_initialized >= 1) {
845                if ((res = i2c_del_driver(&adm9240_driver))) {
846                        printk
847                            ("adm9240.o: Driver deregistration failed, module not removed.\n");
848                        return res;
849                }
850                adm9240_initialized--;
851        }
852        return 0;
853}
854
855EXPORT_NO_SYMBOLS;
856
857#ifdef MODULE
858
859MODULE_AUTHOR
860    ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
861MODULE_DESCRIPTION("ADM9240 driver");
862
863int init_module(void)
864{
865        return sensors_adm9240_init();
866}
867
868int cleanup_module(void)
869{
870        return adm9240_cleanup();
871}
872
873#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.