root/lm-sensors/trunk/kernel/chips/lm80.c @ 691

Revision 691, 23.7 KB (checked in by frodo, 14 years ago)

Fixed a temperature bug in the LM80 driver

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