root/lm-sensors/trunk/kernel/chips/adm1021.c @ 395

Revision 395, 16.9 KB (checked in by frodo, 14 years ago)

ADM1021 documentation

The old documentation of Phil is still present at the bottom of the file.
Phil may decide to remove it.

In the driver, file 'status' is renamed to 'alarms' and masked to display
only the alarm bits. This fits more closely with other drivers, and the
remaining bit was not interesting anyway.

I fixed a problem that made insertion of the module impossible (I made a
typo when I introduced the insmod parameters) *** Someone else seems to
have changed this at almost the same moment?!? Now it is correct. ***

The MAX1617 and MAX1617A are now also supported by the library.

Once more, some slight formatting changes are made in the documentation
generators (some columns were made wider).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    adm1021.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
5    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 "smbus.h"
25#include "sensors.h"
26#include "i2c.h"
27#include "i2c-isa.h"
28#include "version.h"
29
30/* Addresses to scan */
31static unsigned short normal_i2c[] = {SENSORS_I2C_END};
32static unsigned short normal_i2c_range[] = {0x18,0x1a,0x29,0x2b,
33                                            0x4c,0x4e,SENSORS_I2C_END};
34static unsigned int normal_isa[] = {SENSORS_ISA_END};
35static unsigned int normal_isa_range[] = {SENSORS_ISA_END};
36
37/* Insmod parameters */
38SENSORS_INSMOD_3(adm1021,max1617,max1617a);
39
40/* adm1021 constants specified below */
41
42/* The adm1021 registers */
43/* Read-only */
44#define ADM1021_REG_TEMP 0x00
45#define ADM1021_REG_REMOTE_TEMP 0x01
46#define ADM1021_REG_STATUS 0x02
47#define ADM1021_REG_MAN_ID 0x0FE  /* should always read 0x41 */
48#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 */
49#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */
50/* These use different addresses for reading/writing */
51#define ADM1021_REG_CONFIG_R 0x03
52#define ADM1021_REG_CONFIG_W 0x09
53#define ADM1021_REG_CONV_RATE_R 0x04
54#define ADM1021_REG_CONV_RATE_W 0x0A
55#define ADM1021_REG_TOS_R 0x05
56#define ADM1021_REG_TOS_W 0x0B
57#define ADM1021_REG_REMOTE_TOS_R 0x07
58#define ADM1021_REG_REMOTE_TOS_W 0x0D
59#define ADM1021_REG_THYST_R 0x06
60#define ADM1021_REG_THYST_W 0x0C
61#define ADM1021_REG_REMOTE_THYST_R 0x08
62#define ADM1021_REG_REMOTE_THYST_W 0x0E
63/* write-only */
64#define ADM1021_REG_ONESHOT 0x0F
65
66
67/* Conversions. Rounding and limit checking is only done on the TO_REG
68   variants. Note that you should be a bit careful with which arguments
69   these macros are called: arguments may be evaluated more than once.
70   Fixing this is just not worth it. */
71/* Conversions  note: 1021 uses normal integer signed-byte format*/
72#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val)
73#define TEMP_TO_REG(val)   (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255))
74
75/* Initial values */
76
77/* Note: Eventhough I left the low and high limits named os and hyst,
78they don't quite work like a thermostat the way the LM75 does.  I.e.,
79a lower temp than THYST actuall triggers an alarm instead of
80clearing it.  Weird, ey?   --Phil  */
81#define adm1021_INIT_TOS 60
82#define adm1021_INIT_THYST 20
83#define adm1021_INIT_REMOTE_TOS 60
84#define adm1021_INIT_REMOTE_THYST 20
85
86/* Each client has this additional data */
87struct adm1021_data {
88         int sysctl_id;
89         enum chips type;
90
91         struct semaphore update_lock;
92         char valid;                 /* !=0 if following fields are valid */
93         unsigned long last_updated; /* In jiffies */
94
95         u8 temp,temp_os,temp_hyst; /* Register values */
96         u8 remote_temp,remote_temp_os,remote_temp_hyst,alarms,die_code; 
97};
98
99#ifdef MODULE
100extern int init_module(void);
101extern int cleanup_module(void);
102#endif /* MODULE */
103
104static int adm1021_init(void);
105static int adm1021_cleanup(void);
106static int adm1021_attach_adapter(struct i2c_adapter *adapter);
107static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind);
108static void adm1021_init_client(struct i2c_client *client);
109static int adm1021_detach_client(struct i2c_client *client);
110static int adm1021_command(struct i2c_client *client, unsigned int cmd,
111                        void *arg);
112static void adm1021_inc_use (struct i2c_client *client);
113static void adm1021_dec_use (struct i2c_client *client);
114static int adm1021_read_value(struct i2c_client *client, u8 reg);
115static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value);
116static void adm1021_temp(struct i2c_client *client, int operation, int ctl_name,
117                      int *nrels_mag, long *results);
118static void adm1021_remote_temp(struct i2c_client *client, int operation, int ctl_name,
119                      int *nrels_mag, long *results);
120static void adm1021_alarms(struct i2c_client *client, int operation, int ctl_name,
121                      int *nrels_mag, long *results);
122static void adm1021_die_code(struct i2c_client *client, int operation, int ctl_name,
123                      int *nrels_mag, long *results);
124static void adm1021_update_client(struct i2c_client *client);
125
126
127/* This is the driver that will be inserted */
128static struct i2c_driver adm1021_driver = {
129  /* name */            "adm1021, MAX1617 sensor driver",
130  /* id */              I2C_DRIVERID_ADM1021,
131  /* flags */           DF_NOTIFY,
132  /* attach_adapter */  &adm1021_attach_adapter,
133  /* detach_client */   &adm1021_detach_client,
134  /* command */         &adm1021_command,
135  /* inc_use */         &adm1021_inc_use,
136  /* dec_use */         &adm1021_dec_use
137};
138
139/* These files are created for each detected adm1021. This is just a template;
140   though at first sight, you might think we could use a statically
141   allocated list, we need some way to get back to the parent - which
142   is done through one of the 'extra' fields which are initialized
143   when a new copy is allocated. */
144static ctl_table adm1021_dir_table_template[] = {
145  { ADM1021_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real,
146    &sensors_sysctl_real, NULL, &adm1021_temp },
147    {ADM1021_SYSCTL_REMOTE_TEMP, "remote_temp", NULL, 0, 0644, NULL, &sensors_proc_real,
148    &sensors_sysctl_real, NULL, &adm1021_remote_temp },
149    {ADM1021_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &sensors_proc_real,
150    &sensors_sysctl_real, NULL, &adm1021_die_code },
151    {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &sensors_proc_real,
152    &sensors_sysctl_real, NULL, &adm1021_alarms },
153  { 0 }
154};
155
156static ctl_table adm1021_max_dir_table_template[] = {
157  { ADM1021_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real,
158    &sensors_sysctl_real, NULL, &adm1021_temp },
159    {ADM1021_SYSCTL_REMOTE_TEMP, "remote_temp", NULL, 0, 0644, NULL, &sensors_proc_real,
160    &sensors_sysctl_real, NULL, &adm1021_remote_temp },
161    {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &sensors_proc_real,
162    &sensors_sysctl_real, NULL, &adm1021_alarms },
163  { 0 }
164};
165
166
167/* Used by init/cleanup */
168static int adm1021_initialized = 0;
169
170/* I choose here for semi-static allocation. Complete dynamic
171   allocation could also be used; the code needed for this would probably
172   take more memory than the datastructure takes now. */
173#define MAX_ADM1021_NR 9
174static struct i2c_client *adm1021_list[MAX_ADM1021_NR];
175
176int adm1021_attach_adapter(struct i2c_adapter *adapter)
177{
178  return sensors_detect(adapter,&addr_data,adm1021_detect);
179}
180
181static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
182{ 
183  int i;
184  struct i2c_client *new_client;
185  struct adm1021_data *data;
186  int err=0;
187  const char *type_name = "";
188  const char *client_name = "";
189
190  /* Make sure we aren't probing the ISA bus!! This is just a safety check
191     at this moment; sensors_detect really won't call us. */
192#ifdef DEBUG
193  if (i2c_is_isa_adapter(adapter)) {
194    printk("adm1021.o: adm1021_detect called for an ISA bus adapter?!?\n");
195    return 0;
196  }
197#endif
198
199
200  /* We need address registration for the I2C bus too. That is not yet
201     implemented. */
202
203  /* OK. For now, we presume we have a valid client. We now create the
204     client structure, even though we cannot fill it completely yet.
205     But it allows us to access adm1021_{read,write}_value. */
206
207  if (! (new_client = kmalloc(sizeof(struct i2c_client) +
208                               sizeof(struct adm1021_data),
209                               GFP_KERNEL))) {
210    err = -ENOMEM;
211    goto ERROR0;
212  }
213
214  data = (struct adm1021_data *) (new_client + 1);
215  new_client->addr = address;
216  new_client->data = data;
217  new_client->adapter = adapter;
218  new_client->driver = &adm1021_driver;
219
220  /* Now, we do the remaining detection. */
221
222  if (kind < 0) {
223    if ((adm1021_read_value(new_client,ADM1021_REG_STATUS) & 0x03) != 0x00)
224      goto ERROR1;
225  }
226
227  /* Determine the chip type. */
228 
229  if (kind <= 0) {
230    i = adm1021_read_value(new_client,ADM1021_REG_MAN_ID);
231    if (i == 0x41)
232      kind = adm1021;
233    else if ((i== 0x4d) && 
234             (adm1021_read_value(new_client,ADM1021_REG_DEV_ID) == 0x01))
235      kind = max1617a;
236    else 
237      kind = max1617;
238  }
239
240  if (kind == max1617) {
241    type_name = "max1617";
242    client_name = "MAX1617 chip";
243  } else if (kind == max1617a) {
244    type_name = "max1617a";
245    client_name = "MAX1617A chip";
246  } else if (kind == adm1021) {
247    type_name = "adm1021";
248    client_name = "ADM1021 chip";
249  } else {
250#ifdef DEBUG
251    printk("adm1021.o: Internal error: unknown kind (%d)?!?",kind);
252#endif
253    goto ERROR1;
254  }
255
256  /* Fill in the remaining client fields and put it into the global list */
257  strcpy(new_client->name,client_name);
258  data->type = kind;
259
260  for(i = 0; i < MAX_ADM1021_NR; i++)
261    if (! adm1021_list[i])
262      break;
263  if (i == MAX_ADM1021_NR) {
264    printk("adm1021.o: No empty slots left, recompile and heighten "
265           "MAX_ADM1021_NR!\n");
266    err = -ENOMEM;
267    goto ERROR2;
268  }
269  adm1021_list[i] = new_client;
270  new_client->id = i;
271  data->valid = 0;
272  data->update_lock = MUTEX;
273
274  /* Tell the I2C layer a new client has arrived */
275  if ((err = i2c_attach_client(new_client)))
276    goto ERROR3;
277
278  /* Register a new directory entry with module sensors */
279  if ((i = sensors_register_entry((struct i2c_client *) new_client,
280                        type_name,
281                        data->type==adm1021?adm1021_dir_table_template:
282                                    adm1021_max_dir_table_template)) < 0) {
283    err = i;
284    goto ERROR4;
285  }
286  data->sysctl_id = i;
287
288  /* Initialize the ADM1021 chip */
289  adm1021_init_client((struct i2c_client *) new_client);
290  return 0;
291
292/* OK, this is not exactly good programming practice, usually. But it is
293   very code-efficient in this case. */
294
295ERROR4:
296  i2c_detach_client(new_client);
297ERROR3:
298  for (i = 0; i < MAX_ADM1021_NR; i++)
299    if (new_client == adm1021_list[i])
300      adm1021_list[i] = NULL;
301ERROR2:
302ERROR1:
303  kfree(new_client);
304ERROR0:
305  return err;
306}
307
308void adm1021_init_client(struct i2c_client *client)
309{
310  /* Initialize the adm1021 chip */
311  adm1021_write_value(client,ADM1021_REG_TOS_W,
312                   TEMP_TO_REG(adm1021_INIT_TOS));
313  adm1021_write_value(client,ADM1021_REG_THYST_W,
314                   TEMP_TO_REG(adm1021_INIT_THYST));
315  adm1021_write_value(client,ADM1021_REG_REMOTE_TOS_W,
316                   TEMP_TO_REG(adm1021_INIT_REMOTE_TOS));
317  adm1021_write_value(client,ADM1021_REG_REMOTE_THYST_W,
318                   TEMP_TO_REG(adm1021_INIT_REMOTE_THYST));
319  /* Enable ADC and disable suspend mode */
320  adm1021_write_value(client,ADM1021_REG_CONFIG_W,0); 
321  /* Set Conversion rate to 1/sec (this can be tinkered with) */
322  adm1021_write_value(client,ADM1021_REG_CONV_RATE_W,0x04); 
323}
324
325int adm1021_detach_client(struct i2c_client *client)
326{
327
328  int err,i;
329
330  sensors_deregister_entry(((struct adm1021_data *)(client->data))->sysctl_id);
331
332  if ((err = i2c_detach_client(client))) {
333    printk("adm1021.o: Client deregistration failed, client not detached.\n");
334    return err;
335  }
336
337  for (i = 0; i < MAX_ADM1021_NR; i++)
338    if (client == adm1021_list[i])
339      break;
340  if ((i == MAX_ADM1021_NR)) {
341    printk("adm1021.o: Client to detach not found.\n");
342    return -ENOENT;
343  }
344  adm1021_list[i] = NULL;
345
346  kfree(client);
347
348  return 0;
349
350}
351
352
353/* No commands defined yet */
354int adm1021_command(struct i2c_client *client, unsigned int cmd, void *arg)
355{
356  return 0;
357}
358
359void adm1021_inc_use (struct i2c_client *client)
360{
361#ifdef MODULE
362  MOD_INC_USE_COUNT;
363#endif
364}
365
366void adm1021_dec_use (struct i2c_client *client)
367{
368#ifdef MODULE
369  MOD_DEC_USE_COUNT;
370#endif
371}
372
373/* All registers are byte-sized */
374int adm1021_read_value(struct i2c_client *client, u8 reg)
375{
376    return smbus_read_byte_data(client->adapter,client->addr,reg);
377}
378
379int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value)
380{
381    return smbus_write_byte_data(client->adapter,client->addr,reg,value);
382}
383
384void adm1021_update_client(struct i2c_client *client)
385{
386  struct adm1021_data *data = client->data;
387
388  down(&data->update_lock);
389
390  if ((jiffies - data->last_updated > HZ+HZ/2 ) ||
391      (jiffies < data->last_updated) || ! data->valid) {
392
393#ifdef DEBUG
394    printk("Starting adm1021 update\n");
395#endif
396
397    data->temp = adm1021_read_value(client,ADM1021_REG_TEMP);
398    data->temp_os = adm1021_read_value(client,ADM1021_REG_TOS_R);
399    data->temp_hyst = adm1021_read_value(client,ADM1021_REG_THYST_R);
400    data->remote_temp = adm1021_read_value(client,ADM1021_REG_REMOTE_TEMP);
401    data->remote_temp_os = adm1021_read_value(client,ADM1021_REG_REMOTE_TOS_R);
402    data->remote_temp_hyst = adm1021_read_value(client,ADM1021_REG_REMOTE_THYST_R);
403    data->alarms = adm1021_read_value(client,ADM1021_REG_STATUS) & 0xec;
404    if (data->type == adm1021)
405      data->die_code = adm1021_read_value(client,ADM1021_REG_DIE_CODE);
406    data->last_updated = jiffies;
407    data->valid = 1;
408  }
409
410  up(&data->update_lock);
411}
412
413
414void adm1021_temp(struct i2c_client *client, int operation, int ctl_name,
415               int *nrels_mag, long *results)
416{
417  struct adm1021_data *data = client->data;
418  if (operation == SENSORS_PROC_REAL_INFO)
419    *nrels_mag = 0;
420  else if (operation == SENSORS_PROC_REAL_READ) {
421    adm1021_update_client(client);
422    results[0] = TEMP_FROM_REG(data->temp_os);
423    results[1] = TEMP_FROM_REG(data->temp_hyst);
424    results[2] = TEMP_FROM_REG(data->temp);
425    *nrels_mag = 3;
426  } else if (operation == SENSORS_PROC_REAL_WRITE) {
427    if (*nrels_mag >= 1) {
428      data->temp_os = TEMP_TO_REG(results[0]);
429      adm1021_write_value(client,ADM1021_REG_TOS_W,data->temp_os);
430    }
431    if (*nrels_mag >= 2) {
432      data->temp_hyst = TEMP_TO_REG(results[1]);
433      adm1021_write_value(client,ADM1021_REG_THYST_W,data->temp_hyst);
434    }
435  }
436}
437
438void adm1021_remote_temp(struct i2c_client *client, int operation, int ctl_name,
439               int *nrels_mag, long *results)
440{
441  struct adm1021_data *data = client->data;
442  if (operation == SENSORS_PROC_REAL_INFO)
443    *nrels_mag = 0;
444  else if (operation == SENSORS_PROC_REAL_READ) {
445    adm1021_update_client(client);
446    results[0] = TEMP_FROM_REG(data->remote_temp_os);
447    results[1] = TEMP_FROM_REG(data->remote_temp_hyst);
448    results[2] = TEMP_FROM_REG(data->remote_temp);
449    *nrels_mag = 3;
450  } else if (operation == SENSORS_PROC_REAL_WRITE) {
451    if (*nrels_mag >= 1) {
452      data->remote_temp_os = TEMP_TO_REG(results[0]);
453      adm1021_write_value(client,ADM1021_REG_REMOTE_TOS_W,data->remote_temp_os);
454    }
455    if (*nrels_mag >= 2) {
456      data->remote_temp_hyst = TEMP_TO_REG(results[1]);
457      adm1021_write_value(client,ADM1021_REG_REMOTE_THYST_W,data->remote_temp_hyst);
458    }
459  }
460}
461
462void adm1021_die_code(struct i2c_client *client, int operation, int ctl_name,
463               int *nrels_mag, long *results)
464{
465  struct adm1021_data *data = client->data;
466  if (operation == SENSORS_PROC_REAL_INFO)
467    *nrels_mag = 0;
468  else if (operation == SENSORS_PROC_REAL_READ) {
469    adm1021_update_client(client);
470    results[0] = data->die_code;
471    *nrels_mag = 1;
472  } else if (operation == SENSORS_PROC_REAL_WRITE) {
473    /* Can't write to it */
474  }
475}
476
477void adm1021_alarms(struct i2c_client *client, int operation, int ctl_name,
478               int *nrels_mag, long *results)
479{
480  struct adm1021_data *data = client->data;
481  if (operation == SENSORS_PROC_REAL_INFO)
482    *nrels_mag = 0;
483  else if (operation == SENSORS_PROC_REAL_READ) {
484    adm1021_update_client(client);
485    results[0] = data->alarms;
486    *nrels_mag = 1;
487  } else if (operation == SENSORS_PROC_REAL_WRITE) {
488    /* Can't write to it */
489  }
490}
491
492int adm1021_init(void)
493{
494  int res;
495
496  printk("adm1021.o version %s (%s)\n",LM_VERSION,LM_DATE);
497  adm1021_initialized = 0;
498  if ((res = i2c_add_driver(&adm1021_driver))) {
499    printk("adm1021.o: Driver registration failed, module not inserted.\n");
500    adm1021_cleanup();
501    return res;
502  }
503  adm1021_initialized ++;
504  return 0;
505}
506
507int adm1021_cleanup(void)
508{
509  int res;
510
511  if (adm1021_initialized >= 1) {
512    if ((res = i2c_del_driver(&adm1021_driver))) {
513      printk("adm1021.o: Driver deregistration failed, module not removed.\n");
514      return res;
515    }
516    adm1021_initialized --;
517  }
518
519  return 0;
520}
521
522
523#ifdef MODULE
524
525MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
526MODULE_DESCRIPTION("adm1021 driver");
527
528int init_module(void)
529{
530  return adm1021_init();
531}
532
533int cleanup_module(void)
534{
535  return adm1021_cleanup();
536}
537
538#endif /* MODULE */
539
Note: See TracBrowser for help on using the browser.