root/lm-sensors/trunk/kernel/chips/fscpos.c @ 1193

Revision 1193, 23.3 KB (checked in by mds, 12 years ago)

malloc.h -> slab.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    fscpos.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 2001 Hermann Jung <hej@odn.de>
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21/*
22    fujitsu siemens poseidon chip,
23    module based on lm80.c
24    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
25    and Philip Edelbrock <phil@netroedge.com>
26*/
27
28#include <linux/version.h>
29#include <linux/module.h>
30#include <linux/slab.h>
31#include <linux/proc_fs.h>
32#include <linux/ioport.h>
33#include <linux/sysctl.h>
34#include <asm/errno.h>
35#include <asm/io.h>
36#include <linux/types.h>
37#include <linux/i2c.h>
38#include "version.h"
39#include "sensors.h"
40#include <linux/init.h>
41
42#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \
43    (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0))
44#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
45#endif
46
47#ifndef THIS_MODULE
48#define THIS_MODULE NULL
49#endif
50
51
52/* Addresses to scan */
53static unsigned short normal_i2c[] = { 0x73, SENSORS_I2C_END };
54static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
55static unsigned int normal_isa[] = { SENSORS_ISA_END };
56static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
57
58/* Insmod parameters */
59SENSORS_INSMOD_1(fscpos);
60
61/* The FSCPOS registers */
62
63/* chip identification */
64#define FSCPOS_REG_IDENT_0    0x00
65#define FSCPOS_REG_IDENT_1    0x01
66#define FSCPOS_REG_IDENT_2    0x02
67#define FSCPOS_REG_REVISION   0x03
68
69/* global control and status */
70#define FSCPOS_REG_EVENT_STATE  0x04
71#define FSCPOS_REG_CONTROL       0x05
72
73/* watchdog */
74#define FSCPOS_REG_WDOG_PRESET      0x28
75#define FSCPOS_REG_WDOG_STATE       0x23
76#define FSCPOS_REG_WDOG_CONTROL     0x21
77
78/* fan 0  */
79#define FSCPOS_REG_FAN0_MIN      0x55
80#define FSCPOS_REG_FAN0_ACT      0x0e
81#define FSCPOS_REG_FAN0_STATE   0x0d
82#define FSCPOS_REG_FAN0_RIPPLE   0x0f
83
84/* fan 1  */
85#define FSCPOS_REG_FAN1_MIN      0x65
86#define FSCPOS_REG_FAN1_ACT      0x6b
87#define FSCPOS_REG_FAN1_STATE   0x62
88#define FSCPOS_REG_FAN1_RIPPLE   0x6f
89
90/* fan 2  */
91/* min speed fan2 not supported */
92#define FSCPOS_REG_FAN2_ACT      0xab
93#define FSCPOS_REG_FAN2_STATE   0xa2
94#define FSCPOS_REG_FAN2_RIPPLE   0x0af
95
96/* voltage supervision */
97#define FSCPOS_REG_VOLT_12       0x45
98#define FSCPOS_REG_VOLT_5        0x42
99#define FSCPOS_REG_VOLT_BATT     0x48
100
101/* temperatures */
102/* sensor 0 */
103#define FSCPOS_REG_TEMP0_ACT       0x64
104#define FSCPOS_REG_TEMP0_STATE    0x71
105
106/* sensor 1 */
107#define FSCPOS_REG_TEMP1_ACT       0x32
108#define FSCPOS_REG_TEMP1_STATE    0x81
109
110/* sensor 2 */
111#define FSCPOS_REG_TEMP2_ACT       0x35
112#define FSCPOS_REG_TEMP2_STATE    0x91
113
114
115
116
117/* Conversions. Rounding and limit checking is only done on the TO_REG
118   variants. Note that you should be a bit careful with which arguments
119   these macros are called: arguments may be evaluated more than once.
120   Fixing this is just not worth it. */
121
122#define IN_TO_REG(val,nr) (SENSORS_LIMIT((val),0,255))
123#define IN_FROM_REG(val,nr) (val)
124
125/* Initial limits */
126
127#ifdef MODULE
128extern int init_module(void);
129extern int cleanup_module(void);
130#endif                          /* MODULE */
131
132/* For each registered FSCPOS, we need to keep some data in memory. That
133   data is pointed to by fscpos_list[NR]->data. The structure itself is
134   dynamically allocated, at the same time when a new fscpos client is
135   allocated. */
136struct fscpos_data {
137        int sysctl_id;
138
139        struct semaphore update_lock;
140        char valid;             /* !=0 if following fields are valid */
141        unsigned long last_updated;     /* In jiffies */
142
143        u8  revision;        /* revision of chip */
144        u8  global_event;    /* global event status */
145        u8  global_control;  /* global control register */
146        u8  watchdog[3];     /* watchdog */
147        u8  volt[3];         /* 12, 5, battery current */ 
148        u8  temp_act[3];     /* temperature */
149        u8  temp_status[3];  /* status of sensor */
150        u8  fan_act[3];      /* fans revolutions per second */
151        u8  fan_status[3];   /* fan status */
152        u8  fan_min[3];      /* fan min value for rps */
153        u8  fan_ripple[3];   /* divider for rps */
154};
155
156
157#ifdef MODULE
158static
159#else
160extern
161#endif
162int __init sensors_fscpos_init(void);
163static int __init fscpos_cleanup(void);
164
165static int fscpos_attach_adapter(struct i2c_adapter *adapter);
166static int fscpos_detect(struct i2c_adapter *adapter, int address,
167                       unsigned short flags, int kind);
168static int fscpos_detach_client(struct i2c_client *client);
169static int fscpos_command(struct i2c_client *client, unsigned int cmd,
170                        void *arg);
171static void fscpos_inc_use(struct i2c_client *client);
172static void fscpos_dec_use(struct i2c_client *client);
173
174static int fscpos_read_value(struct i2c_client *client, u8 register);
175static int fscpos_write_value(struct i2c_client *client, u8 register,
176                            u8 value);
177static void fscpos_update_client(struct i2c_client *client);
178static void fscpos_init_client(struct i2c_client *client);
179
180
181static void fscpos_in(struct i2c_client *client, int operation, int ctl_name,
182                        int *nrels_mag, long *results);
183static void fscpos_fan(struct i2c_client *client, int operation,
184                        int ctl_name, int *nrels_mag, long *results);
185static void fscpos_fan_internal(struct i2c_client *client, int operation,
186                        int ctl_name, int *nrels_mag, long *results, 
187                        int nr, int reg_state, int reg_min, int res_ripple);
188static void fscpos_temp(struct i2c_client *client, int operation,
189                        int ctl_name, int *nrels_mag, long *results);
190static void fscpos_volt(struct i2c_client *client, int operation,
191                        int ctl_name, int *nrels_mag, long *results);
192static void fscpos_wdog(struct i2c_client *client, int operation,
193                        int ctl_name, int *nrels_mag, long *results);
194
195static int fscpos_id = 0;
196
197static struct i2c_driver fscpos_driver = {
198        /* name */ "FSCPOS sensor driver",
199        /* id */ I2C_DRIVERID_FSCPOS,
200        /* flags */ I2C_DF_NOTIFY,
201        /* attach_adapter */ &fscpos_attach_adapter,
202        /* detach_client */ &fscpos_detach_client,
203        /* command */ &fscpos_command,
204        /* inc_use */ &fscpos_inc_use,
205        /* dec_use */ &fscpos_dec_use
206};
207
208/* Used by fscpos_init/cleanup */
209static int __initdata fscpos_initialized = 0;
210
211/* The /proc/sys entries */
212/* These files are created for each detected FSCPOS. This is just a template;
213   though at first sight, you might think we could use a statically
214   allocated list, we need some way to get back to the parent - which
215   is done through one of the 'extra' fields which are initialized
216   when a new copy is allocated. */
217static ctl_table fscpos_dir_table_template[] = {
218        {FSCPOS_SYSCTL_REV, "rev", NULL, 0, 0444, NULL, &i2c_proc_real,
219         &i2c_sysctl_real, NULL, &fscpos_in},
220        {FSCPOS_SYSCTL_EVENT, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
221         &i2c_sysctl_real, NULL, &fscpos_in},
222        {FSCPOS_SYSCTL_CONTROL, "control", NULL, 0, 0644, NULL, &i2c_proc_real,
223         &i2c_sysctl_real, NULL, &fscpos_in},
224        {FSCPOS_SYSCTL_TEMP0, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
225         &i2c_sysctl_real, NULL, &fscpos_temp},
226        {FSCPOS_SYSCTL_TEMP1, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
227         &i2c_sysctl_real, NULL, &fscpos_temp},
228        {FSCPOS_SYSCTL_TEMP2, "temp3", NULL, 0, 0644, NULL, &i2c_proc_real,
229         &i2c_sysctl_real, NULL, &fscpos_temp},
230        {FSCPOS_SYSCTL_VOLT0, "in0", NULL, 0, 0444, NULL, &i2c_proc_real,
231         &i2c_sysctl_real, NULL, &fscpos_volt},
232        {FSCPOS_SYSCTL_VOLT1, "in1", NULL, 0, 0444, NULL, &i2c_proc_real,
233         &i2c_sysctl_real, NULL, &fscpos_volt},
234        {FSCPOS_SYSCTL_VOLT2, "in2", NULL, 0, 0444, NULL, &i2c_proc_real,
235         &i2c_sysctl_real, NULL, &fscpos_volt},
236        {FSCPOS_SYSCTL_FAN0, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
237         &i2c_sysctl_real, NULL, &fscpos_fan},
238        {FSCPOS_SYSCTL_FAN1, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
239         &i2c_sysctl_real, NULL, &fscpos_fan},
240        {FSCPOS_SYSCTL_FAN2, "fan3", NULL, 0, 0644, NULL, &i2c_proc_real,
241         &i2c_sysctl_real, NULL, &fscpos_fan},
242        {FSCPOS_SYSCTL_WDOG, "wdog", NULL, 0, 0644, NULL, &i2c_proc_real,
243         &i2c_sysctl_real, NULL, &fscpos_wdog},
244        {0}
245};
246
247int fscpos_attach_adapter(struct i2c_adapter *adapter)
248{
249        return i2c_detect(adapter, &addr_data, fscpos_detect);
250}
251
252int fscpos_detect(struct i2c_adapter *adapter, int address,
253                unsigned short flags, int kind)
254{
255        int i;
256        struct i2c_client *new_client;
257        struct fscpos_data *data;
258        int err = 0;
259        const char *type_name, *client_name;
260
261        /* Make sure we aren't probing the ISA bus!! This is just a safety check
262           at this moment; i2c_detect really won't call us. */
263#ifdef DEBUG
264        if (i2c_is_isa_adapter(adapter)) {
265                printk
266                    ("fscpos.o: fscpos_detect called for an ISA bus adapter?!?\n");
267                return 0;
268        }
269#endif
270
271        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
272                goto ERROR0;
273
274        /* OK. For now, we presume we have a valid client. We now create the
275           client structure, even though we cannot fill it completely yet.
276           But it allows us to access fscpos_{read,write}_value. */
277        if (!(new_client = kmalloc(sizeof(struct i2c_client) +
278                                   sizeof(struct fscpos_data),
279                                   GFP_KERNEL))) {
280                err = -ENOMEM;
281                goto ERROR0;
282        }
283
284        data = (struct fscpos_data *) (new_client + 1);
285        new_client->addr = address;
286        new_client->data = data;
287        new_client->adapter = adapter;
288        new_client->driver = &fscpos_driver;
289        new_client->flags = 0;
290
291        /* Do the remaining detection unless force or force_fscpos parameter */
292        if (kind < 0) {
293                if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_0) != 0x50)
294                        goto ERROR1;
295                if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_1) != 0x45)
296                        goto ERROR1;
297                if (fscpos_read_value(new_client, FSCPOS_REG_IDENT_2) != 0x47)
298                        goto ERROR1;
299        }
300
301        kind = fscpos;
302
303        type_name = "fscpos";
304        client_name = "fsc poseidon chip";
305
306        /* Fill in the remaining client fields and put it into the global list */
307        strcpy(new_client->name, client_name);
308
309        new_client->id = fscpos_id++;
310        data->valid = 0;
311        init_MUTEX(&data->update_lock);
312
313        /* Tell the I2C layer a new client has arrived */
314        if ((err = i2c_attach_client(new_client)))
315                goto ERROR3;
316
317        /* Register a new directory entry with module sensors */
318        if ((i = i2c_register_entry(new_client, type_name,
319                                        fscpos_dir_table_template,
320                                        THIS_MODULE)) < 0) {
321                err = i;
322                goto ERROR4;
323        }
324        data->sysctl_id = i;
325
326        fscpos_init_client(new_client);
327        return 0;
328
329/* OK, this is not exactly good programming practice, usually. But it is
330   very code-efficient in this case. */
331      ERROR4:
332        i2c_detach_client(new_client);
333      ERROR3:
334      ERROR1:
335        kfree(new_client);
336      ERROR0:
337        return err;
338}
339
340int fscpos_detach_client(struct i2c_client *client)
341{
342        int err;
343
344        i2c_deregister_entry(((struct fscpos_data *) (client->data))->
345                                 sysctl_id);
346
347        if ((err = i2c_detach_client(client))) {
348                printk
349                    ("fscpos.o: Client deregistration failed, client not detached.\n");
350                return err;
351        }
352
353        kfree(client);
354
355        return 0;
356}
357
358/* No commands defined yet */
359int fscpos_command(struct i2c_client *client, unsigned int cmd, void *arg)
360{
361        return 0;
362}
363
364void fscpos_inc_use(struct i2c_client *client)
365{
366#ifdef MODULE
367        MOD_INC_USE_COUNT;
368#endif
369}
370
371void fscpos_dec_use(struct i2c_client *client)
372{
373#ifdef MODULE
374        MOD_DEC_USE_COUNT;
375#endif
376}
377
378
379int fscpos_read_value(struct i2c_client *client, u8 reg)
380{
381#ifdef DEBUG
382        printk("fscpos: read reg 0x%02x\n",reg);
383#endif
384        return i2c_smbus_read_byte_data(client, reg);
385}
386
387int fscpos_write_value(struct i2c_client *client, u8 reg, u8 value)
388{
389#ifdef DEBUG
390        printk("fscpos: write reg 0x%02x, val 0x%02x\n",reg, value);
391#endif
392        return i2c_smbus_write_byte_data(client, reg, value);
393}
394
395/* Called when we have found a new FSCPOS. It should set limits, etc. */
396void fscpos_init_client(struct i2c_client *client)
397{
398        struct fscpos_data *data = client->data;
399
400        /* read revision from chip */
401        data->revision =  fscpos_read_value(client,FSCPOS_REG_REVISION);
402        /* setup missing fan2_min value */
403        data->fan_min[2] = 0xff;
404}
405
406void fscpos_update_client(struct i2c_client *client)
407{
408        struct fscpos_data *data = client->data;
409
410        down(&data->update_lock);
411
412        if ((jiffies - data->last_updated > 2 * HZ) ||
413            (jiffies < data->last_updated) || !data->valid) {
414
415#ifdef DEBUG
416                printk("Starting fscpos update\n");
417#endif
418                data->temp_act[0] = fscpos_read_value(client, FSCPOS_REG_TEMP0_ACT);
419                data->temp_act[1] = fscpos_read_value(client, FSCPOS_REG_TEMP1_ACT);
420                data->temp_act[2] = fscpos_read_value(client, FSCPOS_REG_TEMP2_ACT);
421                data->temp_status[0] = fscpos_read_value(client, FSCPOS_REG_TEMP0_STATE);
422                data->temp_status[1] = fscpos_read_value(client, FSCPOS_REG_TEMP1_STATE);
423                data->temp_status[2] = fscpos_read_value(client, FSCPOS_REG_TEMP2_STATE);
424
425                data->volt[0] = fscpos_read_value(client, FSCPOS_REG_VOLT_12);
426                data->volt[1] = fscpos_read_value(client, FSCPOS_REG_VOLT_5);
427                data->volt[2] = fscpos_read_value(client, FSCPOS_REG_VOLT_BATT);
428
429                data->fan_act[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_ACT);
430                data->fan_act[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_ACT);
431                data->fan_act[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_ACT);
432                data->fan_status[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_STATE);
433                data->fan_status[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_STATE);
434                data->fan_status[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_STATE);
435                data->fan_min[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_MIN);
436                data->fan_min[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_MIN);
437                /* fan2_min is not supported */
438                data->fan_ripple[0] = fscpos_read_value(client, FSCPOS_REG_FAN0_RIPPLE);
439                data->fan_ripple[1] = fscpos_read_value(client, FSCPOS_REG_FAN1_RIPPLE);
440                data->fan_ripple[2] = fscpos_read_value(client, FSCPOS_REG_FAN2_RIPPLE);
441
442                data->watchdog[0] = fscpos_read_value(client, FSCPOS_REG_WDOG_PRESET);
443                data->watchdog[1] = fscpos_read_value(client, FSCPOS_REG_WDOG_STATE);
444                data->watchdog[2] = fscpos_read_value(client, FSCPOS_REG_WDOG_CONTROL);
445
446                data->global_event = fscpos_read_value(client, FSCPOS_REG_EVENT_STATE);
447
448                data->last_updated = jiffies;
449                data->valid = 1;                 
450        }
451
452        up(&data->update_lock);
453}
454
455
456/* The next few functions are the call-back functions of the /proc/sys and
457   sysctl files. Which function is used is defined in the ctl_table in
458   the extra1 field.
459   Each function must return the magnitude (power of 10 to divide the date
460   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
461   put a maximum of *nrels elements in results reflecting the data of this
462   file, and set *nrels to the number it actually put in it, if operation==
463   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
464   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
465   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
466   large enough (by checking the incoming value of *nrels). This is not very
467   good practice, but as long as you put less than about 5 values in results,
468   you can assume it is large enough. */
469void fscpos_in(struct i2c_client *client, int operation, int ctl_name,
470             int *nrels_mag, long *results)
471{
472        struct fscpos_data *data = client->data;
473
474        if (operation == SENSORS_PROC_REAL_INFO)
475                *nrels_mag = 0;
476        else if (operation == SENSORS_PROC_REAL_READ) {
477                fscpos_update_client(client);
478                switch(ctl_name) {
479                        case FSCPOS_SYSCTL_REV:
480                                results[0] = data->revision ;
481                                break;
482                        case FSCPOS_SYSCTL_EVENT:
483                                results[0] = data->global_event & 0x1f;
484                                break;
485                        case FSCPOS_SYSCTL_CONTROL:
486                                results[0] = data->global_control & 0x01;
487                                break;
488                        default:
489                                printk("fscpos: ctl_name %d not supported\n",
490                                        ctl_name);
491                                *nrels_mag = 0;
492                                return;
493                }
494                *nrels_mag = 1;
495        } else if (operation == SENSORS_PROC_REAL_WRITE) {
496                if((ctl_name == FSCPOS_SYSCTL_CONTROL) && (*nrels_mag >= 1)) {
497                        data->global_control = (results[0] & 0x01);
498                        printk("fscpos: writing 0x%02x to global_control\n",
499                                data->global_control);
500                        fscpos_write_value(client,FSCPOS_REG_CONTROL,
501                                data->global_control);
502                }
503                else
504                        printk("fscpos: writing to chip not supported\n");
505        }
506}
507
508#define TEMP_FROM_REG(val)    (val-128)
509
510
511void fscpos_temp(struct i2c_client *client, int operation, int ctl_name,
512               int *nrels_mag, long *results)
513{
514        struct fscpos_data *data = client->data;
515
516        if (operation == SENSORS_PROC_REAL_INFO)
517                *nrels_mag = 0;
518        else if (operation == SENSORS_PROC_REAL_READ) {
519                fscpos_update_client(client);
520                switch(ctl_name) {
521                        case FSCPOS_SYSCTL_TEMP0:
522                                results[0] = data->temp_status[0] & 0x03;
523                                results[1] = TEMP_FROM_REG(data->temp_act[0]);
524                                break;
525                        case FSCPOS_SYSCTL_TEMP1:
526                                results[0] = data->temp_status[1] & 0x03;
527                                results[1] = TEMP_FROM_REG(data->temp_act[1]);
528                                break;
529                        case FSCPOS_SYSCTL_TEMP2:
530                                results[0] = data->temp_status[2] & 0x03;
531                                results[1] = TEMP_FROM_REG(data->temp_act[2]);
532                                break;
533                        default:
534                                printk("fscpos: ctl_name %d not supported\n",
535                                        ctl_name);
536                                *nrels_mag = 0;
537                                return;
538                }
539                *nrels_mag = 2;
540        } else if (operation == SENSORS_PROC_REAL_WRITE) {
541                if(*nrels_mag >= 1) {
542                        switch(ctl_name) {
543                                case FSCPOS_SYSCTL_TEMP0:
544                                        data->temp_status[0] = 
545                                                (data->temp_status[0] & ~0x02) 
546                                                | (results[0] & 0x02);
547                                        printk("fscpos: writing value 0x%02x "
548                                                "to temp0_status\n",
549                                                data->temp_status[0]);
550                                        fscpos_write_value(client,
551                                                FSCPOS_REG_TEMP0_STATE,
552                                                data->temp_status[0] & 0x02);
553                                        break;
554                                case FSCPOS_SYSCTL_TEMP1:
555                                        data->temp_status[1] = (data->temp_status[1] & ~0x02) | (results[0] & 0x02);
556                                        printk("fscpos: writing value 0x%02x to temp1_status\n", data->temp_status[1]);
557                                        fscpos_write_value(client,FSCPOS_REG_TEMP1_STATE,
558                                                data->temp_status[1] & 0x02);
559                                        break;
560                                case FSCPOS_SYSCTL_TEMP2:
561                                        data->temp_status[2] = (data->temp_status[2] & ~0x02) | (results[0] & 0x02);
562                                        printk("fscpos: writing value 0x%02x to temp2_status\n", data->temp_status[2]);
563                                        fscpos_write_value(client,FSCPOS_REG_TEMP2_STATE,
564                                                data->temp_status[2] & 0x02);
565                                        break;
566                                default:
567                                        printk("fscpos: ctl_name %d not supported\n",ctl_name);
568                        }
569                }
570                else
571                        printk("fscpos: writing to chip not supported\n");
572        }
573}
574
575#define VOLT_FROM_REG(val,mult)    (val*mult/255)
576
577void fscpos_volt(struct i2c_client *client, int operation, int ctl_name,
578               int *nrels_mag, long *results)
579{
580        struct fscpos_data *data = client->data;
581        if (operation == SENSORS_PROC_REAL_INFO)
582                *nrels_mag = 2;
583        else if (operation == SENSORS_PROC_REAL_READ) {
584                fscpos_update_client(client);
585                switch(ctl_name) {
586                        case FSCPOS_SYSCTL_VOLT0:
587                                results[0] = VOLT_FROM_REG(data->volt[0],1420);
588                                break;
589                        case FSCPOS_SYSCTL_VOLT1:
590                                results[0] = VOLT_FROM_REG(data->volt[1],660);
591                                break;
592                        case FSCPOS_SYSCTL_VOLT2:
593                                results[0] = VOLT_FROM_REG(data->volt[2],330);
594                                break;
595                        default:
596                                printk("fscpos: ctl_name %d not supported\n",
597                                        ctl_name);
598                                *nrels_mag = 0;
599                                return;
600                }
601                *nrels_mag = 1;
602        } else if (operation == SENSORS_PROC_REAL_WRITE) {
603                        printk("fscpos: writing to chip not supported\n");
604        }
605}
606
607void fscpos_fan(struct i2c_client *client, int operation, int ctl_name,
608               int *nrels_mag, long *results)
609{
610
611        switch(ctl_name) {
612                case FSCPOS_SYSCTL_FAN0:
613                        fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results,
614                                0,FSCPOS_REG_FAN0_STATE,FSCPOS_REG_FAN0_MIN,
615                                FSCPOS_REG_FAN0_RIPPLE);
616                        break;
617                case FSCPOS_SYSCTL_FAN1:
618                        fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results,
619                                1,FSCPOS_REG_FAN1_STATE,FSCPOS_REG_FAN1_MIN,
620                                FSCPOS_REG_FAN1_RIPPLE);
621                        break;
622                case FSCPOS_SYSCTL_FAN2:
623                        fscpos_fan_internal(client,operation,ctl_name,nrels_mag,results,
624                                2,FSCPOS_REG_FAN2_STATE,0xff,
625                                FSCPOS_REG_FAN2_RIPPLE);
626                        break;
627                default:
628                        printk("fscpos: illegal fan nr %d\n",ctl_name);
629        }
630}
631                       
632#define RPM_FROM_REG(val)   (val*60)
633
634void fscpos_fan_internal(struct i2c_client *client, int operation, int ctl_name,
635               int *nrels_mag, long *results, int nr,
636               int reg_state, int reg_min, int reg_ripple )
637{
638        struct fscpos_data *data = client->data;
639
640        if (operation == SENSORS_PROC_REAL_INFO)
641                *nrels_mag = 0;
642        else if (operation == SENSORS_PROC_REAL_READ) {
643                fscpos_update_client(client);
644                results[0] = data->fan_status[nr] & 0x04;
645                results[1] = data->fan_min[nr];
646                results[2] = data->fan_ripple[nr] & 0x03;
647                results[3] = RPM_FROM_REG(data->fan_act[nr]);
648                *nrels_mag = 4;
649        } else if (operation == SENSORS_PROC_REAL_WRITE) {
650                if(*nrels_mag >= 1) {
651                        data->fan_status[nr] = results[0] & 0x04;
652                        printk("fscpos: writing value 0x%02x to fan%d_status\n",
653                                data->fan_status[nr],nr);
654                        fscpos_write_value(client,reg_state,
655                                data->fan_status[nr]);
656                }
657                if((*nrels_mag >= 2) && (nr < 2)) { 
658                        /* minimal speed for fan2 not supported */
659                        data->fan_min[nr] = results[1];
660                        printk("fscpos: writing value 0x%02x to fan%d_min\n",
661                                data->fan_min[nr],nr);
662                        fscpos_write_value(client,reg_min,
663                                data->fan_min[nr]);
664                }
665                if(*nrels_mag >= 3) {
666                        if((results[2] & 0x03) == 0) {
667                                printk("fscpos: fan%d ripple 0 not allowed\n",nr);
668                                return;
669                        }
670                        data->fan_ripple[nr] = results[2] & 0x03;
671                        printk("fscpos: writing value 0x%02x to fan%d_ripple\n",
672                                data->fan_ripple[nr],nr);
673                        fscpos_write_value(client,reg_ripple,
674                                data->fan_ripple[nr]);
675                }       
676        }
677}
678
679void fscpos_wdog(struct i2c_client *client, int operation, int ctl_name,
680             int *nrels_mag, long *results)
681{
682        struct fscpos_data *data = client->data;
683
684        if (operation == SENSORS_PROC_REAL_INFO)
685                *nrels_mag = 0;
686        else if (operation == SENSORS_PROC_REAL_READ) {
687                fscpos_update_client(client);
688                results[0] = data->watchdog[0] ;
689                results[1] = data->watchdog[1] & 0x02;
690                results[2] = data->watchdog[2] & 0xb0;
691                *nrels_mag = 3;
692        } else if (operation == SENSORS_PROC_REAL_WRITE) {
693                if (*nrels_mag >= 1) {
694                        data->watchdog[0] = results[0] & 0xff;
695                        printk("fscpos: writing value 0x%02x to wdog_preset\n",
696                                data->watchdog[0]); 
697                        fscpos_write_value(client,FSCPOS_REG_WDOG_PRESET,
698                                data->watchdog[0]);
699                } 
700                if (*nrels_mag >= 2) {
701                        data->watchdog[1] = results[1] & 0x02;
702                        printk("fscpos: writing value 0x%02x to wdog_state\n",
703                                data->watchdog[1]); 
704                        fscpos_write_value(client,FSCPOS_REG_WDOG_STATE,
705                                data->watchdog[1]);
706                }
707                if (*nrels_mag >= 3) {
708                        data->watchdog[2] = results[2] & 0xb0;
709                        printk("fscpos: writing value 0x%02x to wdog_control\n",
710                                data->watchdog[2]); 
711                        fscpos_write_value(client,FSCPOS_REG_WDOG_CONTROL,
712                                data->watchdog[2]);
713                }
714        }
715}
716
717int __init sensors_fscpos_init(void)
718{
719        int res;
720
721        printk("fscpos.o version %s (%s)\n", LM_VERSION, LM_DATE);
722        fscpos_initialized = 0;
723
724        if ((res = i2c_add_driver(&fscpos_driver))) {
725                printk
726                    ("fscpos.o: Driver registration failed, module not inserted.\n");
727                fscpos_cleanup();
728                return res;
729        }
730        fscpos_initialized++;
731        return 0;
732}
733
734int __init fscpos_cleanup(void)
735{
736        int res;
737
738        if (fscpos_initialized >= 1) {
739                if ((res = i2c_del_driver(&fscpos_driver))) {
740                        printk
741                            ("fscpos.o: Driver deregistration failed, module not removed.\n");
742                        return res;
743                }
744                fscpos_initialized--;
745        }
746        return 0;
747}
748
749EXPORT_NO_SYMBOLS;
750
751#ifdef MODULE
752
753MODULE_AUTHOR
754    ("Hermann Jung <hej@odn.de> based on work from Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
755MODULE_DESCRIPTION("fujitsu siemens poseidon chip driver");
756
757int init_module(void)
758{
759        return sensors_fscpos_init();
760}
761
762int cleanup_module(void)
763{
764        return fscpos_cleanup();
765}
766
767#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.