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

Revision 640, 17.0 KB (checked in by frodo, 13 years ago)

Patches to make it compatible with kernel 2.3.27 and newer

* Improved monitoring of /proc directories

Instead of doing:

proc_bus_i2c->fill_inode = &monitor_bus_i2c;
void monitor_bus_i2c(struct inode *inode, int fill)
{

if (fill)

MOD_INC_USE_COUNT;

else

MOD_DEC_USE_COUNT;

}

you can now simply set:

proc_bus_i2c->owner = THIS_MODULE;

and this is just as good!

* An old 2.3 problem seemingly never was resolved yet: instead of using

a *wait_queue directly, you have to use a wait_queue_head_t and
initialize it properly:

#if (LINUX_VERSION_CODE < 0x020301)
static struct wait_queue *pcf_wait = NULL;
#else
static wait_queue_head_t pcf_wait;
#endif

#if (LINUX_VERSION_CODE >= 0x020301)

init_waitqueue_head(&pcf_wait);

#endif

except for this, semantics remain the same (but using a plain
wait_queue_head_t instead of a pointer to a wait_queue)

* I had to change the semantics of sensors_register_entry slightly,

to make the monitoring of /proc/sys/dev/* files possible for kernels
2.3.27 and newer. It now takes an additional parameter, which you
can specify as THIS_MODULE.

* THIS_MODULE is only defined in kernels 2.3.13 and later; added

it to compat.h and the compatibility section of mkpatch.

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