root/lm-sensors/trunk/kernel/chips/gl518sm.c @ 2867

Revision 2867, 28.3 KB (checked in by khali, 8 years ago)

Drop unused client id.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    gl518sm.c - Part of lm_sensors, Linux kernel modules for hardware
3                monitoring
4    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>,
5                              Kyösti Mälkki <kmalkki@cc.hut.fi>
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
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/i2c.h>
26#include <linux/i2c-proc.h>
27#include <linux/init.h>
28#ifdef __SMP__
29#include <linux/smp_lock.h>
30#endif
31#include "version.h"
32
33MODULE_LICENSE("GPL");
34
35/* Addresses to scan */
36static unsigned short normal_i2c[] = { 0x2c, 0x2d, SENSORS_I2C_END };
37static unsigned short normal_i2c_range[] = { SENSORS_I2C_END };
38static unsigned int normal_isa[] = { SENSORS_ISA_END };
39static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
40
41/* Insmod parameters */
42SENSORS_INSMOD_2(gl518sm_r00, gl518sm_r80);
43
44/* Defining this will enable debug messages for the voltage iteration
45   code used with rev 0 ICs */
46#undef DEBUG_VIN
47
48/* Many GL518 constants specified below */
49
50/* The GL518 registers */
51#define GL518_REG_CHIP_ID 0x00
52#define GL518_REG_REVISION 0x01
53#define GL518_REG_VENDOR_ID 0x02
54#define GL518_REG_CONF 0x03
55#define GL518_REG_TEMP 0x04
56#define GL518_REG_TEMP_OVER 0x05
57#define GL518_REG_TEMP_HYST 0x06
58#define GL518_REG_FAN_COUNT 0x07
59#define GL518_REG_FAN_LIMIT 0x08
60#define GL518_REG_VIN1_LIMIT 0x09
61#define GL518_REG_VIN2_LIMIT 0x0a
62#define GL518_REG_VIN3_LIMIT 0x0b
63#define GL518_REG_VDD_LIMIT 0x0c
64#define GL518_REG_VIN3 0x0d
65#define GL518_REG_MISC 0x0f
66#define GL518_REG_ALARM 0x10
67#define GL518_REG_MASK 0x11
68#define GL518_REG_INT 0x12
69#define GL518_REG_VIN2 0x13
70#define GL518_REG_VIN1 0x14
71#define GL518_REG_VDD 0x15
72
73
74/* Conversions. Rounding and limit checking is only done on the TO_REG
75   variants. Note that you should be a bit careful with which arguments
76   these macros are called: arguments may be evaluated more than once.
77   Fixing this is just not worth it. */
78
79#define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-5:(val)+5) / 10)+119),\
80                                        0,255))
81#define TEMP_FROM_REG(val) (((val) - 119) * 10)
82
83static inline u8 FAN_TO_REG(long rpm, int div)
84{
85        if (rpm == 0)
86                return 255;
87        rpm = SENSORS_LIMIT(rpm, 1, 1000000);
88        return SENSORS_LIMIT((960000 + rpm * div / 2) / (rpm * div), 1,
89                             254);
90}
91
92#define FAN_FROM_REG(val,div) \
93 ( (val)==0 ? 0 : (val)==255 ? 0 : (960000/((val)*(div))) )
94
95#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*10+8)/19),0,255))
96#define IN_FROM_REG(val) (((val)*19)/10)
97
98#define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*10+11)/23),0,255))
99#define VDD_FROM_REG(val) (((val)*23)/10)
100
101#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
102#define DIV_FROM_REG(val) (1 << (val))
103
104#define ALARMS_FROM_REG(val) val
105
106#define BEEP_ENABLE_TO_REG(val) ((val)?0:1)
107#define BEEP_ENABLE_FROM_REG(val) ((val)?0:1)
108
109#define BEEPS_TO_REG(val) ((val) & 0x7f)
110#define BEEPS_FROM_REG(val) ((val) & 0x7f)
111
112/* Each client has this additional data */
113struct gl518_data {
114        struct i2c_client client;
115        int sysctl_id;
116        enum chips type;
117
118        struct semaphore update_lock;
119
120        int iterate_lock;
121        int quit_thread;
122        struct task_struct *thread;
123        wait_queue_head_t wq;
124        char valid;             /* !=0 if following fields are valid */
125        unsigned long last_updated;     /* In jiffies */
126        unsigned long last_updated_v00;
127        /* In jiffies (used only by rev00 chips) */
128
129        u8 voltage[4];          /* Register values; [0] = VDD */
130        u8 voltage_min[4];      /* Register values; [0] = VDD */
131        u8 voltage_max[4];      /* Register values; [0] = VDD */
132        u8 iter_voltage[4];     /* Register values; [0] = VDD */
133        u8 fan[2];
134        u8 fan_min[2];
135        u8 temp;                /* Register values */
136        u8 temp_over;           /* Register values */
137        u8 temp_hyst;           /* Register values */
138        u8 alarms, beeps;       /* Register value */
139        u8 alarm_mask;          /* Register value */
140        u8 fan_div[2];          /* Register encoding, shifted right */
141        u8 beep_enable;         /* Boolean */
142        u8 iterate;             /* Voltage iteration mode */
143};
144
145static int gl518_attach_adapter(struct i2c_adapter *adapter);
146static int gl518_detect(struct i2c_adapter *adapter, int address,
147                        unsigned short flags, int kind);
148static void gl518_init_client(struct i2c_client *client);
149static int gl518_detach_client(struct i2c_client *client);
150
151static int gl518_read_value(struct i2c_client *client, u8 reg);
152static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value);
153static void gl518_update_client(struct i2c_client *client);
154
155static void gl518_update_client_rev00(struct i2c_client *client);
156static void gl518_update_iterate(struct i2c_client *client);
157
158static void gl518_vin(struct i2c_client *client, int operation,
159                      int ctl_name, int *nrels_mag, long *results);
160static void gl518_fan(struct i2c_client *client, int operation,
161                      int ctl_name, int *nrels_mag, long *results);
162static void gl518_temp(struct i2c_client *client, int operation,
163                       int ctl_name, int *nrels_mag, long *results);
164static void gl518_fan_div(struct i2c_client *client, int operation,
165                          int ctl_name, int *nrels_mag, long *results);
166static void gl518_alarms(struct i2c_client *client, int operation,
167                         int ctl_name, int *nrels_mag, long *results);
168static void gl518_beep(struct i2c_client *client, int operation,
169                       int ctl_name, int *nrels_mag, long *results);
170static void gl518_fan1off(struct i2c_client *client, int operation,
171                          int ctl_name, int *nrels_mag, long *results);
172static void gl518_iterate(struct i2c_client *client, int operation,
173                          int ctl_name, int *nrels_mag, long *results);
174
175/* This is the driver that will be inserted */
176static struct i2c_driver gl518_driver = {
177        .name           = "GL518SM sensor chip driver",
178        .id             = I2C_DRIVERID_GL518,
179        .flags          = I2C_DF_NOTIFY,
180        .attach_adapter = gl518_attach_adapter,
181        .detach_client  = gl518_detach_client,
182};
183
184/* -- SENSORS SYSCTL START -- */
185
186#define GL518_SYSCTL_VDD  1000  /* Volts * 100 */
187#define GL518_SYSCTL_VIN1 1001
188#define GL518_SYSCTL_VIN2 1002
189#define GL518_SYSCTL_VIN3 1003
190#define GL518_SYSCTL_FAN1 1101  /* RPM */
191#define GL518_SYSCTL_FAN2 1102
192#define GL518_SYSCTL_TEMP 1200  /* Degrees Celcius * 10 */
193#define GL518_SYSCTL_FAN_DIV 2000       /* 1, 2, 4 or 8 */
194#define GL518_SYSCTL_ALARMS 2001        /* bitvector */
195#define GL518_SYSCTL_BEEP 2002  /* bitvector */
196#define GL518_SYSCTL_FAN1OFF 2003
197#define GL518_SYSCTL_ITERATE 2004
198
199#define GL518_ALARM_VDD 0x01
200#define GL518_ALARM_VIN1 0x02
201#define GL518_ALARM_VIN2 0x04
202#define GL518_ALARM_VIN3 0x08
203#define GL518_ALARM_TEMP 0x10
204#define GL518_ALARM_FAN1 0x20
205#define GL518_ALARM_FAN2 0x40
206
207/* -- SENSORS SYSCTL END -- */
208
209/* These files are created for each detected GL518. This is just a template;
210   though at first sight, you might think we could use a statically
211   allocated list, we need some way to get back to the parent - which
212   is done through one of the 'extra' fields which are initialized
213   when a new copy is allocated. */
214static ctl_table gl518_dir_table_template[] = {
215        {GL518_SYSCTL_VIN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real,
216         &i2c_sysctl_real, NULL, &gl518_vin},
217        {GL518_SYSCTL_VIN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real,
218         &i2c_sysctl_real, NULL, &gl518_vin},
219        {GL518_SYSCTL_VIN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real,
220         &i2c_sysctl_real, NULL, &gl518_vin},
221        {GL518_SYSCTL_VDD, "in0", NULL, 0, 0644, NULL, &i2c_proc_real,
222         &i2c_sysctl_real, NULL, &gl518_vin},
223        {GL518_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real,
224         &i2c_sysctl_real, NULL, &gl518_fan},
225        {GL518_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real,
226         &i2c_sysctl_real, NULL, &gl518_fan},
227        {GL518_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real,
228         &i2c_sysctl_real, NULL, &gl518_temp},
229        {GL518_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &i2c_proc_real,
230         &i2c_sysctl_real, NULL, &gl518_fan_div},
231        {GL518_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real,
232         &i2c_sysctl_real, NULL, &gl518_alarms},
233        {GL518_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &i2c_proc_real,
234         &i2c_sysctl_real, NULL, &gl518_beep},
235        {GL518_SYSCTL_FAN1OFF, "fan1off", NULL, 0, 0644, NULL, &i2c_proc_real,
236         &i2c_sysctl_real, NULL, &gl518_fan1off},
237        {GL518_SYSCTL_ITERATE, "iterate", NULL, 0, 0644, NULL, &i2c_proc_real,
238         &i2c_sysctl_real, NULL, &gl518_iterate},
239        {0}
240};
241
242/* I choose here for semi-static GL518SM allocation. Complete dynamic
243   allocation could also be used; the code needed for this would probably
244   take more memory than the datastructure takes now. */
245#define MAX_GL518_NR 4
246static struct i2c_client *gl518_list[MAX_GL518_NR];
247
248static int gl518_attach_adapter(struct i2c_adapter *adapter)
249{
250        return i2c_detect(adapter, &addr_data, gl518_detect);
251}
252
253static int gl518_detect(struct i2c_adapter *adapter, int address,
254                        unsigned short flags, int kind)
255{
256        int i;
257        struct i2c_client *new_client;
258        struct gl518_data *data;
259        int err = 0;
260        const char *type_name = "";
261        const char *client_name = "";
262
263        /* Make sure we aren't probing the ISA bus!! This is just a safety check
264           at this moment; i2c_detect really won't call us. */
265#ifdef DEBUG
266        if (i2c_is_isa_adapter(adapter)) {
267                printk
268                    ("gl518sm.o: gl518_detect called for an ISA bus adapter?!?\n");
269                return 0;
270        }
271#endif
272
273        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
274                                     I2C_FUNC_SMBUS_WORD_DATA))
275                    goto ERROR0;
276
277        /* OK. For now, we presume we have a valid client. We now create the
278           client structure, even though we cannot fill it completely yet.
279           But it allows us to access gl518_{read,write}_value. */
280
281        if (!(data = kmalloc(sizeof(struct gl518_data), GFP_KERNEL))) {
282                err = -ENOMEM;
283                goto ERROR0;
284        }
285
286        new_client = &data->client;
287        new_client->addr = address;
288        new_client->data = data;
289        new_client->adapter = adapter;
290        new_client->driver = &gl518_driver;
291        new_client->flags = 0;
292
293        /* Now, we do the remaining detection. */
294
295        if (kind < 0) {
296                if (
297                    (gl518_read_value(new_client, GL518_REG_CHIP_ID) !=
298                     0x80)
299                    || (gl518_read_value(new_client, GL518_REG_CONF) &
300                        0x80)) goto ERROR1;
301        }
302
303        /* Determine the chip type. */
304        if (kind <= 0) {
305                i = gl518_read_value(new_client, GL518_REG_REVISION);
306                if (i == 0x00)
307                        kind = gl518sm_r00;
308                else if (i == 0x80)
309                        kind = gl518sm_r80;
310                else {
311                        if (kind == 0)
312                                printk
313                                    ("gl518sm.o: Ignoring 'force' parameter for unknown chip at "
314                                     "adapter %d, address 0x%02x\n",
315                                     i2c_adapter_id(adapter), address);
316                        goto ERROR1;
317                }
318        }
319
320        type_name = "gl518sm";
321        if (kind == gl518sm_r00) {
322                client_name = "GL518SM Revision 0x00 chip";
323        } else if (kind == gl518sm_r80) {
324                client_name = "GL518SM Revision 0x80 chip";
325        } else {
326#ifdef DEBUG
327                printk("gl518sm.o: Internal error: unknown kind (%d)?!?",
328                       kind);
329#endif
330                goto ERROR1;
331        }
332
333        /* Fill in the remaining client fields and put it into the global list */
334        strcpy(new_client->name, client_name);
335        data->type = kind;
336
337        for (i = 0; i < MAX_GL518_NR; i++)
338                if (!gl518_list[i])
339                        break;
340        if (i == MAX_GL518_NR) {
341                printk
342                    ("gl518sm.o: No empty slots left, recompile and heighten "
343                     "MAX_GL518_NR!\n");
344                err = -ENOMEM;
345                goto ERROR2;
346        }
347        gl518_list[i] = new_client;
348        data->valid = 0;
349        init_MUTEX(&data->update_lock);
350
351        /* Tell the I2C layer a new client has arrived */
352        if ((err = i2c_attach_client(new_client)))
353                goto ERROR3;
354
355        /* Register a new directory entry with module sensors */
356        if ((i = i2c_register_entry((struct i2c_client *) new_client,
357                                        type_name,
358                                        gl518_dir_table_template,
359                                        THIS_MODULE)) < 0) {
360                err = i;
361                goto ERROR4;
362        }
363        data->sysctl_id = i;
364
365        /* Initialize the GL518SM chip */
366        if (kind == gl518sm_r00)
367                data->iterate = 0;
368        else
369                data->iterate = 3;
370        data->iterate_lock = 0;
371        data->quit_thread = 0;
372        data->thread = NULL;
373        data->alarm_mask = 0xff;
374        data->voltage[0]=data->voltage[1]=data->voltage[2]=0;
375        gl518_init_client((struct i2c_client *) new_client);
376        return 0;
377
378/* OK, this is not exactly good programming practice, usually. But it is
379   very code-efficient in this case. */
380
381      ERROR4:
382        i2c_detach_client(new_client);
383      ERROR3:
384        for (i = 0; i < MAX_GL518_NR; i++)
385                if (new_client == gl518_list[i])
386                        gl518_list[i] = NULL;
387      ERROR2:
388      ERROR1:
389        kfree(data);
390      ERROR0:
391        return err;
392}
393
394
395/* Called when we have found a new GL518SM. It should set limits, etc. */
396static void gl518_init_client(struct i2c_client *client)
397{
398        /* Power-on defaults (bit 7=1) */
399        gl518_write_value(client, GL518_REG_CONF, 0x80);
400
401        /* No noisy output (bit 2=1), Comparator mode (bit 3=0), two fans (bit4=0),
402           standby mode (bit6=0) */
403        gl518_write_value(client, GL518_REG_CONF, 0x04);
404
405        /* Never interrupts */
406        gl518_write_value(client, GL518_REG_MASK, 0x00);
407
408        /* Clear status register (bit 5=1), start (bit6=1) */
409        gl518_write_value(client, GL518_REG_CONF, 0x24);
410        gl518_write_value(client, GL518_REG_CONF, 0x44);
411}
412
413static int gl518_detach_client(struct i2c_client *client)
414{
415        int err, i;
416        struct gl518_data *data = client->data;
417
418        i2c_deregister_entry(((struct gl518_data *) (client->data))->
419                                 sysctl_id);
420
421        if ((err = i2c_detach_client(client))) {
422                printk
423                    ("gl518sm.o: Client deregistration failed, client not detached.\n");
424                return err;
425        }
426
427        for (i = 0; i < MAX_GL518_NR; i++)
428                if (client == gl518_list[i])
429                        break;
430        if ((i == MAX_GL518_NR)) {
431                printk("gl518sm.o: Client to detach not found.\n");
432                return -ENOENT;
433        }
434        gl518_list[i] = NULL;
435
436        if (data->thread) {
437                data->quit_thread = 1;
438                wake_up_interruptible(&data->wq);
439        }
440
441        kfree(client->data);
442
443        return 0;
444}
445
446
447/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
448   GL518 uses a high-byte first convention, which is exactly opposite to
449   the usual practice. */
450static int gl518_read_value(struct i2c_client *client, u8 reg)
451{
452        if ((reg >= 0x07) && (reg <= 0x0c))
453                return swab16(i2c_smbus_read_word_data(client, reg));
454        else
455                return i2c_smbus_read_byte_data(client, reg);
456}
457
458/* Registers 0x07 to 0x0c are word-sized, others are byte-sized
459   GL518 uses a high-byte first convention, which is exactly opposite to
460   the usual practice. */
461static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value)
462{
463        if ((reg >= 0x07) && (reg <= 0x0c))
464                return i2c_smbus_write_word_data(client, reg, swab16(value));
465        else
466                return i2c_smbus_write_byte_data(client, reg, value);
467}
468
469static void gl518_update_client(struct i2c_client *client)
470{
471        struct gl518_data *data = client->data;
472        int val;
473
474        down(&data->update_lock);
475
476        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
477            (jiffies < data->last_updated) || !data->valid) {
478
479#ifdef DEBUG
480                printk("Starting gl518 update\n");
481#endif
482
483                data->alarms = gl518_read_value(client, GL518_REG_INT);
484                data->beeps = gl518_read_value(client, GL518_REG_ALARM);
485
486                val = gl518_read_value(client, GL518_REG_VDD_LIMIT);
487                data->voltage_min[0] = val & 0xff;
488                data->voltage_max[0] = (val >> 8) & 0xff;
489                val = gl518_read_value(client, GL518_REG_VIN1_LIMIT);
490                data->voltage_min[1] = val & 0xff;
491                data->voltage_max[1] = (val >> 8) & 0xff;
492                val = gl518_read_value(client, GL518_REG_VIN2_LIMIT);
493                data->voltage_min[2] = val & 0xff;
494                data->voltage_max[2] = (val >> 8) & 0xff;
495                val = gl518_read_value(client, GL518_REG_VIN3_LIMIT);
496                data->voltage_min[3] = val & 0xff;
497                data->voltage_max[3] = (val >> 8) & 0xff;
498
499                val = gl518_read_value(client, GL518_REG_FAN_COUNT);
500                data->fan[0] = (val >> 8) & 0xff;
501                data->fan[1] = val & 0xff;
502
503                val = gl518_read_value(client, GL518_REG_FAN_LIMIT);
504                data->fan_min[0] = (val >> 8) & 0xff;
505                data->fan_min[1] = val & 0xff;
506
507                data->temp = gl518_read_value(client, GL518_REG_TEMP);
508                data->temp_over =
509                    gl518_read_value(client, GL518_REG_TEMP_OVER);
510                data->temp_hyst =
511                    gl518_read_value(client, GL518_REG_TEMP_HYST);
512
513                val = gl518_read_value(client, GL518_REG_MISC);
514                data->fan_div[0] = (val >> 6) & 0x03;
515                data->fan_div[1] = (val >> 4) & 0x03;
516
517                data->alarms &= data->alarm_mask;
518
519                val = gl518_read_value(client, GL518_REG_CONF);
520                data->beep_enable = (val >> 2) & 1;
521
522#ifndef DEBUG_VIN
523                if (data->type != gl518sm_r00) {
524                        data->voltage[0] =
525                            gl518_read_value(client, GL518_REG_VDD);
526                        data->voltage[1] =
527                            gl518_read_value(client, GL518_REG_VIN1);
528                        data->voltage[2] =
529                            gl518_read_value(client, GL518_REG_VIN2);
530                        data->voltage[3] =
531                            gl518_read_value(client, GL518_REG_VIN3);
532                } else
533                        gl518_update_client_rev00(client);
534#else
535                gl518_update_client_rev00(client);
536#endif
537
538                data->last_updated = jiffies;
539                data->valid = 1;
540        }
541
542        up(&data->update_lock);
543}
544
545/* Here we decide how to run the iteration code.
546   When called, we trigger the iteration and report the last
547   measured voltage. No delay for user apps */
548static void gl518_update_client_rev00(struct i2c_client *client)
549{
550        struct gl518_data *data = client->data;
551        int i;
552
553        if (data->iterate == 1) {       /* 10 sec delay */
554                /* as that update is slow, we consider the data valid for 30 seconds */
555                if (
556                    ((jiffies - data->last_updated_v00 > 30 * HZ)
557                     || (data->alarms & 7)
558                     || (!data->valid)) && (!data->iterate_lock)) {
559                        data->iterate_lock = 1;
560                        gl518_update_iterate(client);
561                        data->iterate_lock = 0;
562                }
563                for (i = 0; i < 4; i++)
564                        data->voltage[i] = data->iter_voltage[i];
565        } else if (data->iterate == 2) {        /* show results of last iteration */
566                for (i = 0; i < 4; i++)
567                        data->voltage[i] = data->iter_voltage[i];
568                wake_up_interruptible(&data->wq);
569        } else {                /* no iteration */
570                data->voltage[3] =
571                    gl518_read_value(client, GL518_REG_VIN3);
572        }
573}
574
575static int gl518_update_thread(void *c)
576{
577        struct i2c_client *client = c;
578        struct gl518_data *data = client->data;
579
580#ifdef __SMP__
581        lock_kernel();
582#endif
583        exit_mm(current);
584        current->session = 1;
585        current->pgrp = 1;
586        sigfillset(&current->blocked);
587        current->fs->umask = 0;
588        strcpy(current->comm, "gl518sm");
589
590        init_waitqueue_head(&(data->wq));
591        data->thread = current;
592
593#ifdef __SMP__
594        unlock_kernel();
595#endif
596
597        for (;;) {
598                if (!data->iterate_lock) {
599                        data->iterate_lock = 1;
600                        gl518_update_iterate(client);
601                        data->iterate_lock = 0;
602                }
603
604                if ((data->quit_thread) || signal_pending(current))
605                        break;
606                interruptible_sleep_on(&data->wq);
607        }
608
609        data->thread = NULL;
610        data->quit_thread = 0;
611        return 0;
612}
613
614/* This updates vdd, vin1, vin2 values by doing slow and multiple
615   comparisons for the GL518SM rev 00 that lacks support for direct
616   reading of these values.   Values are kept in iter_voltage   */
617
618static void gl518_update_iterate(struct i2c_client *client)
619{
620        struct gl518_data *data = client->data;
621        int i, j, loop_more = 1, min[3], max[3], delta[3];
622        int alarm, beeps, irqs;
623
624#define VIN_REG(c) c==0?GL518_REG_VDD_LIMIT:\
625                   c==1?GL518_REG_VIN1_LIMIT:\
626                   GL518_REG_VIN2_LIMIT
627
628        /* disable beeps & irqs for vin0-2 */
629        beeps = gl518_read_value(client, GL518_REG_ALARM);
630        irqs = gl518_read_value(client, GL518_REG_MASK);
631        gl518_write_value(client, GL518_REG_ALARM, beeps & ~0x7);
632        gl518_write_value(client, GL518_REG_MASK, irqs & ~0x7);
633
634        alarm = data->alarms;
635
636        for (i = 0; i < 3; i++) {
637                if (alarm & (1 << i)) {
638                        min[i] = 0;
639                        max[i] = 127;
640                } else {
641                        min[i] = data->voltage_min[i];
642                        max[i] =
643                            (data->voltage_max[i] +
644                             data->voltage_min[i]) / 2;
645                }
646                delta[i] = (max[i] - min[i]) / 2;
647        }
648
649        for (j = 0; (j < 10 && loop_more); j++) {
650
651                for (i = 0; i < 3; i++)
652                        gl518_write_value(client, VIN_REG(i),
653                                          max[i] << 8 | min[i]);
654
655                if ((data->thread) &&
656                    ((data->quit_thread) || signal_pending(current)))
657                        goto finish;
658
659                /* we wait now 1.5 seconds before comparing */
660                current->state = TASK_INTERRUPTIBLE;
661                schedule_timeout(HZ + HZ / 2);
662
663                alarm = gl518_read_value(client, GL518_REG_INT);
664
665#ifdef DEBUG_VIN
666                printk("gl518sm: iteration %2d: %4d%c %4d%c %4d%c\n", j,
667                       max[0], (alarm & 1) ? '!' : ' ',
668                       max[1], (alarm & 2) ? '!' : ' ',
669                       max[2], (alarm & 4) ? '!' : ' ');
670#endif
671
672                for (loop_more = 0, i = 0; i < 3; i++) {
673                        if (alarm & (1 << i))
674                                max[i] += delta[i];
675                        else
676                                max[i] -= delta[i];
677
678                        if (delta[i])
679                                loop_more++;
680                        delta[i] >>= 1;
681                }
682
683        }
684
685        for (i = 0; i < 3; i++)
686                if (alarm & (1 << i))
687                        max[i]++;
688
689#ifdef DEBUG_VIN
690        printk("gl518sm:    final   :%5d %5d %5d\n", max[0], max[1],
691               max[2]);
692        printk("gl518sm:    meter   :%5d %5d %5d\n", data->voltage[0],
693               data->voltage[1], data->voltage[2]);
694#endif
695
696        /* update values, including vin3 */
697        for (i = 0; i < 3; i++) {
698                data->iter_voltage[i] = max[i];
699        }
700        data->iter_voltage[3] = gl518_read_value(client, GL518_REG_VIN3);
701        data->last_updated_v00 = jiffies;
702
703      finish:
704
705        /* reset values */
706        for (i = 0; i < 3; i++) {
707                gl518_write_value(client, VIN_REG(i),
708                                  data->voltage_max[i] << 8 | data->
709                                  voltage_min[i]);
710        }
711
712        gl518_write_value(client, GL518_REG_ALARM, beeps);
713        gl518_write_value(client, GL518_REG_MASK, irqs);
714
715#undef VIN_REG
716}
717
718void gl518_temp(struct i2c_client *client, int operation, int ctl_name,
719                int *nrels_mag, long *results)
720{
721        struct gl518_data *data = client->data;
722        if (operation == SENSORS_PROC_REAL_INFO)
723                *nrels_mag = 1;
724        else if (operation == SENSORS_PROC_REAL_READ) {
725                gl518_update_client(client);
726                results[0] = TEMP_FROM_REG(data->temp_over);
727                results[1] = TEMP_FROM_REG(data->temp_hyst);
728                results[2] = TEMP_FROM_REG(data->temp);
729                *nrels_mag = 3;
730        } else if (operation == SENSORS_PROC_REAL_WRITE) {
731                if (*nrels_mag >= 1) {
732                        data->temp_over = TEMP_TO_REG(results[0]);
733                        gl518_write_value(client, GL518_REG_TEMP_OVER,
734                                          data->temp_over);
735                }
736                if (*nrels_mag >= 2) {
737                        data->temp_hyst = TEMP_TO_REG(results[1]);
738                        gl518_write_value(client, GL518_REG_TEMP_HYST,
739                                          data->temp_hyst);
740                }
741        }
742}
743
744void gl518_vin(struct i2c_client *client, int operation, int ctl_name,
745               int *nrels_mag, long *results)
746{
747        struct gl518_data *data = client->data;
748        int nr = ctl_name - GL518_SYSCTL_VDD;
749        int regnr, old = 0;
750
751        if (operation == SENSORS_PROC_REAL_INFO)
752                *nrels_mag = 2;
753        else if (operation == SENSORS_PROC_REAL_READ) {
754                gl518_update_client(client);
755                results[0] = nr ? IN_FROM_REG(data->voltage_min[nr]) :
756                    VDD_FROM_REG(data->voltage_min[nr]);
757                results[1] = nr ? IN_FROM_REG(data->voltage_max[nr]) :
758                    VDD_FROM_REG(data->voltage_max[nr]);
759                results[2] = nr ? IN_FROM_REG(data->voltage[nr]) :
760                    VDD_FROM_REG(data->voltage[nr]);
761                *nrels_mag = 3;
762        } else if (operation == SENSORS_PROC_REAL_WRITE) {
763                regnr =
764                    nr == 0 ? GL518_REG_VDD_LIMIT : nr ==
765                    1 ? GL518_REG_VIN1_LIMIT : nr ==
766                    2 ? GL518_REG_VIN2_LIMIT : GL518_REG_VIN3_LIMIT;
767                if (*nrels_mag == 1)
768                        old = gl518_read_value(client, regnr) & 0xff00;
769                if (*nrels_mag >= 2) {
770                        data->voltage_max[nr] =
771                            nr ? IN_TO_REG(results[1]) :
772                            VDD_TO_REG(results[1]);
773                        old = data->voltage_max[nr] << 8;
774                }
775                if (*nrels_mag >= 1) {
776                        data->voltage_min[nr] =
777                            nr ? IN_TO_REG(results[0]) :
778                            VDD_TO_REG(results[0]);
779                        old |= data->voltage_min[nr];
780                        gl518_write_value(client, regnr, old);
781                }
782        }
783}
784
785
786void gl518_fan(struct i2c_client *client, int operation, int ctl_name,
787               int *nrels_mag, long *results)
788{
789        struct gl518_data *data = client->data;
790        int nr = ctl_name - GL518_SYSCTL_FAN1;
791        int old;
792
793        if (operation == SENSORS_PROC_REAL_INFO)
794                *nrels_mag = 0;
795        else if (operation == SENSORS_PROC_REAL_READ) {
796                gl518_update_client(client);
797                results[0] = FAN_FROM_REG(data->fan_min[nr],
798                                          DIV_FROM_REG(data->fan_div[nr]));
799                results[1] =
800                    FAN_FROM_REG(data->fan[nr],
801                                 DIV_FROM_REG(data->fan_div[nr]));
802                *nrels_mag = 2;
803        } else if (operation == SENSORS_PROC_REAL_WRITE) {
804                if (*nrels_mag >= 1) {
805                        data->fan_min[nr] = FAN_TO_REG(results[0],
806                                                       DIV_FROM_REG(data->
807                                                                    fan_div
808                                                                    [nr]));
809                        old =
810                            gl518_read_value(client, GL518_REG_FAN_LIMIT);
811
812                        if (nr == 0) {
813                                old =
814                                    (old & 0x00ff) | (data->
815                                                      fan_min[0] << 8);
816                                if (results[0] == 0)
817                                        data->alarm_mask &= ~0x20;
818                                else
819                                        data->alarm_mask |= 0x20;
820                        } else {
821                                old = (old & 0xff00) | data->fan_min[1];
822                                if (results[0] == 0)
823                                        data->alarm_mask &= ~0x40;
824                                else
825                                        data->alarm_mask |= 0x40;
826                        }
827                        gl518_write_value(client, GL518_REG_FAN_LIMIT,
828                                          old);
829                }
830        }
831}
832
833
834void gl518_alarms(struct i2c_client *client, int operation, int ctl_name,
835                  int *nrels_mag, long *results)
836{
837        struct gl518_data *data = client->data;
838        if (operation == SENSORS_PROC_REAL_INFO)
839                *nrels_mag = 0;
840        else if (operation == SENSORS_PROC_REAL_READ) {
841                gl518_update_client(client);
842                results[0] = ALARMS_FROM_REG(data->alarms);
843                *nrels_mag = 1;
844        }
845}
846
847void gl518_beep(struct i2c_client *client, int operation, int ctl_name,
848                int *nrels_mag, long *results)
849{
850        struct gl518_data *data = client->data;
851        if (operation == SENSORS_PROC_REAL_INFO)
852                *nrels_mag = 0;
853        else if (operation == SENSORS_PROC_REAL_READ) {
854                gl518_update_client(client);
855                results[0] = BEEP_ENABLE_FROM_REG(data->beep_enable);
856                results[1] = BEEPS_FROM_REG(data->beeps);
857                *nrels_mag = 2;
858        } else if (operation == SENSORS_PROC_REAL_WRITE) {
859                if (*nrels_mag >= 1) {
860                        data->beep_enable = BEEP_ENABLE_TO_REG(results[0]);
861                        gl518_write_value(client, GL518_REG_CONF,
862                                          (gl518_read_value(client,
863                                                            GL518_REG_CONF)
864                                           & 0xfb) | (data->
865                                                      beep_enable << 2));
866                }
867                if (*nrels_mag >= 2) {
868                        data->beeps =
869                            BEEPS_TO_REG(results[1]) & data->alarm_mask;
870                        gl518_write_value(client, GL518_REG_ALARM,
871                                          data->beeps);
872                }
873        }
874}
875
876
877void gl518_fan_div(struct i2c_client *client, int operation, int ctl_name,
878                   int *nrels_mag, long *results)
879{
880        struct gl518_data *data = client->data;
881        int old;
882        if (operation == SENSORS_PROC_REAL_INFO)
883                *nrels_mag = 0;
884        else if (operation == SENSORS_PROC_REAL_READ) {
885                gl518_update_client(client);
886                results[0] = DIV_FROM_REG(data->fan_div[0]);
887                results[1] = DIV_FROM_REG(data->fan_div[1]);
888                *nrels_mag = 2;
889        } else if (operation == SENSORS_PROC_REAL_WRITE) {
890                old = gl518_read_value(client, GL518_REG_MISC);
891                if (*nrels_mag >= 2) {
892                        data->fan_div[1] = DIV_TO_REG(results[1]);
893                        old = (old & 0xcf) | (data->fan_div[1] << 4);
894                }
895                if (*nrels_mag >= 1) {
896                        data->fan_div[0] = DIV_TO_REG(results[0]);
897                        old = (old & 0x3f) | (data->fan_div[0] << 6);
898                }
899                gl518_write_value(client, GL518_REG_MISC, old);
900        }
901}
902
903void gl518_fan1off(struct i2c_client *client, int operation, int ctl_name,
904                   int *nrels_mag, long *results)
905{
906        int old;
907        if (operation == SENSORS_PROC_REAL_INFO)
908                *nrels_mag = 0;
909        else if (operation == SENSORS_PROC_REAL_READ) {
910                results[0] =
911                    ((gl518_read_value(client, GL518_REG_MISC) & 0x08) !=
912                     0);
913                results[1] =
914                    ((gl518_read_value(client, GL518_REG_CONF) & 0x10) !=
915                     0);
916                *nrels_mag = 2;
917        } else if (operation == SENSORS_PROC_REAL_WRITE) {
918                if (*nrels_mag >= 1) {
919                        old =
920                            gl518_read_value(client,
921                                             GL518_REG_MISC) & 0xf7;
922                        if (results[0])
923                                old |= 0x08;
924                        gl518_write_value(client, GL518_REG_MISC, old);
925                }
926                if (*nrels_mag >= 2) {
927                        old =
928                            gl518_read_value(client,
929                                             GL518_REG_CONF) & 0xef;
930                        if (results[1])
931                                old |= 0x10;
932                        gl518_write_value(client, GL518_REG_CONF, old);
933                }
934        }
935}
936
937void gl518_iterate(struct i2c_client *client, int operation, int ctl_name,
938                   int *nrels_mag, long *results)
939{
940        struct gl518_data *data = client->data;
941        int i;
942        if (operation == SENSORS_PROC_REAL_INFO)
943                *nrels_mag = 0;
944        else if (operation == SENSORS_PROC_REAL_READ) {
945                results[0] = data->iterate;
946                *nrels_mag = 1;
947        } else if (operation == SENSORS_PROC_REAL_WRITE &&
948                   data->type == gl518sm_r00 ) {
949                if ((*nrels_mag >= 1) && (data->iterate != results[0])) {
950                        data->iterate = results[0];
951                        for (i = 0; i < 4; i++) {
952                                data->voltage[i] = 0;
953                                data->iter_voltage[i] = 0;
954                        }
955                        data->valid = 0;
956
957                        if ((data->iterate != 2) && (data->thread)) {
958                                data->quit_thread = 1;
959                                wake_up_interruptible(&data->wq);
960                        } else if ((data->iterate == 2) && (!data->thread)) {
961                                init_waitqueue_head(&(data->wq));
962                                kernel_thread(gl518_update_thread,
963                                              (void *) client, 0);
964                        }
965                }
966        }
967}
968
969static int __init sm_gl518sm_init(void)
970{
971        printk("gl518sm.o version %s (%s)\n", LM_VERSION, LM_DATE);
972        return i2c_add_driver(&gl518_driver);
973}
974
975static void __exit sm_gl518sm_exit(void)
976{
977        i2c_del_driver(&gl518_driver);
978}
979
980
981
982MODULE_AUTHOR
983    ("Frodo Looijaard <frodol@dds.nl> and Kyösti Mälkki <kmalkki@cc.hut.fi>");
984MODULE_DESCRIPTION("GL518SM driver");
985
986module_init(sm_gl518sm_init);
987module_exit(sm_gl518sm_exit);
Note: See TracBrowser for help on using the browser.