root/lm-sensors/trunk/src/lm80.c @ 128

Revision 128, 23.5 KB (checked in by frodo, 14 years ago)

Fan value problems resolved

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    lm80.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 1998  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#include <linux/module.h>
23#include <linux/malloc.h>
24#include <linux/proc_fs.h>
25#include <linux/ioport.h>
26#include <linux/sysctl.h>
27#include <asm/errno.h>
28#include <asm/io.h>
29#include <linux/types.h>
30#include "smbus.h"
31#include "version.h"
32#include "isa.h"
33#include "sensors.h"
34#include "i2c.h"
35#include "compat.h"
36
37/* Many LM80 constants specified below */
38
39/* The LM80 registers */
40#define LM80_REG_IN_MAX(nr) (0x2a + (nr) * 2)
41#define LM80_REG_IN_MIN(nr) (0x2b + (nr) * 2)
42#define LM80_REG_IN(nr) (0x20 + (nr))
43
44#define LM80_REG_FAN1_MIN 0x3c
45#define LM80_REG_FAN2_MIN 0x3d
46#define LM80_REG_FAN1 0x28
47#define LM80_REG_FAN2 0x29
48
49#define LM80_REG_TEMP 0x27
50#define LM80_REG_TEMP_HOT_MAX 0x38
51#define LM80_REG_TEMP_HOT_HYST 0x39
52#define LM80_REG_TEMP_OS_MAX 0x3a
53#define LM80_REG_TEMP_OS_HYST 0x3b
54
55#define LM80_REG_CONFIG 0x00
56#define LM80_REG_ALARM1 0x01
57#define LM80_REG_ALARM2 0x02
58#define LM80_REG_MASK1 0x03
59#define LM80_REG_MASK2 0x04
60#define LM80_REG_FANDIV 0x05
61#define LM80_REG_RES 0x06
62
63
64/* Conversions. Rounding is only done on the TO_REG variants. */
65#define IN_TO_REG(val,nr) ((val) & 0xff)
66#define IN_FROM_REG(val,nr) (val)
67
68#define FAN_TO_REG(val,div) ((val)==0?255:\
69                             ((1350000+(val)*(div)/2)/((val)*(div))) & 0xff)
70#define FAN_FROM_REG(val,div) ((val)==0?-1:\
71                               (val)==255?0:1350000/((div)*(val)))
72
73#define TEMP_FROM_REG(val) lm80_temp_from_reg(val)
74
75#define TEMP_LIMIT_TO_REG(val) (((val)<0?(((val)-50)/100)&0xff:\
76                                           ((val)+50)/100) & 0xff)
77#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*100)
78
79#define ALARMS_FROM_REG(val) (val)
80
81#define DIV_FROM_REG(val) (1 << (val))
82#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
83
84/* Initial limits */
85#define LM80_INIT_IN_0 190
86#define LM80_INIT_IN_1 190
87#define LM80_INIT_IN_2 190
88#define LM80_INIT_IN_3 190
89#define LM80_INIT_IN_4 190
90#define LM80_INIT_IN_5 190
91#define LM80_INIT_IN_6 190
92
93#define LM80_INIT_IN_PERCENTAGE 10
94
95#define LM80_INIT_IN_MIN_0 \
96        (LM80_INIT_IN_0 - LM80_INIT_IN_0 * LM80_INIT_IN_PERCENTAGE / 100)
97#define LM80_INIT_IN_MAX_0 \
98        (LM80_INIT_IN_0 + LM80_INIT_IN_0 * LM80_INIT_IN_PERCENTAGE / 100)
99#define LM80_INIT_IN_MIN_1 \
100        (LM80_INIT_IN_1 - LM80_INIT_IN_1 * LM80_INIT_IN_PERCENTAGE / 100)
101#define LM80_INIT_IN_MAX_1 \
102        (LM80_INIT_IN_1 + LM80_INIT_IN_1 * LM80_INIT_IN_PERCENTAGE / 100)
103#define LM80_INIT_IN_MIN_2 \
104        (LM80_INIT_IN_2 - LM80_INIT_IN_2 * LM80_INIT_IN_PERCENTAGE / 100)
105#define LM80_INIT_IN_MAX_2 \
106        (LM80_INIT_IN_2 + LM80_INIT_IN_2 * LM80_INIT_IN_PERCENTAGE / 100)
107#define LM80_INIT_IN_MIN_3 \
108        (LM80_INIT_IN_3 - LM80_INIT_IN_3 * LM80_INIT_IN_PERCENTAGE / 100)
109#define LM80_INIT_IN_MAX_3 \
110        (LM80_INIT_IN_3 + LM80_INIT_IN_3 * LM80_INIT_IN_PERCENTAGE / 100)
111#define LM80_INIT_IN_MIN_4 \
112        (LM80_INIT_IN_4 - LM80_INIT_IN_4 * LM80_INIT_IN_PERCENTAGE / 100)
113#define LM80_INIT_IN_MAX_4 \
114        (LM80_INIT_IN_4 + LM80_INIT_IN_4 * LM80_INIT_IN_PERCENTAGE / 100)
115#define LM80_INIT_IN_MIN_5 \
116        (LM80_INIT_IN_5 - LM80_INIT_IN_5 * LM80_INIT_IN_PERCENTAGE / 100)
117#define LM80_INIT_IN_MAX_5 \
118        (LM80_INIT_IN_5 + LM80_INIT_IN_5 * LM80_INIT_IN_PERCENTAGE / 100)
119#define LM80_INIT_IN_MIN_6 \
120        (LM80_INIT_IN_6 - LM80_INIT_IN_6 * LM80_INIT_IN_PERCENTAGE / 100)
121#define LM80_INIT_IN_MAX_6 \
122        (LM80_INIT_IN_6 + LM80_INIT_IN_6 * LM80_INIT_IN_PERCENTAGE / 100)
123
124#define LM80_INIT_FAN_MIN_1 3000
125#define LM80_INIT_FAN_MIN_2 3000
126
127#define LM80_INIT_TEMP_OS_MAX 600
128#define LM80_INIT_TEMP_OS_HYST 500
129#define LM80_INIT_TEMP_HOT_MAX 700
130#define LM80_INIT_TEMP_HOT_HYST 600
131
132#ifdef MODULE
133extern int init_module(void);
134extern int cleanup_module(void);
135#endif /* MODULE */
136
137/* For each registered LM80, we need to keep some data in memory. That
138   data is pointed to by lm80_list[NR]->data. The structure itself is
139   dynamically allocated, at the same time when a new lm80 client is
140   allocated. */
141struct lm80_data {
142         int sysctl_id;
143
144         struct semaphore update_lock;
145         char valid;                 /* !=0 if following fields are valid */
146         unsigned long last_updated; /* In jiffies */
147
148         u8 in[7];                   /* Register value */
149         u8 in_max[7];               /* Register value */
150         u8 in_min[7];               /* Register value */
151         u8 fan[2];                  /* Register value */
152         u8 fan_min[2];              /* Register value */
153         u8 fan_div[2];              /* Register encoding, shifted right */
154         u16 temp;                   /* Register values, shifted right */
155         u8 temp_hot_max;            /* Register value */
156         u8 temp_hot_hyst;           /* Register value */
157         u8 temp_os_max;             /* Register value */
158         u8 temp_os_hyst;            /* Register value */
159         u16 alarms;                 /* Register encoding, combined */
160};
161
162
163static int lm80_init(void);
164static int lm80_cleanup(void);
165
166static int lm80_attach_adapter(struct i2c_adapter *adapter);
167static int lm80_detach_client(struct i2c_client *client);
168static int lm80_new_client(struct i2c_adapter *adapter,
169                           struct i2c_client *new_client);
170static void lm80_remove_client(struct i2c_client *client);
171static int lm80_command(struct i2c_client *client, unsigned int cmd, 
172                        void *arg);
173static void lm80_inc_use (struct i2c_client *client);
174static void lm80_dec_use (struct i2c_client *client);
175
176static long lm80_temp_from_reg(u16 regs);
177
178static int lm80_read_value(struct i2c_client *client, u8 register);
179static int lm80_write_value(struct i2c_client *client, u8 register, u8 value);
180static void lm80_update_client(struct i2c_client *client);
181static void lm80_init_client(struct i2c_client *client);
182
183
184static void lm80_in(struct i2c_client *client, int operation, int ctl_name,
185                    int *nrels_mag, long *results);
186static void lm80_fan(struct i2c_client *client, int operation, int ctl_name,
187                     int *nrels_mag, long *results);
188static void lm80_temp(struct i2c_client *client, int operation, int ctl_name,
189                      int *nrels_mag, long *results);
190static void lm80_alarms(struct i2c_client *client, int operation, int ctl_name,
191                        int *nrels_mag, long *results);
192static void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name,
193                         int *nrels_mag, long *results);
194
195/* I choose here for semi-static LM80 allocation. Complete dynamic
196   allocation could also be used; the code needed for this would probably
197   take more memory than the datastructure takes now. */
198#define MAX_LM80_NR 4
199static struct i2c_client *lm80_list[MAX_LM80_NR];
200
201/* The driver. I choose to use type i2c_driver, as at is identical to both
202   smbus_driver and isa_driver, and clients could be of either kind */
203static struct i2c_driver lm80_driver = {
204  /* name */            "LM80 sensor driver",
205  /* id */              I2C_DRIVERID_LM80,
206  /* flags */           DF_NOTIFY,
207  /* attach_adapter */  &lm80_attach_adapter,
208  /* detach_client */   &lm80_detach_client,
209  /* command */         &lm80_command,
210  /* inc_use */         &lm80_inc_use,
211  /* dec_use */         &lm80_dec_use
212};
213
214/* Used by lm80_init/cleanup */
215static int lm80_initialized = 0;
216
217/* The /proc/sys entries */
218/* These files are created for each detected LM80. This is just a template;
219   though at first sight, you might think we could use a statically
220   allocated list, we need some way to get back to the parent - which
221   is done through one of the 'extra' fields which are initialized
222   when a new copy is allocated. */
223static ctl_table lm80_dir_table_template[] = {
224  { LM80_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &sensors_proc_real,
225    &sensors_sysctl_real, NULL, &lm80_in },
226  { LM80_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &sensors_proc_real,
227    &sensors_sysctl_real, NULL, &lm80_in },
228  { LM80_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &sensors_proc_real,
229    &sensors_sysctl_real, NULL, &lm80_in },
230  { LM80_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &sensors_proc_real,
231    &sensors_sysctl_real, NULL, &lm80_in },
232  { LM80_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &sensors_proc_real,
233    &sensors_sysctl_real, NULL, &lm80_in },
234  { LM80_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &sensors_proc_real,
235    &sensors_sysctl_real, NULL, &lm80_in },
236  { LM80_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &sensors_proc_real,
237    &sensors_sysctl_real, NULL, &lm80_in },
238  { LM80_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real,
239    &sensors_sysctl_real, NULL, &lm80_fan },
240  { LM80_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real,
241    &sensors_sysctl_real, NULL, &lm80_fan },
242  { LM80_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real,
243    &sensors_sysctl_real, NULL, &lm80_temp },
244  { LM80_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real,
245    &sensors_sysctl_real, NULL, &lm80_fan_div },
246  { LM80_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real,
247    &sensors_sysctl_real, NULL, &lm80_alarms },
248  { 0 }
249};
250
251
252int lm80_attach_adapter(struct i2c_adapter *adapter)
253{
254  int address,err;
255  struct i2c_client *new_client;
256  const char *type_name,*client_name;
257
258  /* OK, this is no detection. I know. It will do for now, though.  */
259  err = 0;
260  for (address = 0x20; (! err) && (address <= 0x2f); address ++) {
261
262    /* Later on, we will keep a list of registered addresses for each
263       adapter, and check whether they are used here */
264
265    if (smbus_read_byte_data(adapter,address,LM80_REG_CONFIG) < 0) 
266      continue;
267
268    /* Real detection code goes here */
269
270    printk("lm80.o: LM80 detected\n");
271    type_name = "lm80";
272    client_name = "LM80 chip";
273
274
275    /* Allocate space for a new client structure. To counter memory
276       fragmentation somewhat, we only do one kmalloc. */
277    if (! (new_client = kmalloc(sizeof(struct i2c_client) + 
278                                sizeof(struct lm80_data),
279                               GFP_KERNEL))) {
280      err = -ENOMEM;
281      continue;
282    }
283
284    /* Fill the new client structure with data */
285    new_client->data = (struct lm80_data *) (new_client + 1);
286    new_client->addr = address;
287    strcpy(new_client->name,client_name);
288    if ((err = lm80_new_client(adapter,new_client)))
289      goto ERROR2;
290
291    /* Tell i2c-core a new client has arrived */
292    if ((err = i2c_attach_client(new_client))) 
293      goto ERROR3;
294
295    /* Register a new directory entry with module sensors */
296    if ((err = sensors_register_entry(new_client,type_name,
297                                      lm80_dir_table_template)) < 0)
298      goto ERROR4;
299    ((struct lm80_data *) (new_client->data))->sysctl_id = err;
300    err = 0;
301
302    /* Initialize the LM80 chip */
303    lm80_init_client(new_client);
304    continue;
305
306/* OK, this is not exactly good programming practice, usually. But it is
307   very code-efficient in this case. */
308ERROR4:
309    i2c_detach_client(new_client);
310ERROR3:
311    lm80_remove_client((struct i2c_client *) new_client);
312ERROR2:
313    kfree(new_client);
314  }
315  return err;
316}
317
318int lm80_detach_client(struct i2c_client *client)
319{
320  int err,i;
321  for (i = 0; i < MAX_LM80_NR; i++)
322    if (client == lm80_list[i])
323      break;
324  if ((i == MAX_LM80_NR)) {
325    printk("lm80.o: Client to detach not found.\n");
326    return -ENOENT;
327  }
328
329  sensors_deregister_entry(((struct lm80_data *)(client->data))->sysctl_id);
330
331  if ((err = i2c_detach_client(client))) {
332    printk("lm80.o: Client deregistration failed, client not detached.\n");
333    return err;
334  }
335  lm80_remove_client(client);
336  kfree(client);
337  return 0;
338}
339
340
341/* Find a free slot, and initialize most of the fields */
342int lm80_new_client(struct i2c_adapter *adapter,
343                    struct i2c_client *new_client)
344{
345  int i;
346  struct lm80_data *data;
347
348  /* First, seek out an empty slot */
349  for(i = 0; i < MAX_LM80_NR; i++)
350    if (! lm80_list[i])
351      break;
352  if (i == MAX_LM80_NR) {
353    printk("lm80.o: No empty slots left, recompile and heighten "
354           "MAX_LM80_NR!\n");
355    return -ENOMEM;
356  }
357 
358  lm80_list[i] = new_client;
359  new_client->id = i;
360  new_client->adapter = adapter;
361  new_client->driver = &lm80_driver;
362  data = new_client->data;
363  data->valid = 0;
364  data->update_lock = MUTEX;
365  return 0;
366}
367
368/* Inverse of lm80_new_client */
369void lm80_remove_client(struct i2c_client *client)
370{
371  int i;
372  for (i = 0; i < MAX_LM80_NR; i++)
373    if (client == lm80_list[i]) 
374      lm80_list[i] = NULL;
375}
376
377/* No commands defined yet */
378int lm80_command(struct i2c_client *client, unsigned int cmd, void *arg)
379{
380  return 0;
381}
382
383void lm80_inc_use (struct i2c_client *client)
384{
385#ifdef MODULE
386  MOD_INC_USE_COUNT;
387#endif
388}
389
390void lm80_dec_use (struct i2c_client *client)
391{
392#ifdef MODULE
393  MOD_DEC_USE_COUNT;
394#endif
395}
396 
397
398long lm80_temp_from_reg(u16 temp)
399{
400  long res;
401  res = ((temp & 0xff00) >> 8) * 10000 + ((temp & 0x10) >> 4) * 5000 +
402        ((temp & 0x20) >> 5) * 2500 + ((temp & 0x40) >> 6) * 1250 +
403        ((temp & 0x80) >> 7) * 625;
404  temp /= 100;
405  if (temp >= 0x80 * 100)
406    temp = - (0x100 * 100 - temp);
407  return temp;
408}
409
410int lm80_read_value(struct i2c_client *client, u8 reg)
411{
412  return smbus_read_byte_data(client->adapter,client->addr, reg);
413}
414
415int lm80_write_value(struct i2c_client *client, u8 reg, u8 value)
416{
417  return smbus_write_byte_data(client->adapter, client->addr, reg,value);
418}
419
420/* Called when we have found a new LM80. It should set limits, etc. */
421void lm80_init_client(struct i2c_client *client)
422{
423  /* Reset all except Watchdog values and last conversion values
424     This sets fan-divs to 2, among others. This makes most other
425     initializations unnecessary */
426  lm80_write_value(client,LM80_REG_CONFIG,0x80);
427  /* Set 11-bit temperature resolution */
428  lm80_write_value(client,LM80_REG_RES,0x08);
429
430  lm80_write_value(client,LM80_REG_IN_MIN(0),IN_TO_REG(LM80_INIT_IN_MIN_0,0));
431  lm80_write_value(client,LM80_REG_IN_MAX(0),IN_TO_REG(LM80_INIT_IN_MAX_0,0));
432  lm80_write_value(client,LM80_REG_IN_MIN(1),IN_TO_REG(LM80_INIT_IN_MIN_1,1));
433  lm80_write_value(client,LM80_REG_IN_MAX(1),IN_TO_REG(LM80_INIT_IN_MAX_1,1));
434  lm80_write_value(client,LM80_REG_IN_MIN(2),IN_TO_REG(LM80_INIT_IN_MIN_2,2));
435  lm80_write_value(client,LM80_REG_IN_MAX(2),IN_TO_REG(LM80_INIT_IN_MAX_2,2));
436  lm80_write_value(client,LM80_REG_IN_MIN(3),IN_TO_REG(LM80_INIT_IN_MIN_3,3));
437  lm80_write_value(client,LM80_REG_IN_MAX(3),IN_TO_REG(LM80_INIT_IN_MAX_3,3));
438  lm80_write_value(client,LM80_REG_IN_MIN(4),IN_TO_REG(LM80_INIT_IN_MIN_4,4));
439  lm80_write_value(client,LM80_REG_IN_MAX(4),IN_TO_REG(LM80_INIT_IN_MAX_4,4));
440  lm80_write_value(client,LM80_REG_IN_MIN(5),IN_TO_REG(LM80_INIT_IN_MIN_5,5));
441  lm80_write_value(client,LM80_REG_IN_MAX(5),IN_TO_REG(LM80_INIT_IN_MAX_5,5));
442  lm80_write_value(client,LM80_REG_IN_MIN(6),IN_TO_REG(LM80_INIT_IN_MIN_6,6));
443  lm80_write_value(client,LM80_REG_IN_MAX(6),IN_TO_REG(LM80_INIT_IN_MAX_6,6));
444  lm80_write_value(client,LM80_REG_FAN1_MIN,FAN_TO_REG(LM80_INIT_FAN_MIN_1,2));
445  lm80_write_value(client,LM80_REG_FAN2_MIN,FAN_TO_REG(LM80_INIT_FAN_MIN_2,2));
446  lm80_write_value(client,LM80_REG_TEMP_HOT_MAX,
447                   TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_MAX));
448  lm80_write_value(client,LM80_REG_TEMP_HOT_HYST,
449                   TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_HYST));
450  lm80_write_value(client,LM80_REG_TEMP_OS_MAX,
451                   TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_MAX));
452  lm80_write_value(client,LM80_REG_TEMP_OS_HYST,
453                   TEMP_LIMIT_TO_REG(LM80_INIT_TEMP_OS_HYST));
454
455  /* Start monitoring */
456  lm80_write_value(client,LM80_REG_CONFIG,0x01);
457}
458
459void lm80_update_client(struct i2c_client *client)
460{
461  struct lm80_data *data = client->data;
462  int i;
463
464  down(&data->update_lock);
465
466  if ((jiffies - data->last_updated > 2*HZ ) ||
467      (jiffies < data->last_updated) || ! data->valid) {
468
469#ifdef DEBUG
470    printk("Starting lm80 update\n");
471#endif
472    for (i = 0; i <= 6; i++) {
473      data->in[i]     = lm80_read_value(client,LM80_REG_IN(i));
474      data->in_min[i] = lm80_read_value(client,LM80_REG_IN_MIN(i));
475      data->in_max[i] = lm80_read_value(client,LM80_REG_IN_MAX(i));
476    }
477    data->fan[0] = lm80_read_value(client,LM80_REG_FAN1);
478    data->fan_min[0] = lm80_read_value(client,LM80_REG_FAN1_MIN);
479    data->fan[1] = lm80_read_value(client,LM80_REG_FAN2);
480    data->fan_min[1] = lm80_read_value(client,LM80_REG_FAN2_MIN);
481   
482    data->temp = (lm80_read_value(client,LM80_REG_TEMP) << 8) |
483                 (lm80_read_value(client,LM80_REG_RES) & 0xf0);
484    data->temp_os_max = lm80_read_value(client,LM80_REG_TEMP_OS_MAX);
485    data->temp_os_hyst = lm80_read_value(client,LM80_REG_TEMP_OS_HYST);
486    data->temp_hot_max = lm80_read_value(client,LM80_REG_TEMP_HOT_MAX);
487    data->temp_hot_hyst = lm80_read_value(client,LM80_REG_TEMP_HOT_HYST);
488
489    i = lm80_read_value(client,LM80_REG_FANDIV);
490    data->fan_div[0] = (i >> 2) & 0x03;
491    data->fan_div[1] = (i >> 4) & 0x03;
492    data->alarms = lm80_read_value(client,LM80_REG_ALARM1) +
493                   (lm80_read_value(client,LM80_REG_ALARM2) << 8);
494    data->last_updated = jiffies;
495    data->valid = 1;
496  }
497
498  up(&data->update_lock);
499}
500
501
502/* The next few functions are the call-back functions of the /proc/sys and
503   sysctl files. Which function is used is defined in the ctl_table in
504   the extra1 field.
505   Each function must return the magnitude (power of 10 to divide the date
506   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
507   put a maximum of *nrels elements in results reflecting the data of this
508   file, and set *nrels to the number it actually put in it, if operation==
509   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
510   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
511   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
512   large enough (by checking the incoming value of *nrels). This is not very
513   good practice, but as long as you put less than about 5 values in results,
514   you can assume it is large enough. */
515void lm80_in(struct i2c_client *client, int operation, int ctl_name, 
516             int *nrels_mag, long *results)
517{
518  struct lm80_data *data = client->data;
519  int nr = ctl_name - LM80_SYSCTL_IN0;
520
521  if (operation == SENSORS_PROC_REAL_INFO)
522    *nrels_mag = 2;
523  else if (operation == SENSORS_PROC_REAL_READ) {
524    lm80_update_client(client);
525    results[0] = IN_FROM_REG(data->in_min[nr],nr);
526    results[1] = IN_FROM_REG(data->in_max[nr],nr);
527    results[2] = IN_FROM_REG(data->in[nr],nr);
528    *nrels_mag = 3;
529  } else if (operation == SENSORS_PROC_REAL_WRITE) {
530      if (*nrels_mag >= 1) {
531        data->in_min[nr] = IN_TO_REG(results[0],nr);
532        lm80_write_value(client,LM80_REG_IN_MIN(nr),data->in_min[nr]);
533      }
534      if (*nrels_mag >= 2) {
535        data->in_max[nr] = IN_TO_REG(results[1],nr);
536        lm80_write_value(client,LM80_REG_IN_MAX(nr),data->in_max[nr]);
537      }
538  }
539}
540
541void lm80_fan(struct i2c_client *client, int operation, int ctl_name,
542              int *nrels_mag, long *results)
543{
544  struct lm80_data *data = client->data;
545  int nr = ctl_name - LM80_SYSCTL_FAN1 + 1;
546
547  if (operation == SENSORS_PROC_REAL_INFO)
548    *nrels_mag = 0;
549  else if (operation == SENSORS_PROC_REAL_READ) {
550    lm80_update_client(client);
551    results[0] = FAN_FROM_REG(data->fan_min[nr-1],data->fan_div[nr-1]);
552    results[1] = FAN_FROM_REG(data->fan[nr-1],data->fan_div[nr-1]);
553    *nrels_mag = 2;
554  } else if (operation == SENSORS_PROC_REAL_WRITE) {
555    if (*nrels_mag >= 1) {
556      data->fan_min[nr-1] = FAN_TO_REG(results[0],data->fan_div[nr-1]);
557      lm80_write_value(client,nr==1?LM80_REG_FAN1_MIN:LM80_REG_FAN2_MIN,
558                       data->fan_min[nr-1]);
559    }
560  }
561}
562
563
564void lm80_temp(struct i2c_client *client, int operation, int ctl_name,
565               int *nrels_mag, long *results)
566{
567  struct lm80_data *data = client->data;
568  if (operation == SENSORS_PROC_REAL_INFO)
569    *nrels_mag = 1;
570  else if (operation == SENSORS_PROC_REAL_READ) {
571    lm80_update_client(client);
572    results[0] = TEMP_LIMIT_FROM_REG(data->temp_hot_max);
573    results[1] = TEMP_LIMIT_FROM_REG(data->temp_hot_hyst);
574    results[2] = TEMP_LIMIT_FROM_REG(data->temp_os_max);
575    results[3] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst);
576    results[4] = TEMP_FROM_REG(data->temp);
577    *nrels_mag = 5;
578  } else if (operation == SENSORS_PROC_REAL_WRITE) {
579    if (*nrels_mag >= 1) {
580      data->temp_hot_max = TEMP_LIMIT_TO_REG(results[0]);
581      lm80_write_value(client,LM80_REG_TEMP_HOT_MAX,data->temp_hot_max);
582    }
583    if (*nrels_mag >= 2) {
584      data->temp_hot_hyst = TEMP_LIMIT_TO_REG(results[1]);
585      lm80_write_value(client,LM80_REG_TEMP_HOT_HYST,data->temp_hot_hyst);
586    }
587    if (*nrels_mag >= 3) {
588      data->temp_os_max = TEMP_LIMIT_TO_REG(results[2]);
589      lm80_write_value(client,LM80_REG_TEMP_OS_MAX,data->temp_os_max);
590    }
591    if (*nrels_mag >= 4) {
592      data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[3]);
593      lm80_write_value(client,LM80_REG_TEMP_OS_HYST,data->temp_os_hyst);
594    }
595  }
596}
597
598void lm80_alarms(struct i2c_client *client, int operation, int ctl_name,
599                 int *nrels_mag, long *results)
600{
601  struct lm80_data *data = client->data;
602  if (operation == SENSORS_PROC_REAL_INFO)
603    *nrels_mag = 0;
604  else if (operation == SENSORS_PROC_REAL_READ) {
605    lm80_update_client(client);
606    results[0] = ALARMS_FROM_REG(data->alarms);
607    *nrels_mag = 1;
608  }
609}
610
611void lm80_fan_div(struct i2c_client *client, int operation, int ctl_name,
612                  int *nrels_mag, long *results)
613{
614  struct lm80_data *data = client->data;
615  int old;
616
617  if (operation == SENSORS_PROC_REAL_INFO)
618    *nrels_mag = 0;
619  else if (operation == SENSORS_PROC_REAL_READ) {
620    lm80_update_client(client);
621    results[0] = DIV_FROM_REG(data->fan_div[0]);
622    results[1] = DIV_FROM_REG(data->fan_div[1]);
623    results[2] = 2;
624    *nrels_mag = 3;
625  } else if (operation == SENSORS_PROC_REAL_WRITE) {
626    old = lm80_read_value(client,LM80_REG_FANDIV);
627    if (*nrels_mag >= 2) {
628      data->fan_div[1] = DIV_TO_REG(results[1]);
629      old = (old & 0xcf) | (data->fan_div[1] << 4);
630    }
631    if (*nrels_mag >= 1) {
632      data->fan_div[0] = DIV_TO_REG(results[0]);
633      old = (old & 0xf3) | (data->fan_div[0] << 2);
634      lm80_write_value(client,LM80_REG_FANDIV,old);
635    }
636  }
637}
638
639int lm80_init(void)
640{
641  int res;
642
643  printk("lm80.o version %s (%s)\n",LM_VERSION,LM_DATE);
644  lm80_initialized = 0;
645
646  if ((res =i2c_add_driver(&lm80_driver))) {
647    printk("lm80.o: Driver registration failed, module not inserted.\n");
648    lm80_cleanup();
649    return res;
650  }
651  lm80_initialized ++;
652  return 0;
653}
654
655int lm80_cleanup(void)
656{
657  int res;
658
659  if (lm80_initialized >= 1) {
660    if ((res = i2c_del_driver(&lm80_driver))) {
661      printk("lm80.o: Driver deregistration failed, module not removed.\n");
662      return res;
663    }
664    lm80_initialized --;
665  }
666  return 0;
667}
668
669
670#ifdef MODULE
671
672MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
673MODULE_DESCRIPTION("LM80 driver");
674
675int init_module(void)
676{
677  return lm80_init();
678}
679
680int cleanup_module(void)
681{
682  return lm80_cleanup();
683}
684
685#endif /* MODULE */
686
Note: See TracBrowser for help on using the browser.