root/lm-sensors/trunk/src/w83781d.c @ 87

Revision 87, 37.3 KB (checked in by phil, 14 years ago)

(Phil) Added access to 'beep' buzzer control registers via 'beep' file.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1
2/*
3    w83781d.c - A Linux module for reading sensor data.
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 W83781D constants specified below */
38
39/* Length of ISA address segment */
40#define W83781D_EXTENT 8
41
42/* Where are the ISA address/data registers relative to the base address */
43#define W83781D_ADDR_REG_OFFSET 5
44#define W83781D_DATA_REG_OFFSET 6
45
46/* The W83781D registers */
47#define W83781D_REG_IN_MAX(nr) (0x2b + (nr) * 2)
48#define W83781D_REG_IN_MIN(nr) (0x2c + (nr) * 2)
49#define W83781D_REG_IN(nr) (0x20 + (nr))
50
51#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
52#define W83781D_REG_FAN(nr) (0x27 + (nr))
53
54#define W83781D_REG_TEMP23 0x50
55#define W83781D_REG_TEMP_HYST23 0x53
56#define W83781D_REG_TEMP_CONFIG23 0x52
57#define W83781D_REG_TEMP_OVER23 0x55
58#define W83781D_REG_TEMP 0x27
59#define W83781D_REG_TEMP_OVER 0x39
60#define W83781D_REG_TEMP_HYST 0x3A
61#define W83781D_REG_TEMP_CONFIG 0x52
62#define W83781D_REG_TEMP_SEL 0x4E
63
64#define W83781D_REG_CONFIG 0x40
65#define W83781D_REG_ALARM1 0x41
66#define W83781D_REG_ALARM2 0x42
67
68#define W83781D_REG_BEEP_CONFIG 0x4D
69#define W83781D_REG_BEEP_INTS1 0x56
70#define W83781D_REG_BEEP_INTS2 0x57
71
72#define W83781D_REG_VID_FANDIV 0x47
73
74#define W83781D_REG_CHIPID 0x58
75#define W83781D_REG_CHIPMAN 0x4F
76
77
78/* Conversions. Rounding is only done on the TO_REG variants. */
79static int w83781d_in_conv[7] = {10000, 10000, 10000, 16892, 38000, 
80                              -34768, -15050 };
81#define IN_TO_REG(val,nr) (((((val) * 100000 / w83781d_in_conv[nr]) + 8) / 16) \
82                           & 0xff)
83#define IN_FROM_REG(val,nr) (((val) *  16 * w83781d_in_conv[nr]) / 100000)
84
85#define FAN_TO_REG(val) ((val)==0?255:((1350000+(val))/((val)*2)) & 0xff)
86#define FAN_FROM_REG(val) ((val)==0?-1:(val)==255?0:1350000/((val)*2))
87
88#define TEMP_TO_REG(val) (((val)<0?(((val)-5)/10)&0xff:((val)+5)/10) & 0xff)
89#define TEMP_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10)
90
91#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\
92                           (val)>=0x06?0:205-(val)*5)
93#define ALARMS_FROM_REG(val) (val)
94
95#define DIV_FROM_REG(val) (1 << (val))
96#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
97
98/* Initial limits */
99#define W83781D_INIT_IN_0 (vid==350?280:vid)
100#define W83781D_INIT_IN_1 (vid==350?280:vid)
101#define W83781D_INIT_IN_2 330
102#define W83781D_INIT_IN_3 500
103#define W83781D_INIT_IN_4 1200
104#define W83781D_INIT_IN_5 -1200
105#define W83781D_INIT_IN_6 -500
106
107#define W83781D_INIT_IN_PERCENTAGE 10
108
109#define W83781D_INIT_IN_MIN_0 \
110        (W83781D_INIT_IN_0 - W83781D_INIT_IN_0 * W83781D_INIT_IN_PERCENTAGE / 100)
111#define W83781D_INIT_IN_MAX_0 \
112        (W83781D_INIT_IN_0 + W83781D_INIT_IN_0 * W83781D_INIT_IN_PERCENTAGE / 100)
113#define W83781D_INIT_IN_MIN_1 \
114        (W83781D_INIT_IN_1 - W83781D_INIT_IN_1 * W83781D_INIT_IN_PERCENTAGE / 100)
115#define W83781D_INIT_IN_MAX_1 \
116        (W83781D_INIT_IN_1 + W83781D_INIT_IN_1 * W83781D_INIT_IN_PERCENTAGE / 100)
117#define W83781D_INIT_IN_MIN_2 \
118        (W83781D_INIT_IN_2 - W83781D_INIT_IN_2 * W83781D_INIT_IN_PERCENTAGE / 100)
119#define W83781D_INIT_IN_MAX_2 \
120        (W83781D_INIT_IN_2 + W83781D_INIT_IN_2 * W83781D_INIT_IN_PERCENTAGE / 100)
121#define W83781D_INIT_IN_MIN_3 \
122        (W83781D_INIT_IN_3 - W83781D_INIT_IN_3 * W83781D_INIT_IN_PERCENTAGE / 100)
123#define W83781D_INIT_IN_MAX_3 \
124        (W83781D_INIT_IN_3 + W83781D_INIT_IN_3 * W83781D_INIT_IN_PERCENTAGE / 100)
125#define W83781D_INIT_IN_MIN_4 \
126        (W83781D_INIT_IN_4 - W83781D_INIT_IN_4 * W83781D_INIT_IN_PERCENTAGE / 100)
127#define W83781D_INIT_IN_MAX_4 \
128        (W83781D_INIT_IN_4 + W83781D_INIT_IN_4 * W83781D_INIT_IN_PERCENTAGE / 100)
129#define W83781D_INIT_IN_MIN_5 \
130        (W83781D_INIT_IN_5 - W83781D_INIT_IN_5 * W83781D_INIT_IN_PERCENTAGE / 100)
131#define W83781D_INIT_IN_MAX_5 \
132        (W83781D_INIT_IN_5 + W83781D_INIT_IN_5 * W83781D_INIT_IN_PERCENTAGE / 100)
133#define W83781D_INIT_IN_MIN_6 \
134        (W83781D_INIT_IN_6 - W83781D_INIT_IN_6 * W83781D_INIT_IN_PERCENTAGE / 100)
135#define W83781D_INIT_IN_MAX_6 \
136        (W83781D_INIT_IN_6 + W83781D_INIT_IN_6 * W83781D_INIT_IN_PERCENTAGE / 100)
137
138#define W83781D_INIT_FAN_MIN_1 3000
139#define W83781D_INIT_FAN_MIN_2 3000
140#define W83781D_INIT_FAN_MIN_3 3000
141
142#define W83781D_INIT_TEMP_OVER 600
143#define W83781D_INIT_TEMP_HYST 500
144
145#ifdef MODULE
146extern int init_module(void);
147extern int cleanup_module(void);
148#endif /* MODULE */
149
150/* There are some complications in a module like this. First off, W83781D chips
151   may be both present on the SMBus and the ISA bus, and we have to handle
152   those cases separately at some places. Second, there might be several
153   W83781D chips available (well, actually, that is probably never done; but
154   it is a clean illustration of how to handle a case like that). Finally,
155   a specific chip may be attached to *both* ISA and SMBus, and we would
156   not like to detect it double. Fortunately, in the case of the W83781D at
157   least, a register tells us what SMBus address we are on, so that helps
158   a bit - except if there could be more than one SMBus. Groan. No solution
159   for this yet. */
160
161/* This module may seem overly long and complicated. In fact, it is not so
162   bad. Quite a lot of bookkeeping is done. A real driver can often cut
163   some corners. */
164
165/* For each registered W83781D, we need to keep some data in memory. That
166   data is pointed to by w83781d_list[NR]->data. The structure itself is
167   dynamically allocated, at the same time when a new w83781d client is
168   allocated. */
169struct w83781d_data {
170         struct semaphore lock;
171         int sysctl_id;
172
173         struct semaphore update_lock;
174         char valid;                 /* !=0 if following fields are valid */
175         unsigned long last_updated; /* In jiffies */
176
177         u8 in[7];                   /* Register value */
178         u8 in_max[7];               /* Register value */
179         u8 in_min[7];               /* Register value */
180         u8 fan[3];                  /* Register value */
181         u8 fan_min[3];              /* Register value */
182         u8 temp[3];                    /* Register value */
183         u8 temp_over[3];               /* Register value */
184         u8 temp_hyst[3];               /* Register value */
185         u8 fan_div[2];              /* Register encoding, shifted right */
186         u8 vid;                     /* Register encoding, combined */
187         u16 alarms;                 /* Register encoding, combined */
188         u8 beep[3];                    /* Register value of config and interrupt masks */
189};
190
191
192static int w83781d_init(void);
193static int w83781d_cleanup(void);
194
195static int w83781d_attach_adapter(struct i2c_adapter *adapter);
196static int w83781d_detect_isa(struct isa_adapter *adapter);
197static int w83781d_detect_smbus(struct i2c_adapter *adapter);
198static int w83781d_detach_client(struct i2c_client *client);
199static int w83781d_detach_isa(struct isa_client *client);
200static int w83781d_detach_smbus(struct i2c_client *client);
201static int w83781d_new_client(struct i2c_adapter *adapter,
202                           struct i2c_client *new_client);
203static void w83781d_remove_client(struct i2c_client *client);
204static int w83781d_command(struct i2c_client *client, unsigned int cmd, 
205                        void *arg);
206static void w83781d_inc_use (struct i2c_client *client);
207static void w83781d_dec_use (struct i2c_client *client);
208
209static int w83781d_read_value(struct i2c_client *client, u8 register);
210static int w83781d_write_value(struct i2c_client *client, u8 register, u8 value);
211static void w83781d_update_client(struct i2c_client *client);
212static void w83781d_init_client(struct i2c_client *client);
213
214
215static void w83781d_in(struct i2c_client *client, int operation, int ctl_name,
216                    int *nrels_mag, long *results);
217static void w83781d_fan(struct i2c_client *client, int operation, int ctl_name,
218                     int *nrels_mag, long *results);
219static void w83781d_temp(struct i2c_client *client, int operation, int ctl_name,
220                      int *nrels_mag, long *results,int tempnum);
221static void w83781d_temp1(struct i2c_client *client, int operation, int ctl_name,
222                      int *nrels_mag, long *results);
223static void w83781d_temp2(struct i2c_client *client, int operation, int ctl_name,
224                      int *nrels_mag, long *results);
225static void w83781d_temp3(struct i2c_client *client, int operation, int ctl_name,
226                      int *nrels_mag, long *results);
227static void w83781d_vid(struct i2c_client *client, int operation, int ctl_name,
228                     int *nrels_mag, long *results);
229static void w83781d_alarms(struct i2c_client *client, int operation, int ctl_name,
230                        int *nrels_mag, long *results);
231static void w83781d_beep(struct i2c_client *client, int operation, int ctl_name,
232                      int *nrels_mag, long *results);
233static void w83781d_fan_div(struct i2c_client *client, int operation, int ctl_name,
234                         int *nrels_mag, long *results);
235
236/* I choose here for semi-static W83781D allocation. Complete dynamic
237   allocation could also be used; the code needed for this would probably
238   take more memory than the datastructure takes now. */
239#define MAX_W83781D_NR 4
240static struct i2c_client *w83781d_list[MAX_W83781D_NR];
241
242/* The driver. I choose to use type i2c_driver, as at is identical to both
243   smbus_driver and isa_driver, and clients could be of either kind */
244static struct i2c_driver w83781d_driver = {
245  /* name */            "W83781D sensor driver",
246  /* id */              I2C_DRIVERID_W83781D,
247  /* flags */           DF_NOTIFY,
248  /* attach_adapter */  &w83781d_attach_adapter,
249  /* detach_client */   &w83781d_detach_client,
250  /* command */         &w83781d_command,
251  /* inc_use */         &w83781d_inc_use,
252  /* dec_use */         &w83781d_dec_use
253};
254
255/* Used by w83781d_init/cleanup */
256static int w83781d_initialized = 0;
257
258/* The /proc/sys entries */
259/* These files are created for each detected W83781D. This is just a template;
260   though at first sight, you might think we could use a statically
261   allocated list, we need some way to get back to the parent - which
262   is done through one of the 'extra' fields which are initialized
263   when a new copy is allocated. */
264static ctl_table w83781d_dir_table_template[] = {
265  { W83781D_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &sensors_proc_real,
266    &sensors_sysctl_real, NULL, &w83781d_in },
267  { W83781D_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &sensors_proc_real,
268    &sensors_sysctl_real, NULL, &w83781d_in },
269  { W83781D_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &sensors_proc_real,
270    &sensors_sysctl_real, NULL, &w83781d_in },
271  { W83781D_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &sensors_proc_real,
272    &sensors_sysctl_real, NULL, &w83781d_in },
273  { W83781D_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &sensors_proc_real,
274    &sensors_sysctl_real, NULL, &w83781d_in },
275  { W83781D_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &sensors_proc_real,
276    &sensors_sysctl_real, NULL, &w83781d_in },
277  { W83781D_SYSCTL_IN6, "in6", NULL, 0, 0644, NULL, &sensors_proc_real,
278    &sensors_sysctl_real, NULL, &w83781d_in },
279  { W83781D_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real,
280    &sensors_sysctl_real, NULL, &w83781d_fan },
281  { W83781D_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real,
282    &sensors_sysctl_real, NULL, &w83781d_fan },
283  { W83781D_SYSCTL_FAN3, "fan3", NULL, 0, 0644, NULL, &sensors_proc_real,
284    &sensors_sysctl_real, NULL, &w83781d_fan },
285  { W83781D_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real,
286    &sensors_sysctl_real, NULL, &w83781d_temp1 },
287  { W83781D_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &sensors_proc_real,
288    &sensors_sysctl_real, NULL, &w83781d_temp2 },
289  { W83781D_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, &sensors_proc_real,
290    &sensors_sysctl_real, NULL, &w83781d_temp3 },
291  { W83781D_SYSCTL_VID, "vid", NULL, 0, 0644, NULL, &sensors_proc_real,
292    &sensors_sysctl_real, NULL, &w83781d_vid },
293  { W83781D_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real,
294    &sensors_sysctl_real, NULL, &w83781d_fan_div },
295  { W83781D_SYSCTL_ALARMS, "alarms", NULL, 0, 0644, NULL, &sensors_proc_real,
296    &sensors_sysctl_real, NULL, &w83781d_alarms },
297  { W83781D_SYSCTL_BEEP, "beep", NULL, 0, 0644, NULL, &sensors_proc_real,
298    &sensors_sysctl_real, NULL, &w83781d_beep },
299  { 0 }
300};
301
302
303/* This function is called when:
304     * w83781d_driver is inserted (when this module is loaded), for each
305       available adapter
306     * when a new adapter is inserted (and w83781d_driver is still present) */
307int w83781d_attach_adapter(struct i2c_adapter *adapter)
308{
309  if (i2c_is_isa_adapter(adapter))
310    return w83781d_detect_isa((struct isa_adapter *) adapter);
311  else
312    return w83781d_detect_smbus(adapter);
313}
314
315/* This function is called whenever a client should be removed:
316    * w83781d_driver is removed (when this module is unloaded)
317    * when an adapter is removed which has a w83781d client (and w83781d_driver
318      is still present). */
319int w83781d_detach_client(struct i2c_client *client)
320{
321  if (i2c_is_isa_client(client))
322    return w83781d_detach_isa((struct isa_client *) client);
323  else
324    return w83781d_detach_smbus(client);
325}
326
327/* Detect whether there is a W83781D on the ISA bus, register and initialize
328   it. */
329int w83781d_detect_isa(struct isa_adapter *adapter)
330{
331  int address,err;
332  struct isa_client *new_client;
333  const char *type_name;
334  const char *client_name;
335
336  /* OK, this is no detection. I know. It will do for now, though.  */
337
338  err = 0;
339  for (address = 0x290; (! err) && (address <= 0x290); address += 0x08) {
340    if (check_region(address, W83781D_EXTENT))
341      continue;
342
343    /* Awful, but true: unused port addresses should return 0xff */
344    if ((inb_p(address + 1) != 0xff) || (inb_p(address + 2) != 0xff) ||
345       (inb_p(address + 3) != 0xff) || (inb_p(address + 7) != 0xff))
346      continue;
347   
348    if (inb_p(address + W83781D_ADDR_REG_OFFSET) == 0xff) {
349      outb_p(0x00,address + W83781D_ADDR_REG_OFFSET);
350      if (inb_p(address + W83781D_ADDR_REG_OFFSET) == 0xff)
351        continue;
352    }
353   
354    /* Real detection code goes here */
355
356    outb_p(W83781D_REG_CHIPID,address + W83781D_ADDR_REG_OFFSET);
357    err = inb_p(address + W83781D_DATA_REG_OFFSET) & 0xfe;
358
359    if (err != 0x20) {
360      printk("w83781d.o: Winbond W83781D detected (ISA addr=0x%X)\n",address);
361      type_name = "w83781d";
362      client_name = "Winbond W83781D chip";
363    } else {
364 #ifdef DEBUG
365     printk("83781d.o: Winbond W83781D not detected (ISA)\n");
366 #endif
367     continue;
368    }
369
370    request_region(address, W83781D_EXTENT, type_name);
371
372    /* Allocate space for a new client structure */
373    if (! (new_client = kmalloc(sizeof(struct isa_client) + 
374                                sizeof(struct w83781d_data),
375                               GFP_KERNEL)))
376    {
377      err=-ENOMEM;
378      goto ERROR1;
379    } 
380
381    /* Fill the new client structure with data */
382    new_client->data = (struct w83781d_data *) (new_client + 1);
383    new_client->addr = 0;
384    strcpy(new_client->name,client_name);
385    new_client->isa_addr = address;
386    if ((err = w83781d_new_client((struct i2c_adapter *) adapter,
387                               (struct i2c_client *) new_client)))
388      goto ERROR2;
389
390    /* Tell i2c-core a new client has arrived */
391    if ((err = isa_attach_client(new_client)))
392      goto ERROR3;
393   
394    /* Register a new directory entry with module sensors */
395    if ((err = sensors_register_entry((struct i2c_client *) new_client,
396                                      type_name,
397                                      w83781d_dir_table_template)) < 0)
398      goto ERROR4;
399    ((struct w83781d_data *) (new_client->data)) -> sysctl_id = err;
400    err = 0;
401
402    /* Initialize the W83781D chip */
403    w83781d_init_client((struct i2c_client *) new_client);
404    continue;
405
406/* OK, this is not exactly good programming practice, usually. But it is
407   very code-efficient in this case. */
408
409ERROR4:
410    isa_detach_client(new_client);
411ERROR3:
412    w83781d_remove_client((struct i2c_client *) new_client);
413ERROR2:
414    kfree(new_client);
415ERROR1:
416    release_region(address, W83781D_EXTENT);
417  }
418  return err;
419
420}
421
422/* Deregister and remove a W83781D client */
423int w83781d_detach_isa(struct isa_client *client)
424{
425  int err,i;
426  for (i = 0; i < MAX_W83781D_NR; i++)
427    if ((client == (struct isa_client *) (w83781d_list[i])))
428      break;
429  if (i == MAX_W83781D_NR) {
430    printk("w83781d.o: Client to detach not found.\n");
431    return -ENOENT;
432  }
433
434  sensors_deregister_entry(((struct w83781d_data *)(client->data))->sysctl_id);
435
436  if ((err = isa_detach_client(client))) {
437    printk("w83781d.o: Client deregistration failed, client not detached.\n");
438    return err;
439  }
440  w83781d_remove_client((struct i2c_client *) client);
441  release_region(client->isa_addr,W83781D_EXTENT);
442  kfree(client);
443  return 0;
444}
445
446int w83781d_detect_smbus(struct i2c_adapter *adapter)
447{
448  int address,err;
449  struct i2c_client *new_client;
450  const char *type_name,*client_name;
451
452  /* OK, this is no detection. I know. It will do for now, though.  */
453  err = 0;
454  for (address = 0x20; (! err) && (address <= 0x2f); address ++) {
455
456    /* Later on, we will keep a list of registered addresses for each
457       adapter, and check whether they are used here */
458
459    if (smbus_read_byte_data(adapter,address,W83781D_REG_CONFIG) < 0) 
460      continue;
461
462    err = smbus_read_byte_data(adapter,address,W83781D_REG_CHIPID);
463   
464    if (err == 0x20) {
465      printk("w83781d.o: Winbond W83781D detected (SMBus addr 0x%X)\n",address);
466      type_name = "w83781d";
467      client_name = "Winbond W83781D chip";
468    } else {
469 #ifdef DEBUG
470     printk("83781d.o: Winbond W83781D not detected (SMBus/I2C)\n");
471 #endif
472     continue;
473    }
474
475    /* Allocate space for a new client structure. To counter memory
476       ragmentation somewhat, we only do one kmalloc. */
477    if (! (new_client = kmalloc(sizeof(struct i2c_client) + 
478                                sizeof(struct w83781d_data),
479                               GFP_KERNEL))) {
480      err = -ENOMEM;
481      continue;
482    }
483
484    /* Fill the new client structure with data */
485    new_client->data = (struct w83781d_data *) (new_client + 1);
486    new_client->addr = address;
487    strcpy(new_client->name,client_name);
488    if ((err = w83781d_new_client(adapter,new_client)))
489      goto ERROR2;
490
491    /* Tell i2c-core a new client has arrived */
492    if ((err = i2c_attach_client(new_client))) 
493      goto ERROR3;
494
495    /* Register a new directory entry with module sensors */
496    if ((err = sensors_register_entry(new_client,type_name,
497                                      w83781d_dir_table_template)) < 0)
498      goto ERROR4;
499    ((struct w83781d_data *) (new_client->data))->sysctl_id = err;
500    err = 0;
501
502    /* Initialize the W83781D chip */
503    w83781d_init_client(new_client);
504    continue;
505
506/* OK, this is not exactly good programming practice, usually. But it is
507   very code-efficient in this case. */
508ERROR4:
509    i2c_detach_client(new_client);
510ERROR3:
511    w83781d_remove_client((struct i2c_client *) new_client);
512ERROR2:
513    kfree(new_client);
514  }
515  return err;
516}
517
518int w83781d_detach_smbus(struct i2c_client *client)
519{
520  int err,i;
521  for (i = 0; i < MAX_W83781D_NR; i++)
522    if (client == w83781d_list[i])
523      break;
524  if ((i == MAX_W83781D_NR)) {
525    printk("w83781d.o: Client to detach not found.\n");
526    return -ENOENT;
527  }
528
529  sensors_deregister_entry(((struct w83781d_data *)(client->data))->sysctl_id);
530
531  if ((err = i2c_detach_client(client))) {
532    printk("w83781d.o: Client deregistration failed, client not detached.\n");
533    return err;
534  }
535  w83781d_remove_client(client);
536  kfree(client);
537  return 0;
538}
539
540
541/* Find a free slot, and initialize most of the fields */
542int w83781d_new_client(struct i2c_adapter *adapter,
543                    struct i2c_client *new_client)
544{
545  int i;
546  struct w83781d_data *data;
547
548  /* First, seek out an empty slot */
549  for(i = 0; i < MAX_W83781D_NR; i++)
550    if (! w83781d_list[i])
551      break;
552  if (i == MAX_W83781D_NR) {
553    printk("w83781d.o: No empty slots left, recompile and heighten "
554           "MAX_W83781D_NR!\n");
555    return -ENOMEM;
556  }
557 
558  w83781d_list[i] = new_client;
559  new_client->id = i;
560  new_client->adapter = adapter;
561  new_client->driver = &w83781d_driver;
562  data = new_client->data;
563  data->valid = 0;
564  data->lock = MUTEX;
565  data->update_lock = MUTEX;
566  return 0;
567}
568
569/* Inverse of w83781d_new_client */
570void w83781d_remove_client(struct i2c_client *client)
571{
572  int i;
573  for (i = 0; i < MAX_W83781D_NR; i++)
574    if (client == w83781d_list[i]) 
575      w83781d_list[i] = NULL;
576}
577
578/* No commands defined yet */
579int w83781d_command(struct i2c_client *client, unsigned int cmd, void *arg)
580{
581  return 0;
582}
583
584/* Nothing here yet */
585void w83781d_inc_use (struct i2c_client *client)
586{
587#ifdef MODULE
588  MOD_INC_USE_COUNT;
589#endif
590}
591
592/* Nothing here yet */
593void w83781d_dec_use (struct i2c_client *client)
594{
595#ifdef MODULE
596  MOD_DEC_USE_COUNT;
597#endif
598}
599 
600
601/* The SMBus locks itself, but ISA access must be locked explicitely!
602   We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
603   would slow down the W83781D access and should not be necessary.
604   There are some ugly typecasts here, but the good new is - they should
605   nowhere else be necessary! */
606int w83781d_read_value(struct i2c_client *client, u8 reg)
607{
608  int res;
609  if (i2c_is_isa_client(client)) {
610    down((struct semaphore *) (client->data));
611    outb_p(reg,(((struct isa_client *) client)->isa_addr) + 
612               W83781D_ADDR_REG_OFFSET);
613    res = inb_p((((struct isa_client *) client)->isa_addr) + 
614                W83781D_DATA_REG_OFFSET);
615    up((struct semaphore *) (client->data));
616    return res;
617  } else
618    return smbus_read_byte_data(client->adapter,client->addr, reg);
619}
620
621/* The SMBus locks itself, but ISA access muse be locked explicitely!
622   We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
623   would slow down the W83781D access and should not be necessary.
624   There are some ugly typecasts here, but the good new is - they should
625   nowhere else be necessary! */
626int w83781d_write_value(struct i2c_client *client, u8 reg, u8 value)
627{
628  if (i2c_is_isa_client(client)) {
629    down((struct semaphore *) (client->data));
630    outb_p(reg,((struct isa_client *) client)->isa_addr + W83781D_ADDR_REG_OFFSET);
631    outb_p(value,((struct isa_client *) client)->isa_addr + W83781D_DATA_REG_OFFSET);
632    up((struct semaphore *) (client->data));
633    return 0;
634  } else
635    return smbus_write_byte_data(client->adapter, client->addr, reg,value);
636}
637
638/* Called when we have found a new W83781D. It should set limits, etc. */
639void w83781d_init_client(struct i2c_client *client)
640{
641  int vid;
642
643  /* Reset all except Watchdog values and last conversion values
644     This sets fan-divs to 2, among others */
645  w83781d_write_value(client,W83781D_REG_CONFIG,0x80);
646
647  vid = w83781d_read_value(client,W83781D_REG_VID_FANDIV) & 0x0f;
648  vid |= (w83781d_read_value(client,W83781D_REG_CHIPID) & 0x01) >> 4;
649  vid = VID_FROM_REG(vid);
650
651  w83781d_write_value(client,W83781D_REG_IN_MIN(0),IN_TO_REG(W83781D_INIT_IN_MIN_0,0));
652  w83781d_write_value(client,W83781D_REG_IN_MAX(0),IN_TO_REG(W83781D_INIT_IN_MAX_0,0));
653  w83781d_write_value(client,W83781D_REG_IN_MIN(1),IN_TO_REG(W83781D_INIT_IN_MIN_1,1));
654  w83781d_write_value(client,W83781D_REG_IN_MAX(1),IN_TO_REG(W83781D_INIT_IN_MAX_1,1));
655  w83781d_write_value(client,W83781D_REG_IN_MIN(2),IN_TO_REG(W83781D_INIT_IN_MIN_2,2));
656  w83781d_write_value(client,W83781D_REG_IN_MAX(2),IN_TO_REG(W83781D_INIT_IN_MAX_2,2));
657  w83781d_write_value(client,W83781D_REG_IN_MIN(3),IN_TO_REG(W83781D_INIT_IN_MIN_3,3));
658  w83781d_write_value(client,W83781D_REG_IN_MAX(3),IN_TO_REG(W83781D_INIT_IN_MAX_3,3));
659  w83781d_write_value(client,W83781D_REG_IN_MIN(4),IN_TO_REG(W83781D_INIT_IN_MIN_4,4));
660  w83781d_write_value(client,W83781D_REG_IN_MAX(4),IN_TO_REG(W83781D_INIT_IN_MAX_4,4));
661  w83781d_write_value(client,W83781D_REG_IN_MIN(5),IN_TO_REG(W83781D_INIT_IN_MIN_5,5));
662  w83781d_write_value(client,W83781D_REG_IN_MAX(5),IN_TO_REG(W83781D_INIT_IN_MAX_5,5));
663  w83781d_write_value(client,W83781D_REG_IN_MIN(6),IN_TO_REG(W83781D_INIT_IN_MIN_6,6));
664  w83781d_write_value(client,W83781D_REG_IN_MAX(6),IN_TO_REG(W83781D_INIT_IN_MAX_6,6));
665  w83781d_write_value(client,W83781D_REG_FAN_MIN(1),FAN_TO_REG(W83781D_INIT_FAN_MIN_1));
666  w83781d_write_value(client,W83781D_REG_FAN_MIN(2),FAN_TO_REG(W83781D_INIT_FAN_MIN_2));
667  w83781d_write_value(client,W83781D_REG_FAN_MIN(3),FAN_TO_REG(W83781D_INIT_FAN_MIN_3));
668  /* Init Temp Sensor1 */
669  w83781d_write_value(client,W83781D_REG_TEMP_SEL,0x00);/* Switch Banks! */
670  w83781d_write_value(client,W83781D_REG_TEMP_OVER,TEMP_TO_REG(W83781D_INIT_TEMP_OVER));
671  w83781d_write_value(client,W83781D_REG_TEMP_HYST,TEMP_TO_REG(W83781D_INIT_TEMP_HYST));
672  w83781d_write_value(client,W83781D_REG_TEMP_CONFIG,0x00);
673  /* Init Temp Sensor2 */
674  w83781d_write_value(client,W83781D_REG_TEMP_SEL,0x01);/* Switch Banks! */
675  w83781d_write_value(client,W83781D_REG_TEMP_OVER23,TEMP_TO_REG(W83781D_INIT_TEMP_OVER));
676  w83781d_write_value(client,W83781D_REG_TEMP_OVER23 + 1,0);
677  w83781d_write_value(client,W83781D_REG_TEMP_HYST23,TEMP_TO_REG(W83781D_INIT_TEMP_HYST));
678  w83781d_write_value(client,W83781D_REG_TEMP_HYST23 + 1,0);
679  w83781d_write_value(client,W83781D_REG_TEMP_CONFIG23,0x00);
680  /* Init Temp Sensor3 */
681  w83781d_write_value(client,W83781D_REG_TEMP_SEL,0x02);/* Switch Banks! */
682  w83781d_write_value(client,W83781D_REG_TEMP_OVER23,TEMP_TO_REG(W83781D_INIT_TEMP_OVER));
683  w83781d_write_value(client,W83781D_REG_TEMP_OVER23 + 1,0);
684  w83781d_write_value(client,W83781D_REG_TEMP_HYST23,TEMP_TO_REG(W83781D_INIT_TEMP_HYST));
685  w83781d_write_value(client,W83781D_REG_TEMP_HYST23 + 1,0);
686  w83781d_write_value(client,W83781D_REG_TEMP_CONFIG23,0x00);
687  w83781d_write_value(client,W83781D_REG_TEMP_SEL,0x00);/* Switch Banks! */
688
689  /* Start monitoring */
690  w83781d_write_value(client,W83781D_REG_CONFIG,
691                   (w83781d_read_value(client,W83781D_REG_CONFIG) & 0xf7) | 0x01);
692 
693}
694
695void w83781d_update_client(struct i2c_client *client)
696{
697  struct w83781d_data *data = client->data;
698  int i;
699
700  down(&data->update_lock);
701
702  if ((jiffies - data->last_updated > HZ+HZ/2 ) ||
703      (jiffies < data->last_updated) || ! data->valid) {
704
705#ifdef DEBUG
706    printk("Starting w83781d update\n");
707#endif
708    for (i = 0; i <= 6; i++) {
709      data->in[i]     = w83781d_read_value(client,W83781D_REG_IN(i));
710      data->in_min[i] = w83781d_read_value(client,W83781D_REG_IN_MIN(i));
711      data->in_max[i] = w83781d_read_value(client,W83781D_REG_IN_MAX(i));
712    }
713    for (i = 1; i <= 3; i++) {
714      data->fan[i-1] = w83781d_read_value(client,W83781D_REG_FAN(i));
715      data->fan_min[i-1] = w83781d_read_value(client,W83781D_REG_FAN_MIN(i));
716    }
717    data->temp[0] = w83781d_read_value(client,W83781D_REG_TEMP);
718    data->temp_over[0] = w83781d_read_value(client,W83781D_REG_TEMP_OVER);
719    data->temp_hyst[0] = w83781d_read_value(client,W83781D_REG_TEMP_HYST);
720    w83781d_write_value(client,W83781D_REG_TEMP_SEL,1);/* Switch Banks!! */
721    data->temp[1] = w83781d_read_value(client,W83781D_REG_TEMP23);
722    data->temp_over[1] = w83781d_read_value(client,W83781D_REG_TEMP_OVER23);
723    data->temp_hyst[1] = w83781d_read_value(client,W83781D_REG_TEMP_HYST23);
724    w83781d_write_value(client,W83781D_REG_TEMP_SEL,2);/* Switch Banks!! */
725    data->temp[2] = w83781d_read_value(client,W83781D_REG_TEMP23);
726    data->temp_over[2] = w83781d_read_value(client,W83781D_REG_TEMP_OVER23);
727    data->temp_hyst[2] = w83781d_read_value(client,W83781D_REG_TEMP_HYST23);
728    w83781d_write_value(client,W83781D_REG_TEMP_SEL,0);/* Switch Banks!! */
729    i = w83781d_read_value(client,W83781D_REG_VID_FANDIV);
730    data->vid = i & 0x0f;
731    data->vid |= (w83781d_read_value(client,W83781D_REG_CHIPID) & 0x01) >> 4;
732    data->fan_div[0] = (i >> 4) & 0x03;
733    data->fan_div[1] = i >> 6;
734    data->alarms = w83781d_read_value(client,W83781D_REG_ALARM1) +
735                   (w83781d_read_value(client,W83781D_REG_ALARM2) >> 8);
736    data->beep[0] = w83781d_read_value(client,W83781D_REG_BEEP_CONFIG);
737    data->beep[1] = w83781d_read_value(client,W83781D_REG_BEEP_INTS1);
738    data->beep[2] = w83781d_read_value(client,W83781D_REG_BEEP_INTS2);
739    data->last_updated = jiffies;
740    data->valid = 1;
741  }
742
743  up(&data->update_lock);
744}
745
746
747/* The next few functions are the call-back functions of the /proc/sys and
748   sysctl files. Which function is used is defined in the ctl_table in
749   the extra1 field.
750   Each function must return the magnitude (power of 10 to divide the date
751   with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must
752   put a maximum of *nrels elements in results reflecting the data of this
753   file, and set *nrels to the number it actually put in it, if operation==
754   SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from
755   results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE.
756   Note that on SENSORS_PROC_REAL_READ, I do not check whether results is
757   large enough (by checking the incoming value of *nrels). This is not very
758   good practice, but as long as you put less than about 5 values in results,
759   you can assume it is large enough. */
760void w83781d_in(struct i2c_client *client, int operation, int ctl_name, 
761             int *nrels_mag, long *results)
762{
763  struct w83781d_data *data = client->data;
764  int nr = ctl_name - W83781D_SYSCTL_IN0;
765
766  if (operation == SENSORS_PROC_REAL_INFO)
767    *nrels_mag = 2;
768  else if (operation == SENSORS_PROC_REAL_READ) {
769    w83781d_update_client(client);
770    results[0] = IN_FROM_REG(data->in_min[nr],nr);
771    results[1] = IN_FROM_REG(data->in_max[nr],nr);
772    results[2] = IN_FROM_REG(data->in[nr],nr);
773    *nrels_mag = 3;
774  } else if (operation == SENSORS_PROC_REAL_WRITE) {
775      if (*nrels_mag >= 1) {
776        data->in_min[nr] = IN_TO_REG(results[0],nr);
777        w83781d_write_value(client,W83781D_REG_IN_MIN(nr),data->in_min[nr]);
778      }
779      if (*nrels_mag >= 2) {
780        data->in_max[nr] = IN_TO_REG(results[1],nr);
781        w83781d_write_value(client,W83781D_REG_IN_MAX(nr),data->in_max[nr]);
782      }
783  }
784}
785
786void w83781d_fan(struct i2c_client *client, int operation, int ctl_name,
787              int *nrels_mag, long *results)
788{
789  struct w83781d_data *data = client->data;
790  int nr = ctl_name - W83781D_SYSCTL_FAN1 + 1;
791
792  if (operation == SENSORS_PROC_REAL_INFO)
793    *nrels_mag = 0;
794  else if (operation == SENSORS_PROC_REAL_READ) {
795    w83781d_update_client(client);
796    results[0] = FAN_FROM_REG(data->fan_min[nr-1]);
797    results[1] = FAN_FROM_REG(data->fan[nr-1]);
798    *nrels_mag = 2;
799  } else if (operation == SENSORS_PROC_REAL_WRITE) {
800    if (*nrels_mag >= 1) {
801      data->fan_min[nr-1] = FAN_TO_REG(results[0]);
802      w83781d_write_value(client,W83781D_REG_FAN_MIN(nr),data->fan_min[nr-1]);
803    }
804  }
805}
806
807
808void w83781d_temp(struct i2c_client *client, int operation, int ctl_name,
809               int *nrels_mag, long *results,int tempnum )
810{
811  struct w83781d_data *data = client->data;
812  if (operation == SENSORS_PROC_REAL_INFO)
813    *nrels_mag = 1;
814  else if (operation == SENSORS_PROC_REAL_READ) {
815    w83781d_update_client(client);
816    results[0] = TEMP_FROM_REG(data->temp_over[tempnum - 1]);
817    results[1] = TEMP_FROM_REG(data->temp_hyst[tempnum - 1]);
818    results[2] = TEMP_FROM_REG(data->temp[tempnum - 1]);
819    *nrels_mag = 3;
820  } else if (operation == SENSORS_PROC_REAL_WRITE) {
821    if (tempnum == 3) {
822     w83781d_write_value(client,W83781D_REG_TEMP_SEL,0x02);/* Switch Banks!! */
823     if (*nrels_mag >= 1) {
824       data->temp_over[2] = TEMP_TO_REG(results[0]);
825       w83781d_write_value(client,W83781D_REG_TEMP_OVER23,data->temp_over[2]);
826       w83781d_write_value(client,W83781D_REG_TEMP_OVER23 + 1,0);
827     }
828     if (*nrels_mag >= 2) {
829       data->temp_hyst[2] = TEMP_TO_REG(results[1]);
830       w83781d_write_value(client,W83781D_REG_TEMP_HYST23,data->temp_hyst[2]);
831       w83781d_write_value(client,W83781D_REG_TEMP_HYST23 + 1,0);
832     }
833     w83781d_write_value(client,W83781D_REG_TEMP_SEL,0x0);/* Switch Banks!! */
834    } else if (tempnum == 2) {
835     w83781d_write_value(client,W83781D_REG_TEMP_SEL,0x01);/* Switch Banks!! */
836     if (*nrels_mag >= 1) {
837       data->temp_over[1] = TEMP_TO_REG(results[0]);
838       w83781d_write_value(client,W83781D_REG_TEMP_OVER23,data->temp_over[1]);
839       w83781d_write_value(client,W83781D_REG_TEMP_OVER23 + 1,0);
840     }
841     if (*nrels_mag >= 2) {
842       data->temp_hyst[1] = TEMP_TO_REG(results[1]);
843       w83781d_write_value(client,W83781D_REG_TEMP_HYST23,data->temp_hyst[1]);
844       w83781d_write_value(client,W83781D_REG_TEMP_HYST23 + 1,0);
845     }
846     w83781d_write_value(client,W83781D_REG_TEMP_SEL,0x0);/* Switch Banks!! */
847    } else {
848     if (*nrels_mag >= 1) {
849       data->temp_over[0] = TEMP_TO_REG(results[0]);
850       w83781d_write_value(client,W83781D_REG_TEMP_OVER,data->temp_over[0]);
851     }
852     if (*nrels_mag >= 2) {
853       data->temp_hyst[0] = TEMP_TO_REG(results[1]);
854       w83781d_write_value(client,W83781D_REG_TEMP_HYST,data->temp_hyst[0]);
855     }
856    }
857  }
858}
859
860
861void w83781d_temp1(struct i2c_client *client, int operation, int ctl_name,
862               int *nrels_mag, long *results) {
863
864  w83781d_temp(client,operation,ctl_name,nrels_mag,results,1);
865}
866
867
868void w83781d_temp2(struct i2c_client *client, int operation, int ctl_name,
869               int *nrels_mag, long *results) {
870               
871  w83781d_temp(client,operation,ctl_name,nrels_mag,results,2);
872}
873
874
875void w83781d_temp3(struct i2c_client *client, int operation, int ctl_name,
876               int *nrels_mag, long *results) {
877               
878  w83781d_temp(client,operation,ctl_name,nrels_mag,results,3);
879}
880
881
882void w83781d_vid(struct i2c_client *client, int operation, int ctl_name,
883              int *nrels_mag, long *results)
884{
885  struct w83781d_data *data = client->data;
886  if (operation == SENSORS_PROC_REAL_INFO)
887    *nrels_mag = 2;
888  else if (operation == SENSORS_PROC_REAL_READ) {
889    w83781d_update_client(client);
890    results[0] = VID_FROM_REG(data->vid);
891    *nrels_mag = 1;
892  }
893}
894
895void w83781d_alarms(struct i2c_client *client, int operation, int ctl_name,
896                 int *nrels_mag, long *results)
897{
898  struct w83781d_data *data = client->data;
899  if (operation == SENSORS_PROC_REAL_INFO)
900    *nrels_mag = 0;
901  else if (operation == SENSORS_PROC_REAL_READ) {
902    w83781d_update_client(client);
903    results[0] = ALARMS_FROM_REG(data->alarms);
904    *nrels_mag = 1;
905  }
906}
907
908void w83781d_beep(struct i2c_client *client, int operation, int ctl_name,
909                 int *nrels_mag, long *results)
910{
911  struct w83781d_data *data = client->data;
912  if (operation == SENSORS_PROC_REAL_INFO)
913    *nrels_mag = 0;
914  else if (operation == SENSORS_PROC_REAL_READ) {
915    w83781d_update_client(client);
916    results[0] = data->beep[0];
917    results[1] = data->beep[1];
918    results[2] = data->beep[2];
919    *nrels_mag = 3;
920  } else if (operation == SENSORS_PROC_REAL_WRITE) {
921    data->beep[0] = results[0];
922    w83781d_write_value(client,W83781D_REG_BEEP_CONFIG,data->beep[0]);
923    data->beep[1] = results[1];
924    w83781d_write_value(client,W83781D_REG_BEEP_INTS1,data->beep[1]);
925    data->beep[2] = results[2];
926    w83781d_write_value(client,W83781D_REG_BEEP_INTS2,data->beep[2]);
927  }
928}
929
930void w83781d_fan_div(struct i2c_client *client, int operation, int ctl_name,
931                  int *nrels_mag, long *results)
932{
933  struct w83781d_data *data = client->data;
934  int old;
935
936  if (operation == SENSORS_PROC_REAL_INFO)
937    *nrels_mag = 0;
938  else if (operation == SENSORS_PROC_REAL_READ) {
939    w83781d_update_client(client);
940    results[0] = DIV_FROM_REG(data->fan_div[0]);
941    results[1] = DIV_FROM_REG(data->fan_div[1]);
942    results[2] = 2;
943    *nrels_mag = 3;
944  } else if (operation == SENSORS_PROC_REAL_WRITE) {
945    old = w83781d_read_value(client,W83781D_REG_VID_FANDIV);
946    if (*nrels_mag >= 2) {
947      data->fan_div[1] = DIV_TO_REG(results[1]);
948      old = (old & 0x3f) | (data->fan_div[1] << 6);
949    }
950    if (*nrels_mag >= 1) {
951      data->fan_div[0] = DIV_TO_REG(results[0]);
952      old = (old & 0xcf) | (data->fan_div[0] << 4);
953      w83781d_write_value(client,W83781D_REG_VID_FANDIV,old);
954    }
955  }
956}
957
958int w83781d_init(void)
959{
960  int res;
961
962  printk("w83781d.o version %s (%s)\n",LM_VERSION,LM_DATE);
963  w83781d_initialized = 0;
964
965  if ((res =i2c_add_driver(&w83781d_driver))) {
966    printk("w83781d.o: Driver registration failed, module not inserted.\n");
967    w83781d_cleanup();
968    return res;
969  }
970  w83781d_initialized ++;
971  return 0;
972}
973
974int w83781d_cleanup(void)
975{
976  int res;
977
978  if (w83781d_initialized >= 1) {
979    if ((res = i2c_del_driver(&w83781d_driver))) {
980      printk("w83781d.o: Driver deregistration failed, module not removed.\n");
981      return res;
982    }
983    w83781d_initialized --;
984  }
985  return 0;
986}
987
988
989#ifdef MODULE
990
991MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
992MODULE_DESCRIPTION("W83781D driver");
993
994int init_module(void)
995{
996  return w83781d_init();
997}
998
999int cleanup_module(void)
1000{
1001  return w83781d_cleanup();
1002}
1003
1004#endif /* MODULE */
1005
Note: See TracBrowser for help on using the browser.