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

Revision 499, 28.1 KB (checked in by kmalkki, 14 years ago)

(Kyösti)

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