root/lm-sensors/trunk/kernel/chips/ds1621.c @ 1193

Revision 1193, 18.0 KB (checked in by mds, 12 years ago)

malloc.h -> slab.h

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    ds1621.c - Part of lm_sensors, Linux kernel modules for hardware
3             monitoring
4    Christian W. Zuckschwerdt  <zany@triq.net>  2000-11-23
5    based on lm75.c by Frodo Looijaard <frodol@dds.nl>
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/* Supports DS1621. See doc/chips/ds1621 for details */
23
24#include <linux/version.h>
25#include <linux/module.h>
26#include <linux/slab.h>
27#include <linux/i2c.h>
28#include "sensors.h"
29#include "version.h"
30#include <linux/init.h>
31
32
33#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \
34    (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0))
35#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
36#endif
37
38#ifndef THIS_MODULE
39#define THIS_MODULE NULL
40#endif
41
42/* Addresses to scan */
43static unsigned short normal_i2c[] = { SENSORS_I2C_END };
44static unsigned short normal_i2c_range[] = { 0x48, 0x4f, SENSORS_I2C_END };
45static unsigned int normal_isa[] = { SENSORS_ISA_END };
46static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
47
48/* Insmod parameters */
49SENSORS_INSMOD_1(ds1621);
50
51/* Many DS1621 constants specified below */
52
53/* Config register used for detection         */
54/*  7    6    5    4    3    2    1    0      */
55/* |Done|THF |TLF |NVB | 1  | 0  |POL |1SHOT| */
56#define DS1621_REG_CONFIG_MASK 0x0C
57#define DS1621_REG_CONFIG_VAL 0x08
58#define DS1621_REG_CONFIG_POLARITY 0x02
59#define DS1621_REG_CONFIG_1SHOT 0x01
60#define DS1621_REG_CONFIG_DONE 0x80
61
62/* Note: the done bit is always unset if continuous conversion is in progress.
63         We need to stop the continuous conversion or switch to single shot
64         before this bit becomes available!
65 */
66
67/* The DS1621 registers */
68#define DS1621_REG_TEMP 0xAA /* word, RO */
69#define DS1621_REG_TEMP_OVER 0xA1 /* word, RW */
70#define DS1621_REG_TEMP_HYST 0xA2 /* word, RW -- it's a low temp trigger */
71#define DS1621_REG_CONF 0xAC /* byte, RW */
72#define DS1621_REG_TEMP_COUNTER 0xA8 /* byte, RO */
73#define DS1621_REG_TEMP_SLOPE 0xA9 /* byte, RO */
74#define DS1621_COM_START 0xEE /* no data */
75#define DS1621_COM_STOP 0x22 /* no data */
76
77/* Conversions. Rounding and limit checking is only done on the TO_REG
78   variants. Note that you should be a bit careful with which arguments
79   these macros are called: arguments may be evaluated more than once.
80   Fixing this is just not worth it. */
81#define TEMP_FROM_REG(val) ((((val & 0x7fff) >> 7) * 5) | \
82                            ((val & 0x8000)?-256:0))
83#define TEMP_TO_REG(val)   (SENSORS_LIMIT((val<0 ? (0x200+((val)/5))<<7 : \
84                                          (((val) + 2) / 5) << 7),0,0xffff))
85#define ALARMS_FROM_REG(val) ((val) & \
86                              (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
87#define ITEMP_FROM_REG(val) ((((val & 0x7fff) >> 8)) | \
88                            ((val & 0x8000)?-256:0))
89
90/* Initial values */
91#define DS1621_INIT_TEMP_OVER 600
92#define DS1621_INIT_TEMP_HYST 0 /* 500 would cause an alarm at room temp. */
93
94/* Each client has this additional data */
95struct ds1621_data {
96        int sysctl_id;
97
98        struct semaphore update_lock;
99        char valid;             /* !=0 if following fields are valid */
100        unsigned long last_updated;     /* In jiffies */
101
102        u16 temp, temp_over, temp_hyst; /* Register values, word */
103        u8 conf;                        /* Register encoding, combined */
104
105        char enable;    /* !=0 if we're expected to restart the conversion */
106        u8 temp_int, temp_counter, temp_slope;  /* Register values, byte */
107};
108
109#ifdef MODULE
110extern int init_module(void);
111extern int cleanup_module(void);
112#endif                          /* MODULE */
113
114#ifdef MODULE
115static
116#else
117extern
118#endif
119int __init sensors_ds1621_init(void);
120static int __init ds1621_cleanup(void);
121static int ds1621_attach_adapter(struct i2c_adapter *adapter);
122static int ds1621_detect(struct i2c_adapter *adapter, int address,
123                         unsigned short flags, int kind);
124static void ds1621_init_client(struct i2c_client *client);
125static int ds1621_detach_client(struct i2c_client *client);
126static int ds1621_command(struct i2c_client *client, unsigned int cmd,
127                          void *arg);
128static void ds1621_inc_use(struct i2c_client *client);
129static void ds1621_dec_use(struct i2c_client *client);
130static u16 swap_bytes(u16 val);
131static int ds1621_read_value(struct i2c_client *client, u8 reg);
132static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value);
133static void ds1621_temp(struct i2c_client *client, int operation,
134                        int ctl_name, int *nrels_mag, long *results);
135static void ds1621_alarms(struct i2c_client *client, int operation,
136                          int ctl_name, int *nrels_mag, long *results);
137static void ds1621_enable(struct i2c_client *client, int operation,
138                          int ctl_name, int *nrels_mag, long *results);
139static void ds1621_continuous(struct i2c_client *client, int operation,
140                              int ctl_name, int *nrels_mag, long *results);
141static void ds1621_polarity(struct i2c_client *client, int operation,
142                            int ctl_name, int *nrels_mag, long *results);
143static void ds1621_update_client(struct i2c_client *client);
144
145
146/* This is the driver that will be inserted */
147static struct i2c_driver ds1621_driver = {
148        /* name */ "DS1621 sensor driver",
149        /* id */ I2C_DRIVERID_DS1621,
150        /* flags */ I2C_DF_NOTIFY,
151        /* attach_adapter */ &ds1621_attach_adapter,
152        /* detach_client */ &ds1621_detach_client,
153        /* command */ &ds1621_command,
154        /* inc_use */ &ds1621_inc_use,
155        /* dec_use */ &ds1621_dec_use
156};
157
158/* These files are created for each detected DS1621. This is just a template;
159   though at first sight, you might think we could use a statically
160   allocated list, we need some way to get back to the parent - which
161   is done through one of the 'extra' fields which are initialized
162   when a new copy is allocated. */
163static ctl_table ds1621_dir_table_template[] = {
164        {DS1621_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL,
165         &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_temp},
166        {DS1621_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
167         &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_alarms},
168        {DS1621_SYSCTL_ENABLE, "enable", NULL, 0, 0644, NULL,
169         &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_enable},
170        {DS1621_SYSCTL_CONTINUOUS, "continuous", NULL, 0, 0644, NULL,
171         &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_continuous},
172        {DS1621_SYSCTL_POLARITY, "polarity", NULL, 0, 0644, NULL,
173         &i2c_proc_real, &i2c_sysctl_real, NULL, &ds1621_polarity},
174        {0}
175};
176
177/* Used by init/cleanup */
178static int __initdata ds1621_initialized = 0;
179
180static int ds1621_id = 0;
181
182int ds1621_attach_adapter(struct i2c_adapter *adapter)
183{
184        return i2c_detect(adapter, &addr_data, ds1621_detect);
185}
186
187/* This function is called by i2c_detect */
188int ds1621_detect(struct i2c_adapter *adapter, int address,
189                unsigned short flags, int kind)
190{
191        int i, conf;
192        struct i2c_client *new_client;
193        struct ds1621_data *data;
194        int err = 0;
195        const char *type_name, *client_name;
196
197        /* Make sure we aren't probing the ISA bus!! This is just a safety check
198           at this moment; i2c_detect really won't call us. */
199#ifdef DEBUG
200        if (i2c_is_isa_adapter(adapter)) {
201                printk
202                 ("ds1621.o: ds1621_detect called for an ISA bus adapter?!?\n");
203                return 0;
204        }
205#endif
206
207        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
208                                     I2C_FUNC_SMBUS_WORD_DATA))
209                    goto ERROR0;
210
211        /* OK. For now, we presume we have a valid client. We now create the
212           client structure, even though we cannot fill it completely yet.
213           But it allows us to access ds1621_{read,write}_value. */
214        if (!(new_client = kmalloc(sizeof(struct i2c_client) +
215                                   sizeof(struct ds1621_data),
216                                   GFP_KERNEL))) {
217                err = -ENOMEM;
218                goto ERROR0;
219        }
220
221        data = (struct ds1621_data *) (new_client + 1);
222        new_client->addr = address;
223        new_client->data = data;
224        new_client->adapter = adapter;
225        new_client->driver = &ds1621_driver;
226        new_client->flags = 0;
227
228        /* Now, we do the remaining detection. It is lousy. */
229        if (kind < 0) {
230                conf = i2c_smbus_read_byte_data(new_client,
231                                                DS1621_REG_CONF);
232                if ((conf & DS1621_REG_CONFIG_MASK)
233                    != DS1621_REG_CONFIG_VAL)
234                        goto ERROR1;
235        }
236
237        /* Determine the chip type - only one kind supported! */
238        if (kind <= 0)
239                kind = ds1621;
240
241        if (kind == ds1621) {
242                type_name = "ds1621";
243                client_name = "DS1621 chip";
244        } else {
245#ifdef DEBUG
246                printk("ds1621.o: Internal error: unknown kind (%d)?!?",
247                       kind);
248#endif
249                goto ERROR1;
250        }
251
252        /* Fill in remaining client fields and put it into the global list */
253        strcpy(new_client->name, client_name);
254
255        new_client->id = ds1621_id++;
256        data->valid = 0;
257        init_MUTEX(&data->update_lock);
258
259        /* Tell the I2C layer a new client has arrived */
260        if ((err = i2c_attach_client(new_client)))
261                goto ERROR3;
262
263        /* Register a new directory entry with module sensors */
264        if ((i = i2c_register_entry(new_client, type_name,
265                                        ds1621_dir_table_template,
266                                        THIS_MODULE)) < 0) {
267                err = i;
268                goto ERROR4;
269        }
270        data->sysctl_id = i;
271
272        ds1621_init_client(new_client);
273        return 0;
274
275/* OK, this is not exactly good programming practice, usually. But it is
276   very code-efficient in this case. */
277
278      ERROR4:
279        i2c_detach_client(new_client);
280      ERROR3:
281      ERROR1:
282        kfree(new_client);
283      ERROR0:
284        return err;
285}
286
287int ds1621_detach_client(struct i2c_client *client)
288{
289        int err;
290
291#ifdef MODULE
292        if (MOD_IN_USE)
293                return -EBUSY;
294#endif
295
296
297        i2c_deregister_entry(((struct ds1621_data *) (client->data))->
298                                 sysctl_id);
299
300        if ((err = i2c_detach_client(client))) {
301                printk
302           ("ds1621.o: Client deregistration failed, client not detached.\n");
303                return err;
304        }
305
306        kfree(client);
307
308        return 0;
309}
310
311
312/* No commands defined yet */
313int ds1621_command(struct i2c_client *client, unsigned int cmd, void *arg)
314{
315        return 0;
316}
317
318/* Nothing here yet */
319void ds1621_inc_use(struct i2c_client *client)
320{
321#ifdef MODULE
322        MOD_INC_USE_COUNT;
323#endif
324}
325
326/* Nothing here yet */
327void ds1621_dec_use(struct i2c_client *client)
328{
329#ifdef MODULE
330        MOD_DEC_USE_COUNT;
331#endif
332}
333
334u16 swap_bytes(u16 val)
335{
336        return (val >> 8) | (val << 8);
337}
338
339/* All registers are word-sized, except for the configuration register.
340   DS1621 uses a high-byte first convention, which is exactly opposite to
341   the usual practice. */
342int ds1621_read_value(struct i2c_client *client, u8 reg)
343{
344        if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER)
345            || (reg == DS1621_REG_TEMP_SLOPE))
346                return i2c_smbus_read_byte_data(client, reg);
347        else
348                return swap_bytes(i2c_smbus_read_word_data(client, reg));
349}
350
351/* All registers are word-sized, except for the configuration register.
352   DS1621 uses a high-byte first convention, which is exactly opposite to
353   the usual practice. */
354int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
355{
356        if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER)
357            || (reg == DS1621_REG_TEMP_SLOPE))
358                return i2c_smbus_write_byte_data(client, reg, value);
359        else
360                return i2c_smbus_write_word_data(client, reg,
361                                                 swap_bytes(value));
362}
363
364void ds1621_init_client(struct i2c_client *client)
365{
366        /* Initialize the DS1621 chip */
367        ds1621_write_value(client, DS1621_REG_TEMP_OVER,
368                         TEMP_TO_REG(DS1621_INIT_TEMP_OVER));
369        ds1621_write_value(client, DS1621_REG_TEMP_HYST,
370                         TEMP_TO_REG(DS1621_INIT_TEMP_HYST));
371        ds1621_write_value(client, DS1621_REG_CONF, 0);
372
373        /* perhaps we should start the continous conversion? For now */
374        /* you got to do that yourself using the "enable" in proc */
375}
376
377void ds1621_update_client(struct i2c_client *client)
378{
379        struct ds1621_data *data = client->data;
380        u8 new_conf;
381
382        down(&data->update_lock);
383
384        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
385            (jiffies < data->last_updated) || !data->valid) {
386
387#ifdef DEBUG
388                printk("Starting ds1621 update\n");
389#endif
390
391                data->conf = ds1621_read_value(client, DS1621_REG_CONF);
392
393                data->temp = ds1621_read_value(client,
394                                               DS1621_REG_TEMP);
395                data->temp_over = ds1621_read_value(client,
396                                                    DS1621_REG_TEMP_OVER);
397                data->temp_hyst = ds1621_read_value(client,
398                                                    DS1621_REG_TEMP_HYST);
399
400                /* wait for the DONE bit before reading extended values */
401
402                if (data->conf & DS1621_REG_CONFIG_DONE) {
403                        data->temp_counter = ds1621_read_value(client,
404                                                     DS1621_REG_TEMP_COUNTER);
405                        data->temp_slope = ds1621_read_value(client,
406                                                     DS1621_REG_TEMP_SLOPE);
407                        data->temp_int = ITEMP_FROM_REG(data->temp);
408                        /* restart the conversion */
409                        if (data->enable)
410                                ds1621_read_value(client, DS1621_COM_START);
411                }
412
413                /* reset alarms if neccessary */
414                new_conf = data->conf;
415                if (data->temp < data->temp_over)
416                        new_conf &= ~DS1621_ALARM_TEMP_HIGH;
417                if (data->temp > data->temp_hyst)
418                        new_conf &= ~DS1621_ALARM_TEMP_LOW;
419                if (data->conf != new_conf)
420                        ds1621_write_value(client, DS1621_REG_CONF,
421                                           new_conf);
422
423                data->last_updated = jiffies;
424                data->valid = 1;
425        }
426
427        up(&data->update_lock);
428}
429
430
431void ds1621_temp(struct i2c_client *client, int operation, int ctl_name,
432                 int *nrels_mag, long *results)
433{
434        struct ds1621_data *data = client->data;
435        if (operation == SENSORS_PROC_REAL_INFO)
436                if (!(data->conf & DS1621_REG_CONFIG_DONE) ||
437                    (data->temp_counter > data->temp_slope) ||
438                    (data->temp_slope == 0)) {
439                        *nrels_mag = 1;
440                } else {
441                        *nrels_mag = 2;
442                }
443        else if (operation == SENSORS_PROC_REAL_READ) {
444                ds1621_update_client(client);
445                /* decide wether to calculate more precise temp */
446                if (!(data->conf & DS1621_REG_CONFIG_DONE) ||
447                    (data->temp_counter > data->temp_slope) ||
448                    (data->temp_slope == 0)) {
449                        results[0] = TEMP_FROM_REG(data->temp_over);
450                        results[1] = TEMP_FROM_REG(data->temp_hyst);
451                        results[2] = TEMP_FROM_REG(data->temp);
452                } else {
453                        results[0] = TEMP_FROM_REG(data->temp_over)*10;
454                        results[1] = TEMP_FROM_REG(data->temp_hyst)*10;
455                        results[2] = data->temp_int * 100 - 25 +
456                                ((data->temp_slope - data->temp_counter) *
457                                 100 / data->temp_slope);
458                }
459                *nrels_mag = 3;
460        } else if (operation == SENSORS_PROC_REAL_WRITE) {
461                if (*nrels_mag >= 1) {
462                        data->temp_over = TEMP_TO_REG(results[0]);
463                        ds1621_write_value(client, DS1621_REG_TEMP_OVER,
464                                         data->temp_over);
465                }
466                if (*nrels_mag >= 2) {
467                        data->temp_hyst = TEMP_TO_REG(results[1]);
468                        ds1621_write_value(client, DS1621_REG_TEMP_HYST,
469                                         data->temp_hyst);
470                }
471        }
472}
473
474void ds1621_alarms(struct i2c_client *client, int operation, int ctl_name,
475                   int *nrels_mag, long *results)
476{
477        struct ds1621_data *data = client->data;
478        if (operation == SENSORS_PROC_REAL_INFO)
479                *nrels_mag = 0;
480        else if (operation == SENSORS_PROC_REAL_READ) {
481                ds1621_update_client(client);
482                results[0] = ALARMS_FROM_REG(data->conf);
483                *nrels_mag = 1;
484        }
485}
486
487void ds1621_enable(struct i2c_client *client, int operation, int ctl_name,
488                   int *nrels_mag, long *results)
489{
490        /* If you really screw up your chip (like I did) this is */
491        /* sometimes needed to (re)start the continous conversion */
492        /* there is no data to read so this might hang your SMBus! */
493
494        struct ds1621_data *data = client->data;
495        if (operation == SENSORS_PROC_REAL_INFO)
496                *nrels_mag = 0;
497        else if (operation == SENSORS_PROC_REAL_READ) {
498                ds1621_update_client(client);
499                results[0] = !(data->conf & DS1621_REG_CONFIG_DONE);
500                *nrels_mag = 1;
501        } else if (operation == SENSORS_PROC_REAL_WRITE) {
502                if (*nrels_mag >= 1) {
503                        if (results[0]) {
504                                ds1621_read_value(client, DS1621_COM_START);
505                                data->enable=1;
506                        } else {
507                                ds1621_read_value(client, DS1621_COM_STOP);
508                                data->enable=0;
509                        }
510                } else {
511                        ds1621_read_value(client, DS1621_COM_START);
512                        data->enable=1;
513                }
514        }
515}
516
517void ds1621_continuous(struct i2c_client *client, int operation, int ctl_name,
518                       int *nrels_mag, long *results)
519{
520        struct ds1621_data *data = client->data;
521        if (operation == SENSORS_PROC_REAL_INFO)
522                *nrels_mag = 0;
523        else if (operation == SENSORS_PROC_REAL_READ) {
524                ds1621_update_client(client);
525                results[0] = !(data->conf & DS1621_REG_CONFIG_1SHOT);
526                *nrels_mag = 1;
527        } else if (operation == SENSORS_PROC_REAL_WRITE) {
528                ds1621_update_client(client);
529                if (*nrels_mag >= 1) {
530                        if (results[0]) {
531                                ds1621_write_value(client, DS1621_REG_CONF,
532                                                   data->conf & ~DS1621_REG_CONFIG_1SHOT);
533                        } else {
534                                ds1621_write_value(client, DS1621_REG_CONF,
535                                                   data->conf | DS1621_REG_CONFIG_1SHOT);
536                        }
537                } else {
538                        ds1621_write_value(client, DS1621_REG_CONF,
539                                           data->conf & ~DS1621_REG_CONFIG_1SHOT);
540                }
541        }
542}
543
544void ds1621_polarity(struct i2c_client *client, int operation, int ctl_name,
545                     int *nrels_mag, long *results)
546{
547        struct ds1621_data *data = client->data;
548        if (operation == SENSORS_PROC_REAL_INFO)
549                *nrels_mag = 0;
550        else if (operation == SENSORS_PROC_REAL_READ) {
551                ds1621_update_client(client);
552                results[0] = !(!(data->conf & DS1621_REG_CONFIG_POLARITY));
553                *nrels_mag = 1;
554        } else if (operation == SENSORS_PROC_REAL_WRITE) {
555                ds1621_update_client(client);
556                if (*nrels_mag >= 1) {
557                        if (results[0]) {
558                                ds1621_write_value(client, DS1621_REG_CONF,
559                                                   data->conf | DS1621_REG_CONFIG_POLARITY);
560                        } else {
561                                ds1621_write_value(client, DS1621_REG_CONF,
562                                                   data->conf & ~DS1621_REG_CONFIG_POLARITY);
563                        }
564                }
565        }
566}
567
568int __init sensors_ds1621_init(void)
569{
570        int res;
571
572        printk("ds1621.o version %s (%s)\n", LM_VERSION, LM_DATE);
573        ds1621_initialized = 0;
574        if ((res = i2c_add_driver(&ds1621_driver))) {
575                printk
576            ("ds1621.o: Driver registration failed, module not inserted.\n");
577                ds1621_cleanup();
578                return res;
579        }
580        ds1621_initialized++;
581        return 0;
582}
583
584int __init ds1621_cleanup(void)
585{
586        int res;
587
588        if (ds1621_initialized >= 1) {
589                if ((res = i2c_del_driver(&ds1621_driver))) {
590                        printk
591                            ("ds1621.o: Driver deregistration failed, module not removed.\n");
592                        return res;
593                }
594                ds1621_initialized--;
595        }
596
597        return 0;
598}
599
600EXPORT_NO_SYMBOLS;
601
602#ifdef MODULE
603
604MODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>");
605MODULE_DESCRIPTION("DS1621 driver");
606
607int init_module(void)
608{
609        return sensors_ds1621_init();
610}
611
612int cleanup_module(void)
613{
614        return ds1621_cleanup();
615}
616
617#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.