root/lm-sensors/trunk/kernel/chips/thmc50.c @ 1115

Revision 1115, 16.1 KB (checked in by mds, 14 years ago)

remove unused swap_bytes() to eliminate compile warning

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    thmc50.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#define DEBUG 1
23
24#include <linux/version.h>
25#include <linux/module.h>
26#include <linux/malloc.h>
27#include <linux/i2c.h>
28#include "sensors.h"
29#include "version.h"
30#include <linux/init.h>
31
32#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \
33    (LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0))
34#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
35#endif
36
37#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
38#define THIS_MODULE NULL
39#endif
40
41/* Addresses to scan */
42static unsigned short normal_i2c[] = { SENSORS_I2C_END };
43static unsigned short normal_i2c_range[] = { 0x2D, 0x2F, SENSORS_I2C_END };
44static unsigned int normal_isa[] = { SENSORS_ISA_END };
45static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
46
47/* Insmod parameters */
48SENSORS_INSMOD_1(thmc50);
49
50/* Many THMC50 constants specified below */
51
52/* The THMC50 registers */
53#define THMC50_REG_TEMP 0x27
54#define THMC50_REG_CONF 0x40
55#define THMC50_REG_TEMP_HYST 0x3A
56#define THMC50_REG_TEMP_OS 0x39
57
58#define THMC50_REG_TEMP_TRIP 0x13
59#define THMC50_REG_TEMP_REMOTE_TRIP 0x14
60#define THMC50_REG_TEMP_DEFAULT_TRIP 0x17
61#define THMC50_REG_TEMP_REMOTE_DEFAULT_TRIP 0x18
62#define THMC50_REG_ANALOG_OUT 0x19
63#define THMC50_REG_REMOTE_TEMP 0x26
64#define THMC50_REG_REMOTE_TEMP_HYST 0x38
65#define THMC50_REG_REMOTE_TEMP_OS 0x37
66
67#define THMC50_REG_INTER 0x41
68#define THMC50_REG_INTER_MIRROR 0x4C
69#define THMC50_REG_INTER_MASK 0x43
70
71#define THMC50_REG_COMPANY_ID 0x3E
72#define THMC50_REG_DIE_CODE 0x3F
73
74
75/* Conversions. Rounding and limit checking is only done on the TO_REG
76   variants. Note that you should be a bit careful with which arguments
77   these macros are called: arguments may be evaluated more than once.
78   Fixing this is just not worth it. */
79#define TEMP_FROM_REG(val) ((val>127)?val - 0x0100:val)
80#define TEMP_TO_REG(val)   ((val<0)?0x0100+val:val)
81
82/* Initial values */
83#define THMC50_INIT_TEMP_OS 60
84#define THMC50_INIT_TEMP_HYST 50
85
86/* Each client has this additional data */
87struct thmc50_data {
88        int sysctl_id;
89
90        struct semaphore update_lock;
91        char valid;             /* !=0 if following fields are valid */
92        unsigned long last_updated;     /* In jiffies */
93
94        u16 temp, temp_os, temp_hyst,
95            remote_temp, remote_temp_os, remote_temp_hyst,
96            inter, inter_mask, die_code, analog_out;    /* Register values */
97};
98
99#ifdef MODULE
100extern int init_module(void);
101extern int cleanup_module(void);
102#endif                          /* MODULE */
103
104#ifdef MODULE
105static
106#else
107extern
108#endif
109int __init sensors_thmc50_init(void);
110static int __init thmc50_cleanup(void);
111static int thmc50_attach_adapter(struct i2c_adapter *adapter);
112static int thmc50_detect(struct i2c_adapter *adapter, int address,
113                         unsigned short flags, int kind);
114static void thmc50_init_client(struct i2c_client *client);
115static int thmc50_detach_client(struct i2c_client *client);
116static int thmc50_command(struct i2c_client *client, unsigned int cmd,
117                          void *arg);
118static void thmc50_inc_use(struct i2c_client *client);
119static void thmc50_dec_use(struct i2c_client *client);
120static int thmc50_read_value(struct i2c_client *client, u8 reg);
121static int thmc50_write_value(struct i2c_client *client, u8 reg,
122                              u16 value);
123static void thmc50_temp(struct i2c_client *client, int operation,
124                        int ctl_name, int *nrels_mag, long *results);
125static void thmc50_remote_temp(struct i2c_client *client, int operation,
126                               int ctl_name, int *nrels_mag,
127                               long *results);
128static void thmc50_inter(struct i2c_client *client, int operation,
129                         int ctl_name, int *nrels_mag, long *results);
130static void thmc50_inter_mask(struct i2c_client *client, int operation,
131                              int ctl_name, int *nrels_mag, long *results);
132static void thmc50_die_code(struct i2c_client *client, int operation,
133                            int ctl_name, int *nrels_mag, long *results);
134static void thmc50_analog_out(struct i2c_client *client, int operation,
135                              int ctl_name, int *nrels_mag, long *results);
136static void thmc50_update_client(struct i2c_client *client);
137
138
139/* This is the driver that will be inserted */
140static struct i2c_driver thmc50_driver = {
141        /* name */ "THMC50 sensor chip driver",
142        /* id */ I2C_DRIVERID_THMC50,
143        /* flags */ I2C_DF_NOTIFY,
144        /* attach_adapter */ &thmc50_attach_adapter,
145        /* detach_client */ &thmc50_detach_client,
146        /* command */ &thmc50_command,
147        /* inc_use */ &thmc50_inc_use,
148        /* dec_use */ &thmc50_dec_use
149};
150
151/* These files are created for each detected THMC50. This is just a template;
152   though at first sight, you might think we could use a statically
153   allocated list, we need some way to get back to the parent - which
154   is done through one of the 'extra' fields which are initialized
155   when a new copy is allocated. */
156static ctl_table thmc50_dir_table_template[] = {
157        {THMC50_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real,
158         &i2c_sysctl_real, NULL, &thmc50_temp},
159        {THMC50_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real,
160         &i2c_sysctl_real, NULL, &thmc50_remote_temp},
161        {THMC50_SYSCTL_INTER, "inter", NULL, 0, 0444, NULL, &i2c_proc_real,
162         &i2c_sysctl_real, NULL, &thmc50_inter},
163        {THMC50_SYSCTL_INTER_MASK, "inter_mask", NULL, 0, 0644, NULL, &i2c_proc_real,
164         &i2c_sysctl_real, NULL, &thmc50_inter_mask},
165        {THMC50_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &i2c_proc_real,
166         &i2c_sysctl_real, NULL, &thmc50_die_code},
167        {THMC50_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &i2c_proc_real,
168         &i2c_sysctl_real, NULL, &thmc50_analog_out},
169        {0}
170};
171
172/* Used by init/cleanup */
173static int __initdata thmc50_initialized = 0;
174
175static int thmc50_id = 0;
176
177int thmc50_attach_adapter(struct i2c_adapter *adapter)
178{
179        return i2c_detect(adapter, &addr_data, thmc50_detect);
180}
181
182/* This function is called by i2c_detect */
183int thmc50_detect(struct i2c_adapter *adapter, int address,
184                  unsigned short flags, int kind)
185{
186        int company, i;
187        struct i2c_client *new_client;
188        struct thmc50_data *data;
189        int err = 0;
190        const char *type_name, *client_name;
191
192#ifdef DEBUG
193        printk("thmc50.o: Probing for THMC50 at 0x%2X on bus %d\n",
194               address, adapter->id);
195#endif
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                    ("thmc50.o: thmc50_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                goto ERROR0;
209
210        /* OK. For now, we presume we have a valid client. We now create the
211           client structure, even though we cannot fill it completely yet.
212           But it allows us to access thmc50_{read,write}_value. */
213        if (!(new_client = kmalloc(sizeof(struct i2c_client) +
214                                   sizeof(struct thmc50_data),
215                                   GFP_KERNEL))) {
216                err = -ENOMEM;
217                goto ERROR0;
218        }
219
220        data =
221            (struct thmc50_data *) (((struct i2c_client *) new_client) +
222                                    1);
223        new_client->addr = address;
224        new_client->data = data;
225        new_client->adapter = adapter;
226        new_client->driver = &thmc50_driver;
227        new_client->flags = 0;
228
229        /* Now, we do the remaining detection. */
230        company =
231            i2c_smbus_read_byte_data(new_client, THMC50_REG_COMPANY_ID);
232
233        if (company != 0x49) {
234#ifdef DEBUG
235                printk
236                    ("thmc50.o: Detect of THMC50 failed (reg 3E: 0x%X)\n",
237                     company);
238#endif
239                goto ERROR1;
240        }
241
242        /* Determine the chip type - only one kind supported! */
243        kind = thmc50;
244
245        if (kind == thmc50) {
246                type_name = "thmc50";
247                client_name = "THMC50 chip";
248        } else {
249#ifdef DEBUG
250                printk("thmc50.o: Internal error: unknown kind (%d)?!?",
251                       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
259        new_client->id = thmc50_id++;
260        data->valid = 0;
261        init_MUTEX(&data->update_lock);
262
263        /* Tell the I2C layer a new client has arrived */
264        if ((err = i2c_attach_client(new_client)))
265                goto ERROR3;
266
267        /* Register a new directory entry with module sensors */
268        if ((i = i2c_register_entry(new_client, type_name,
269                                        thmc50_dir_table_template,
270                                        THIS_MODULE)) < 0) {
271                err = i;
272                goto ERROR4;
273        }
274        data->sysctl_id = i;
275
276        thmc50_init_client(new_client);
277        return 0;
278
279/* OK, this is not exactly good programming practice, usually. But it is
280   very code-efficient in this case. */
281
282      ERROR4:
283        i2c_detach_client(new_client);
284      ERROR3:
285      ERROR1:
286        kfree(new_client);
287      ERROR0:
288        return err;
289}
290
291int thmc50_detach_client(struct i2c_client *client)
292{
293        int err;
294
295        i2c_deregister_entry(((struct thmc50_data *) (client->data))->
296                                 sysctl_id);
297
298        if ((err = i2c_detach_client(client))) {
299                printk
300                    ("thmc50.o: Client deregistration failed, client not detached.\n");
301                return err;
302        }
303
304        kfree(client);
305
306        return 0;
307}
308
309
310/* No commands defined yet */
311int thmc50_command(struct i2c_client *client, unsigned int cmd, void *arg)
312{
313        return 0;
314}
315
316void thmc50_inc_use(struct i2c_client *client)
317{
318#ifdef MODULE
319        MOD_INC_USE_COUNT;
320#endif
321}
322
323void thmc50_dec_use(struct i2c_client *client)
324{
325#ifdef MODULE
326        MOD_DEC_USE_COUNT;
327#endif
328}
329
330/* All registers are word-sized, except for the configuration register.
331   THMC50 uses a high-byte first convention, which is exactly opposite to
332   the usual practice. */
333int thmc50_read_value(struct i2c_client *client, u8 reg)
334{
335        return i2c_smbus_read_byte_data(client, reg);
336}
337
338/* All registers are word-sized, except for the configuration register.
339   THMC50 uses a high-byte first convention, which is exactly opposite to
340   the usual practice. */
341int thmc50_write_value(struct i2c_client *client, u8 reg, u16 value)
342{
343        return i2c_smbus_write_byte_data(client, reg, value);
344}
345
346void thmc50_init_client(struct i2c_client *client)
347{
348        /* Initialize the THMC50 chip */
349        thmc50_write_value(client, THMC50_REG_TEMP_OS,
350                           TEMP_TO_REG(THMC50_INIT_TEMP_OS));
351        thmc50_write_value(client, THMC50_REG_TEMP_HYST,
352                           TEMP_TO_REG(THMC50_INIT_TEMP_HYST));
353        thmc50_write_value(client, THMC50_REG_CONF, 1);
354}
355
356void thmc50_update_client(struct i2c_client *client)
357{
358        struct thmc50_data *data = client->data;
359
360        down(&data->update_lock);
361
362        if ((jiffies - data->last_updated > HZ + HZ / 2) ||
363            (jiffies < data->last_updated) || !data->valid) {
364
365#ifdef DEBUG
366                printk("Starting thmc50 update\n");
367#endif
368
369                data->temp = thmc50_read_value(client, THMC50_REG_TEMP);
370                data->temp_os =
371                    thmc50_read_value(client, THMC50_REG_TEMP_OS);
372                data->temp_hyst =
373                    thmc50_read_value(client, THMC50_REG_TEMP_HYST);
374                data->remote_temp =
375                    thmc50_read_value(client, THMC50_REG_REMOTE_TEMP);
376                data->remote_temp_os =
377                    thmc50_read_value(client, THMC50_REG_REMOTE_TEMP_OS);
378                data->remote_temp_hyst =
379                    thmc50_read_value(client, THMC50_REG_REMOTE_TEMP_HYST);
380                data->inter = thmc50_read_value(client, THMC50_REG_INTER);
381                data->inter_mask =
382                    thmc50_read_value(client, THMC50_REG_INTER_MASK);
383                data->die_code =
384                    thmc50_read_value(client, THMC50_REG_DIE_CODE);
385                data->analog_out =
386                    thmc50_read_value(client, THMC50_REG_ANALOG_OUT);
387                data->last_updated = jiffies;
388                data->valid = 1;
389        }
390
391        up(&data->update_lock);
392}
393
394
395void thmc50_temp(struct i2c_client *client, int operation, int ctl_name,
396                 int *nrels_mag, long *results)
397{
398        struct thmc50_data *data = client->data;
399        if (operation == SENSORS_PROC_REAL_INFO)
400                *nrels_mag = 0;
401        else if (operation == SENSORS_PROC_REAL_READ) {
402                thmc50_update_client(client);
403                results[0] = TEMP_FROM_REG(data->temp_os);
404                results[1] = TEMP_FROM_REG(data->temp_hyst);
405                results[2] = TEMP_FROM_REG(data->temp);
406                *nrels_mag = 3;
407        } else if (operation == SENSORS_PROC_REAL_WRITE) {
408                if (*nrels_mag >= 1) {
409                        data->temp_os = TEMP_TO_REG(results[0]);
410                        thmc50_write_value(client, THMC50_REG_TEMP_OS,
411                                           data->temp_os);
412                }
413                if (*nrels_mag >= 2) {
414                        data->temp_hyst = TEMP_TO_REG(results[1]);
415                        thmc50_write_value(client, THMC50_REG_TEMP_HYST,
416                                           data->temp_hyst);
417                }
418        }
419}
420
421
422void thmc50_remote_temp(struct i2c_client *client, int operation,
423                        int ctl_name, int *nrels_mag, long *results)
424{
425        struct thmc50_data *data = client->data;
426        if (operation == SENSORS_PROC_REAL_INFO)
427                *nrels_mag = 0;
428        else if (operation == SENSORS_PROC_REAL_READ) {
429                thmc50_update_client(client);
430                results[0] = TEMP_FROM_REG(data->remote_temp_os);
431                results[1] = TEMP_FROM_REG(data->remote_temp_hyst);
432                results[2] = TEMP_FROM_REG(data->remote_temp);
433                *nrels_mag = 3;
434        } else if (operation == SENSORS_PROC_REAL_WRITE) {
435                if (*nrels_mag >= 1) {
436                        data->remote_temp_os = TEMP_TO_REG(results[0]);
437                        thmc50_write_value(client,
438                                           THMC50_REG_REMOTE_TEMP_OS,
439                                           data->remote_temp_os);
440                }
441                if (*nrels_mag >= 2) {
442                        data->remote_temp_hyst = TEMP_TO_REG(results[1]);
443                        thmc50_write_value(client,
444                                           THMC50_REG_REMOTE_TEMP_HYST,
445                                           data->remote_temp_hyst);
446                }
447        }
448}
449
450
451void thmc50_inter(struct i2c_client *client, int operation, int ctl_name,
452                  int *nrels_mag, long *results)
453{
454        struct thmc50_data *data = client->data;
455        if (operation == SENSORS_PROC_REAL_INFO)
456                *nrels_mag = 0;
457        else if (operation == SENSORS_PROC_REAL_READ) {
458                thmc50_update_client(client);
459                results[0] = data->inter;
460                *nrels_mag = 1;
461        } else if (operation == SENSORS_PROC_REAL_WRITE) {
462                printk("thmc50.o: No writes to Interrupt register!\n");
463        }
464}
465
466
467void thmc50_inter_mask(struct i2c_client *client, int operation,
468                       int ctl_name, int *nrels_mag, long *results)
469{
470        struct thmc50_data *data = client->data;
471        if (operation == SENSORS_PROC_REAL_INFO)
472                *nrels_mag = 0;
473        else if (operation == SENSORS_PROC_REAL_READ) {
474                thmc50_update_client(client);
475                results[0] = data->inter_mask;
476                *nrels_mag = 1;
477        } else if (operation == SENSORS_PROC_REAL_WRITE) {
478                if (*nrels_mag >= 1) {
479                        data->inter_mask = results[0];
480                        thmc50_write_value(client, THMC50_REG_INTER_MASK,
481                                           data->inter_mask);
482                }
483        }
484}
485
486
487void thmc50_die_code(struct i2c_client *client, int operation,
488                     int ctl_name, int *nrels_mag, long *results)
489{
490        struct thmc50_data *data = client->data;
491        if (operation == SENSORS_PROC_REAL_INFO)
492                *nrels_mag = 0;
493        else if (operation == SENSORS_PROC_REAL_READ) {
494                thmc50_update_client(client);
495                results[0] = data->die_code;
496                *nrels_mag = 1;
497        } else if (operation == SENSORS_PROC_REAL_WRITE) {
498                printk("thmc50.o: No writes to Die-Code register!\n");
499        }
500}
501
502
503void thmc50_analog_out(struct i2c_client *client, int operation,
504                       int ctl_name, int *nrels_mag, long *results)
505{
506        struct thmc50_data *data = client->data;
507        if (operation == SENSORS_PROC_REAL_INFO)
508                *nrels_mag = 0;
509        else if (operation == SENSORS_PROC_REAL_READ) {
510                thmc50_update_client(client);
511                results[0] = data->analog_out;
512                *nrels_mag = 1;
513        } else if (operation == SENSORS_PROC_REAL_WRITE) {
514                if (*nrels_mag >= 1) {
515                        data->analog_out = results[0];
516                        thmc50_write_value(client, THMC50_REG_ANALOG_OUT,
517                                           data->analog_out);
518                }
519        }
520}
521
522
523
524
525int __init sensors_thmc50_init(void)
526{
527        int res;
528
529        printk("thmc50.o version %s (%s)\n", LM_VERSION, LM_DATE);
530        thmc50_initialized = 0;
531        if ((res = i2c_add_driver(&thmc50_driver))) {
532                printk
533                    ("thmc50.o: Driver registration failed, module not inserted.\n");
534                thmc50_cleanup();
535                return res;
536        }
537        thmc50_initialized++;
538        return 0;
539}
540
541int __init thmc50_cleanup(void)
542{
543        int res;
544
545        if (thmc50_initialized >= 1) {
546                if ((res = i2c_del_driver(&thmc50_driver))) {
547                        printk
548                            ("thmc50.o: Driver deregistration failed, module not removed.\n");
549                        return res;
550                }
551                thmc50_initialized--;
552        }
553
554        return 0;
555}
556
557EXPORT_NO_SYMBOLS;
558
559#ifdef MODULE
560
561MODULE_AUTHOR
562    ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
563MODULE_DESCRIPTION("THMC50 driver");
564
565int init_module(void)
566{
567        return sensors_thmc50_init();
568}
569
570int cleanup_module(void)
571{
572        return thmc50_cleanup();
573}
574
575#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.